Field guide / AI handoffs / October 11, 2026

Valid JSON can
still be wrong.

Check the handoff before the next tool. A local JSON Schema exercise that catches missing fields and shows why a passing result still needs source review.

The brackets are tidy. Is the handoff usable?

A project assistant returns an owner, a due date, and a next action. The response parses, so the next tool accepts it. That tells you the syntax worked. It does not tell you whether required information is present or whether the proposed action fits the review state.

We will check six fictional handoffs with Python’s open-source jsonschema library. No AI account, API key, or model download is needed.

The useful limit: a schema checks the rules you wrote. A believable wrong fact can satisfy every one of them. Validation and source review serve different jobs.

Portrait AI Anonymous poster on textured ivory paper. Large black headline: Valid JSON can still be wrong. A black metal inspection gate holds a copper template with curly braces and required-field marks. Cream JSON cards sit at the gate and beside a copper CHECK stamp. Below: Check the handoff before the next tool. JSON SCHEMA / PRACTICAL GUIDE. Footer: by JABSystems and jabsystems.io/ai-anonymous. Original AI-generated conceptual artwork, not a software screenshot or proof of factual accuracy.
Original AI-generated conceptual artwork. The inspection gate illustrates declared checks; it is not a software interface or proof of truth.
01 / Define the contract

Write down the facts and the allowed shape.

Our authored source facts: project Harbor, owner Morgan, due date 2026-10-14, review pending, next action hold. These are invented practice records, not customer data or model outputs.

The receiving tool expects exactly five fields. For this tutorial, Morgan and Riley are both allowed owner names; only source comparison establishes which one owns this project. The status may be pending or approved. If it is pending, the next action must be hold.

The JSON Schema object guide explains why listing properties alone does not require them. We add required and additionalProperties: false to make omissions and unexpected fields visible.

02 / Prepare

Start in an empty practice folder.

Install Python, open PowerShell in a new empty folder, and run:

python --version
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install 'jsonschema==4.26.0'

jsonschema 4.26.0 requires Python 3.10 or newer. We ran this exercise on Windows with Python 3.13.15. The top-level package is pinned; its dependencies are not fully locked. Installation downloads packages.

The virtual environment keeps packages in the practice folder; it does not sandbox execution or change permissions. Calling its interpreter directly avoids changing PowerShell activation policy.

03 / Review the files

Download the complete exercise.

The exercise ZIP contains a schema, the full checker, six authored JSON files, an observed report, a README, and a proposed starter prompt. Extract it, then read the code and rules before running:

Invoke-WebRequest -Uri 'https://jabsystems.io/ai-anonymous/Social/valid-json-exercise.zip' -OutFile .\valid-json-exercise.zip
Expand-Archive -LiteralPath .\valid-json-exercise.zip -DestinationPath .\exercise
Get-Content -LiteralPath .\exercise\validate-handoff.py
Get-Content -LiteralPath .\exercise\handoff-schema.json

The declared contract

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Fictional project handoff",
  "type": "object",
  "properties": {
    "project": {
      "type": "string",
      "const": "Harbor"
    },
    "owner": {
      "type": "string",
      "enum": [
        "Morgan",
        "Riley"
      ]
    },
    "due_date": {
      "type": "string",
      "format": "date"
    },
    "review_status": {
      "type": "string",
      "enum": [
        "pending",
        "approved"
      ]
    },
    "next_action": {
      "type": "string",
      "enum": [
        "hold",
        "prepare-export"
      ]
    }
  },
  "required": [
    "project",
    "owner",
    "due_date",
    "review_status",
    "next_action"
  ],
  "additionalProperties": false,
  "if": {
    "properties": {
      "review_status": {
        "const": "pending"
      }
    },
    "required": [
      "review_status"
    ]
  },
  "then": {
    "properties": {
      "next_action": {
        "const": "hold"
      }
    }
  }
}

The conditional guide describes if and then. Here the condition checks pending review and the consequence requires hold. This rule checks consistency inside the response; it does not verify that an approved status came from a real reviewer.

The string guide documents the date format. In Python jsonschema, format checking needs an explicit checker. Our code enables FormatChecker(formats=["date"]); the library documentation lists date as a format without an extra dependency.

The full checker

"""Check fictional handoff files locally; never execute a handoff action."""
import argparse
import json
from importlib.metadata import version
from pathlib import Path

from jsonschema import Draft202012Validator, FormatChecker


def unique_object(pairs):
    result = {}
    for key, value in pairs:
        if key in result:
            raise ValueError(f"Duplicate object key: {key}")
        result[key] = value
    return result


def reject_constant(value):
    raise ValueError(f"Non-JSON constant: {value}")


