{"record":{"id":"78d6d179dab909a4","repo":"calesthio/OpenMontage","slug":"gate-violation-stage-stage-r-requires-human-app","errorCode":null,"errorMessage":"GATE VIOLATION: stage {stage!r} requires human approval ({gate_source}) but status='completed' was written without human_approved=True. Correct protocol: write status='awaiting_human', present the artifact summary to the user, END YOUR TURN, and only after the user approves re-write with status='completed', human_approved=True.","messagePattern":"GATE VIOLATION: stage (.+?) requires human approval \\((.+?)\\) but status='completed' was written without human_approved=True\\. Correct protocol: write status='awaiting_human', present the artifact summary to the user, END YOUR TURN, and only after the user approves re-write with status='completed', human_approved=True\\.","errorType":"validation","errorClass":"CheckpointValidationError","httpStatus":null,"severity":"error","filePath":"lib/checkpoint.py","lineNumber":487,"sourceCode":"    # gates on human approval; a caller may gate MORE strictly (e.g. a\n    # manual_all checkpoint policy) but never less. A gated stage can only be\n    # written \"completed\" with explicit evidence of approval\n    # (human_approved=True). Skipping a gate is a hard error.\n    #\n    # Enforcement happens at write time only: pre-existing checkpoints written\n    # before gating (or by hand) still read as completed — deliberate\n    # back-compat so in-flight and legacy projects keep resuming.\n    manifest_gate = _stage_requires_approval(pipeline_type, stage)\n    gated = bool(manifest_gate) or human_approval_required\n    if gated:\n        human_approval_required = True\n        if status == \"completed\" and not human_approved:\n            gate_source = (\n                f\"human_approval_default: true in the {pipeline_type!r} manifest\"\n                if manifest_gate\n                else \"human_approval_required=True was passed by the caller\"\n            )\n            raise CheckpointValidationError(\n                f\"GATE VIOLATION: stage {stage!r} requires human approval \"\n                f\"({gate_source}) but status='completed' was written without \"\n                f\"human_approved=True. Correct protocol: write \"\n                f\"status='awaiting_human', present the artifact summary to the \"\n                f\"user, END YOUR TURN, and only after the user approves \"\n                f\"re-write with status='completed', human_approved=True.\"\n            )\n\n    _enforce_stage_prerequisites(\n        pipeline_dir,\n        project_id,\n        pipeline_type,\n        stage,\n        status,\n    )\n\n    checkpoint = {\n        \"version\": \"1.0\",","sourceCodeStart":469,"sourceCodeEnd":505,"githubUrl":"https://github.com/calesthio/OpenMontage/blob/95e1c3d0ab93482159818560f6a8c8e866b9139f/lib/checkpoint.py#L469-L505","documentation":"Raised by lib/checkpoint.py when a checkpoint for a stage that requires human approval (via human_approval_default: true in the pipeline manifest, or human_approval_required=True passed by the caller) is written with status='completed' but without human_approved=True. The checkpoint system enforces a human-in-the-loop gate: the agent must first persist status='awaiting_human', present the artifact summary, end its turn, and only after explicit user approval write status='completed' with human_approved=True. This is a deliberate protocol violation guard, not a data corruption bug.","triggerScenarios":"Calling the checkpoint write API with status='completed' for a stage whose manifest entry has human_approval_default: true (e.g. final_review in a gated pipeline), or passing human_approval_required=True while omitting human_approved=True. Also triggered when an agent skips the awaiting_human intermediate write and tries to complete a gated stage in a single call.","commonSituations":"Agents automating a full pipeline end-to-end without pausing; new pipeline manifests that enable human_approval_default on stages previously auto-completed; legacy code written before the gating was added that resumes in-flight projects and writes completed directly.","solutions":["Rewrite the checkpoint with status='awaiting_human' first, present the artifact summary to the user, and end the turn.","After the user approves, write the checkpoint again with status='completed' and human_approved=True.","If the gate is intentional and the caller is authorized, pass human_approved=True together with status='completed' only when a real human approval exists.","If the stage should not be gated, edit the pipeline manifest and remove human_approval_default: true for that stage (a user/product decision, not an agent one)."],"exampleFix":"# before\nwrite_checkpoint(stage=\"final_review\", status=\"completed\")\n\n# after\nwrite_checkpoint(stage=\"final_review\", status=\"awaiting_human\")\n# ... present artifact summary, END TURN ...\n# after user approval:\nwrite_checkpoint(stage=\"final_review\", status=\"completed\", human_approved=True)","handlingStrategy":"validation","validationCode":"from lib.pipeline_loader import load_pipeline_readonly, get_stage_human_approval_default\n\ndef stage_is_gated(pipeline_type: str, stage: str) -> bool:\n    try:\n        manifest = load_pipeline_readonly(pipeline_type)\n    except Exception:\n        return False\n    return bool(get_stage_human_approval_default(manifest, stage))\n\n# before writing 'completed':\nif stage_is_gated(pipeline_type, stage) and not human_approved:\n    write_checkpoint(stage=stage, status=\"awaiting_human\")  # then end turn","typeGuard":"def can_complete_stage(pipeline_type: str, stage: str, human_approved: bool) -> bool:\n    \"\"\"True only when the stage is ungated OR a human has approved.\"\"\"\n    return human_approved or not stage_is_gated(pipeline_type, stage)","tryCatchPattern":"try:\n    write_checkpoint(stage=stage, status=\"completed\", human_approved=approved)\nexcept CheckpointValidationError as e:\n    if \"GATE VIOLATION\" in str(e):\n        write_checkpoint(stage=stage, status=\"awaiting_human\")\n        present_artifact_summary()\n        return  # end turn; complete only after user approval\n    raise","preventionTips":["Treat gated stages as a two-phase write: awaiting_human first, completed+human_approved=True second.","Check human_approval_default in the pipeline manifest before starting a stage so the pause is planned, not discovered.","Never auto-set human_approved=True; only mirror an explicit user approval event.","Keep the gate violation message as the protocol reminder: present summary, end turn, then complete."],"tags":["checkpoint","human-in-the-loop","state-machine","protocol"],"backgroundTag":null,"analyzedSha":"95e1c3d0ab93482159818560f6a8c8e866b9139f","analyzedAt":"2026-08-15T06:31:20.014Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}