U handoff validator
Skill zig999/siegard-code/dist/.claude/skills/u-handoff-validator
Most AI coding tools help you write code. Siegard Code manages the entire development lifecycle — it writes specifications, plans backlogs, implements features, runs QA, and delivers tested code. All autonomously, all traceable, all through Claude Code.
npx -y skills add zig999/siegard-code --skill u-handoff-validatorAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 9 stars9 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Validates a handoff-manifest.yaml against schema, semantic rules, and provenance (PROV — every pinned artifact hash must be log-notarized by a worker terminal or match the workflow's adoption baseline; the manifest itself must match its generation event) before it is consumed by Dev orchestrators. Single source of truth for manifest validation — replaces inline checks in BE and FE orchestrator cores.
SKILL.md
7.9 KB, as published. Nobody here has run it
SKILL: Handoff Manifest Validator
Purpose
Validate the canonical handoff-manifest.yaml produced by u-spec-orchestrator before any Dev orchestrator consumes it. Returns a structured envelope (handoff-validation-envelope.yaml) that the caller uses to decide whether to proceed, halt, or escalate.
This skill consolidates rules that previously lived inline in u-be-orchestrator-core.md and u-fe-orchestrator-core.md. Both orchestrators now invoke this skill instead of duplicating checks.
When invoked
- By
u-be-orchestrator-coreat session start, if{SPECS_DIR}/handoff-manifest.yamlexists - By
u-fe-orchestrator-coreat session start, if{SPECS_DIR}/handoff-manifest.yamlexists - By
u-spec-to-dev-handoffprotocol before writing a new manifest (pre-write validation)
Inputs
| Field | Value |
|---|---|
manifest_path | Absolute path to {SPECS_DIR}/handoff-manifest.yaml |
caller | u-be-orchestrator-core | u-fe-orchestrator-core | u-spec-orchestrator |
specs_dir | Absolute path to {SPECS_DIR}/ — used to resolve package paths for integrity checks |
Outputs
validate.py prints a single JSON envelope to stdout (see Envelope shape) and signals validity via exit code (0 valid / 1 invalid). The caller acts only on status, errors[] (rule-id-prefixed strings), and halt_signal. The envelope conforms to handoff-validation-envelope.schema.yaml.
Validation rules
The deployed implementation is validate.py (stdlib-only, prod-hardening task 03b): it loads the manifest via minimal_yaml, evaluates the 13 structural rules below plus the PROV provenance rules (v2.35.0), and prints a flat JSON envelope. rules.yaml is the declarative catalog — documentation, NOT loaded at runtime. Each rule has:
PROV rules (v2.35.0) — provenance against the orchestration log, evaluated when a spec_baseline_recorded event exists for the workflow (otherwise degraded to warnings — A6' migration): PROV-010 (every pinned sha256 equals the latest worker-notarized hash after the baseline, or the baseline hash when untouched), PROV-020 (the manifest file's sha256 equals the hash recorded by handoff_manifest_generated), PROV-030 (a generation event exists — delivered_by backed by evidence, P8). Integrity rules prove the manifest matches the files; PROV proves the files came from the pipeline — a freelance edit laundered through manifest regeneration passes HDF-020/021 and fails PROV-010. On PROV failure the consuming orchestrator emits E25_unprovenanced_artifact.
id— stable identifier (FLOW-NNN or HDF-NNN)severity—blocking(populateserrors[]) orwarning(populateswarnings[])applies_to— DESCRIPTIVE ONLY: which caller the rule matters to.validate.pyevaluates all rules regardless of--caller; scoping is data-driven (see note under the catalog).check— declarative description of the predicatevalidate.pyhard-codes
Rule catalog
| ID | Description | Severity | Applies to |
|---|---|---|---|
| FLOW-030 | handoff.delivered_by must be u-spec-orchestrator | blocking | all |
| FLOW-031 | domains[] must have at least 1 entry | blocking | all |
| FLOW-032 | backend_package[] must have at least 1 entry | blocking | be |
| FLOW-033 | new_domain handoff must NOT include change_summary | blocking | all |
| FLOW-034 | major_evolution, fast_track, and reverse_eng handoffs MUST include change_summary | blocking | all |
| FLOW-035 | change_summary.dev_impact must be a valid enum value | blocking | all |
| FLOW-036 | change_summary.type must match handoff.type: fast_track → [patch, minor]; major_evolution → [major]; reverse_eng → [patch, minor, major] | blocking | all |
| FLOW-037 | for new_domain/major_evolution, backend_package[] must include both openapi and back-spec | blocking | be* |
| HDF-010 | handoff.type must be in {new_domain, major_evolution, fast_track, reverse_eng} | blocking | all |
| HDF-020 | Every backend_package[].sha256 must match the actual file at {specs_dir}/{path} | blocking | be |
| HDF-021 | Every frontend_package[].sha256 must match the actual file at {specs_dir}/{path} | blocking | fe |
| HDF-030 | change_summary.dev_impact = stop_domain_task_contracts — caller must halt affected domains | blocking | all |
| HDF-040 | frontend_artifacts omitted for backend-only handoffs — otherwise required fields present | blocking | fe |
* The Applies to column is descriptive (which caller the rule matters to).
validate.pyevaluates all rules regardless of--caller; scoping is data-driven: FLOW-037 fires only fornew_domain/major_evolution, HDF-021 only whenfrontend_packageis present, HDF-040 only whenfrontend_artifactsis present.
Execution protocol
validate.py --manifest <path> --specs-dir <dir> [--caller <id>]:
- Load
manifest_pathvia the stdlibminimal_yamlloader. If the file is missing or unparseable → emitstatus: invalidwith the reason inerrors[]and exit1(fail-closed). No external JSON-Schema validation runs —handoff-manifest.schema.yamlis the reference structure, not an executed step. - Evaluate all 13 rules (FLOW-030..037, HDF-010/020/021/030/040) against the loaded mapping, regardless of
--caller. Scoping is data-driven (FLOW-037 byhandoff.type; HDF-021 only whenfrontend_packagepresent; HDF-040 only whenfrontend_artifactspresent). HDF-020/021 read each pinned file under--specs-dirand compare sha256. - Each blocking failure appends a rule-id-prefixed string to
errors[](e.g."FLOW-030: …").change_summary.dev_impact: stop_domain_task_contractssetshalt_signal: true(HDF-030) — flow control for the caller, not an error. - Print the envelope as one JSON object; exit
0whenstatus: valid(emptyerrors), else1.
Envelope consumption rules
The caller MUST:
- Halt and escalate to human when
status: invalid(exit code1) - Halt affected domains when
halt_signal: true(HDF-030 —change_summary.dev_impact = stop_domain_task_contracts) - Proceed normally when
status: validandhalt_signal: false - Act on
statusandhalt_signalfor flow control;errors[]are rule-id-prefixed strings (e.g."FLOW-030: …") for diagnostics/surfacing, not for branching logic
Envelope shape
validate.py emits this flat JSON object (one line):
{
"status": "valid | invalid",
"errors": ["FLOW-030: …", "HDF-020: sha256 mismatch for …"],
"warnings": [],
"halt_signal": true,
"validated_by": "u-handoff-validator",
"caller": "u-spec-orchestrator | u-be-orchestrator-core | u-fe-orchestrator-core"
}
errors[] are rule-id-prefixed strings (not structured objects). This shape conforms to handoff-validation-envelope.schema.yaml. The SDD→Dev gate (check_handoff_manifest_approved.py) consumes status (must be valid) and surfaces errors[]; orchestrators additionally honor halt_signal.
Versioning
When adding or changing a rule:
- Change
validate.pyfirst — it is the executable source of truth (the SDD gate runs it). - Update
rules.yamland the rule catalog table in this SKILL.md to match. - Add a fixture pair (valid + invalid) under
tests/fixtures/. - Extend the validator test layer (
tests/test_layer5_flows.pyand/ortests/test_layer_hard_handoff_generation.py) to cover the new rule.
New rule IDs: use HDF-NNN (handoff-specific) for rules introduced after the extraction. FLOW-NNN IDs are preserved for backward compatibility with existing tests.