Validate - the combined Arcgram self-check entry
One call. Two questions answered between the siblings:
is the flow well-formed and coherent, AND do its @spec values still match the code?
Validate is a thin wrapper, not a new check. It imports Checkpoint and Reconcile untouched and composes their pure functions:
- Checkpoint (one input: the diagram) checks structure - well-formed, coherent.
- Reconcile (two inputs: diagram + code) checks values -
@specliterals == code constants.
Run both -> the diagram is a faithful, current spec. Every finding still comes from one sibling; Validate only merges, source-tags, and unions the attestation.
Code is optional
| input | what runs | clean possible? |
|---|---|---|
validate(diagram, { code }) |
Checkpoint and Reconcile | yes |
validate(diagram) (no code) |
Checkpoint only | no - values unchecked |
Without code there is nothing to reconcile, so Reconcile is not run (running it would just flag
every @spec pin as missing). Instead the value half is reported as one uncovered
value-check-not-run finding, so a structure-only run is never falsely "clean" on values - the same
anti-silent-pass rule both siblings enforce.
Locked invariant - uncovered is a third state, never a pass. A diagram-only run (no code) can
never produce an overall green clean, even when the structure is perfect. The attestation
explicitly appends | code consistency: NOT CHECKED (no code supplied), summary.codeConsistency
reads "NOT_CHECKED", and the CLI verdict is INCOMPLETE, never the word CLEAN. This guards the
exact silent-pass the family exists to prevent: claiming "checked & clean" while the code half was
never checked.
Output (same contract as both siblings, plus source)
{ findings:[{id,type,severity,note,source}], summary, attestation, clean }
self-check ran HH:MM:SS | N findings | M unchecked
sourceis"checkpoint"|"reconcile"|"validate"- so you can route a finding back to the check that raised it. Everything else (id,type,severity,note) is verbatim from the sibling.attestationis the union: N and M are the combined defect / uncovered totals. When the value half did not run it appends an explicit| code consistency: NOT CHECKED (no code supplied).clean === checkpoint.clean && reconcile.clean(identicallyN=0 && M=0);uncoveredis a third state and is never folded intoclean, so a skipped value-check is not clean.summarynests each sibling's own summary under.checkpoint/.reconcile, plusranandcodeConsistency("checked"|"NOT_CHECKED").- The full sub-results are returned verbatim on
.checkpoint/.reconcilefor a caller that wants the per-check breakdown.
Human reads the marker; agent reads the type (and source).
Use
node validate.mjs <diagram.html | diagram.json> [code-file ...] [--tier-b | --no-tier-b] [--json]
import { validate } from './validate.mjs';
validate({ nodes, edges, meta }, { code }); // code: string | string[]; omit -> structure only
--tier-b / --no-tier-b forward to Checkpoint's justification tier (else auto-detected by a
decision diamond). Exit 1 on any defect (advisory - never blocks; an uncovered value-check is not a
defect).
Verify: node validate-selftest.mjs (36 checks - source tags, union attestation, clean rule, the
code-omitted path, and byte parity with running the two siblings separately).
Example: examples/example-workflow.html vs example-workflow.config.cs (clean).