def read_json(path):
    return json.loads(path.read_text(encoding="utf-8-sig"),
                      object_pairs_hook=unique_object,
                      parse_constant=reject_constant)


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("files", nargs="+", type=Path)
    args = parser.parse_args()
    try:
        schema = read_json(Path(__file__).with_name("handoff-schema.json"))
        Draft202012Validator.check_schema(schema)
    except (OSError, ValueError) as error:
        parser.error(f"Cannot load schema: {error}")
    validator = Draft202012Validator(schema, format_checker=FormatChecker(formats=["date"]))
    results = []
    for path in args.files:
        try:
            instance = read_json(path)
        except (OSError, ValueError) as error:
            results.append({"file": path.name, "status": "input-error", "error": str(error)})
            continue
        errors = sorted(validator.iter_errors(instance), key=lambda e: (e.json_path, e.message))
        results.append({"file": path.name, "status": "pass" if not errors else "schema-fail",
                        "errors": [{"path": e.json_path, "rule": e.validator,
                                    "message": e.message} for e in errors]})
    print(json.dumps({"jsonschema": version("jsonschema"), "draft": "2020-12",
                      "scope": "syntax and declared rules only; no fact verification or actions",
                      "results": results}, indent=2))
    if any(item["status"] == "input-error" for item in results):
        return 2
    return 1 if any(item["status"] == "schema-fail" for item in results) else 0


if __name__ == "__main__":
    raise SystemExit(main())

The checker loads the bundled schema beside itself, validates that schema, and reports every schema error for each input. It never dispatches next_action. There are no external schema references or model requests in these files.

Python’s JSON decoder documentation explains its default treatment of repeated keys and non-finite constants. Our loader deliberately rejects duplicate keys and NaN/Infinity, accepts UTF-8 with an optional BOM, and requires raw JSON rather than Markdown code fences.

04 / Run the checks

Give the contract something to reject.

.\.venv\Scripts\python.exe .\exercise\validate-handoff.py .\exercise\handoff-good.json `
  .\exercise\handoff-missing-owner.json `
  .\exercise\handoff-extra-field.json `
  .\exercise\handoff-invalid-date.json `
  .\exercise\handoff-premature-action.json `
  .\exercise\handoff-wrong-fact.json
$LASTEXITCODE

The command intentionally exits 1: four fixtures violate the schema. Run only the good file for exit 0:

.\.venv\Scripts\python.exe .\exercise\validate-handoff.py .\exercise\handoff-good.json
$LASTEXITCODE

Exit 0 means all supplied files passed the schema. Exit 1 means a schema failure. Exit 2 means an input or command error, such as malformed JSON or a missing file. Read the report before drawing a conclusion.

What actually happened on these downloads

  • handoff-good.json: passes the schema and matches the fictional facts.
  • handoff-missing-owner.json: fails required.
  • handoff-extra-field.json: fails additionalProperties for an invented send_email field.
  • handoff-invalid-date.json: fails format for February 30.
  • handoff-premature-action.json: fails const because pending review requires hold.
  • handoff-wrong-fact.json: passes the schema, but names Riley instead of the source’s Morgan.

Inspect the observed JSON report. Two schema passes and four deliberate failures describe these authored fixtures only; they do not measure AI accuracy.

05 / Apply the idea

Keep the check between the response and the action.

  1. Use the consumer’s contract. Define required fields and permitted values from the receiving tool’s needs. An extra field is not authorization to execute it.
  2. Validate the raw response. Stop on parse errors, schema failures, refusals, or missing required facts. Ask for correction or review. Bound retries instead of inventing values to force a pass.
  3. Compare with trusted sources. Verify the owner, date, and review state independently. If a fact is authoritative and fixed for the job, a narrower rule can help, but only a trusted source can establish that rule.
  4. Authorize side effects separately. Keep approval in trusted application state and enforce permissions in the executing tool. A model-written string saying approved is not evidence of human approval.

The starter prompt is an optional next experiment. It was not submitted to a model. If you try it, attach the schema, use the fictional facts, validate the raw reply, and check every fact before integrating it with work.

06 / Know the boundary

Passing rules does not establish truth.

Verified: installation and execution in the stated Windows/Python environment; six authored fixtures; the expected exits; rejection of malformed JSON, duplicate keys, a non-finite constant, Markdown fences, and a missing file; acceptance of a UTF-8 BOM. The schema-valid wrong-owner fixture demonstrates the gap between declared rules and source truth.

Not tested: model inference, model-generated outputs, improved answer quality, accuracy, speed, a production agent, real approval enforcement, or other operating systems. This is a small-file teaching script, not a hardened service. Real deployments need input-size limits, controlled logs, permission checks, and controlled actions. Error messages can include input values.

Use synthetic or approved non-sensitive data. Review any changed schema and dependencies. This tutorial establishes a local validation exercise, not a security boundary or permission to process confidential records.

07 / Sources and downloads

Keep the contract and evidence together.

Primary sources checked October 11, 2026: JSON Schema’s object, conditional, and string guides; the jsonschema validation documentation and 4.26.0 PyPI metadata; Python’s JSON decoder documentation. This is a practical tutorial, not a claim that the library launched today.

Complete exercise · Caption · Alt text · Posting ZIP

Manual social delivery: the original graphic, teaser caption, alt text, and article URL are prepared for the user to post. Nothing is scheduled or published to social media; no Instagram profile-link change is claimed.

Explore all AI Anonymous resources →