{"record":{"id":"9a490c214563a2d8","repo":"affaan-m/ECC","slug":"missing-required-field-e-at-line-i","errorCode":null,"errorMessage":"Missing required field {e} at line {i}","messagePattern":"Missing required field (.+?) at line (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/skill-comply/scripts/parser.py","lineNumber":72,"sourceCode":"        return []\n\n    events: list[ObservationEvent] = []\n    for i, line in enumerate(text.splitlines(), 1):\n        try:\n            raw = json.loads(line)\n        except json.JSONDecodeError as e:\n            raise ValueError(f\"Invalid JSON at line {i}: {e}\") from e\n        try:\n            events.append(ObservationEvent(\n                timestamp=raw[\"timestamp\"],\n                event=raw[\"event\"],\n                tool=raw[\"tool\"],\n                session=raw[\"session\"],\n                input=raw.get(\"input\", \"\"),\n                output=raw.get(\"output\", \"\"),\n            ))\n        except KeyError as e:\n            raise ValueError(f\"Missing required field {e} at line {i}\") from e\n\n    return sorted(events, key=lambda e: e.timestamp)\n\n\ndef parse_spec(path: Path) -> ComplianceSpec:\n    \"\"\"Parse a YAML compliance spec file.\"\"\"\n    if not path.is_file():\n        raise FileNotFoundError(f\"Spec file not found: {path}\")\n    raw = yaml.safe_load(path.read_text())\n\n    steps: list[Step] = []\n    for s in raw[\"steps\"]:\n        d = s[\"detector\"]\n        steps.append(Step(\n            id=s[\"id\"],\n            description=s[\"description\"],\n            required=s[\"required\"],\n            detector=Detector(","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/skills/skill-comply/scripts/parser.py#L54-L90","documentation":"Each JSONL observation record must contain the keys timestamp, event, tool, and session (input and output default to ''). When one is missing, the ObservationEvent construction raises KeyError, which is wrapped as ValueError naming the missing field and the line number.","triggerScenarios":"A trace producer omits one of the required keys; a renamed field (e.g. 'session_id' instead of 'session') reaches the parser; a manually edited trace line drops a key.","commonSituations":"An upstream schema change in the stream-json adapter (_parse_stream_json) that emits a different key name; third-party tools writing a 'compatible' JSONL with subtly different field names.","solutions":["Inspect the named field and line number in the message and fix the source record.","If the producer uses different key names, normalize records before write (alias session_id -> session).","Run a small jsonschema check over the first record of the trace to catch schema drift early.","Regenerate the trace from runner.run_scenario so it matches the parser's expected schema."],"exampleFix":"# before (producer emits session_id)\n# {\"timestamp\":\"T0001\",\"event\":\"tool_complete\",\"tool\":\"Read\",\"session_id\":\"abc\"}\n\n# after (normalize before writing the JSONL)\nrecord = {\"timestamp\": ts, \"event\": ev, \"tool\": tool, \"session\": sid, \"input\": inp, \"output\": out}\nfout.write(json.dumps(record) + '\\n')","handlingStrategy":"validation","validationCode":"import json\nfrom pathlib import Path\n\nREQUIRED = {'timestamp', 'event', 'tool', 'session'}\ndef validate_trace_schema(path: Path) -> list[tuple[int, set[str]]]:\n    missing: list[tuple[int, set[str]]] = []\n    for i, line in enumerate(path.read_text().splitlines(), 1):\n        line = line.strip()\n        if not line:\n            continue\n        keys = set(json.loads(line))\n        gap = REQUIRED - keys\n        if gap:\n            missing.append((i, gap))\n    return missing","typeGuard":null,"tryCatchPattern":"from scripts.parser import parse_trace\ntry:\n    events = parse_trace(path)\nexcept ValueError as e:\n    if 'Missing required field' in str(e):\n        # identify and drop/repair the offending record\n        raise","preventionTips":["Keep the trace producer and parser schemas in a single shared constant or pydantic model.","Write a contract test that runs parse_trace over a known-good fixture on every CI run.","When aliasing keys (session_id -> session), do it at write time, not read time."],"tags":["parser","trace","validation","schema","skill-comply"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}