ushman-verify
v0.7.0
Published
Pure-Node v4 workspace preflight for ushman/shibuk. Runs ASL immutability, schema, candidate parse, undefined-ref, data-blob, runtime-seam, vendor-residue, cross-ref, and ledger integrity checks.
Maintainers
Readme
ushman-verify
Pure-Node v4 workspace preflight for ushman/shibuk handoffs.
ushman-verify validates a live v4 workspace rooted at the candidate app:
asl/is the immutable donor oracle..lab/is derived evidence and ledger state.src/,public/, and root config files are the candidate tree.
It does not run a browser, compute parity, or modify any file beyond optionally writing .lab/verify-result.json.
Status
Runtime: pure Node >=24. No Bun APIs, no network, no browser harness.
Design notes live in ARCHITECTURE.md.
The verifier is a hard v4 cutover:
- v4 workspaces are detected via
.lab/lab.jsonwithschemaVersion: "ushman-lab/v4.0". - v3 workspaces are refused with the migration hint.
- v3-only
.ushman/manifest checks andstages/03-clean/candidate scanning are deleted.
Dependency Boundary
ushman-verify stays standalone-installable today:
- no
file:dependencies on sibling ushman/shibuk repos - no Bun-only runtime dependencies
- local schema and ledger-doctor compatibility code remains in this package until
@shibuk/schemas,@ushman/lab-types, and@ushman/ledgerare consumable as publishable dependencies forbun i -g ushman-verify
Install
npm i -g ushman-verify
bun add ushman-verifyQuick Start
import { runVerify, checkLedgerIntegrity } from 'ushman-verify';
const report = await runVerify({ workspaceRoot: '.' });
console.log(report.verdict); // 'green' | 'yellow' | 'red'
const ledger = await checkLedgerIntegrity('.');
console.log(ledger.ok); // true | falseushman-verify .
ushman-verify . --tier=0 --json
ushman-verify . --ignore=src/legacy --ignore=public/vendor-debug.js
ushman-verify . --check-ledgerTiers
| Tier | What it checks |
|------|----------------|
| 0a | ASL immutability (asl/donor/** matches asl/.integrity.json and .lab/lab.json:fingerprints.asl) |
| 0b | v4 schema shapes (asl/ and .lab/ JSON documents have expected schemaVersion literals and required keys) |
| 0c | Babel parse (candidate JS/TS under src/, public/, and root config files parse cleanly) |
| 0d | Undefined references (candidate JS/TS has no unresolved identifiers outside the runtime allowlist) |
| 0e | Data blobs (candidate *B64 string literals are valid base64) |
| 1a | Cross references (stage manifests, cleanup artifacts, and ledger refs resolve inside the workspace) |
| 1b | Runtime seams (bridge-aware ambient declarations and Cannot find name diagnostics under src/ resolve against the runtime-host bridge) |
| 1c | Vendor residue (vendor marker strings do not leak from extracted vendor outputs back into non-vendor src/ files) |
checkLedgerIntegrity() is an additional doctor-style ledger check, exposed separately and via --check-ledger.
Large Schema Files
Tier 0b avoids fully deserializing oversized schema JSON when a schema family has an explicit large-file strategy.
| Schema Version | Strategy | Validated Large-File Fields |
|---|---|---|
| ushman-cleanup-map/v1 | header-tail-metadata-only | schemaVersion, schemaName |
| ushman-parity-baselines/v4.0 | targeted-field-extraction | schemaVersion, captureDerivedHash, updatedAt |
Notes:
- Large-file targeted extraction intentionally validates bounded metadata only. Unbounded payloads such as parity
statesstay out of the oversized-document validator path. - Large-file extraction tokenizes snippet text and only trusts root-object keys. Nested
schemaVersioncollisions and quoted key-shaped strings inside other values are ignored instead of being matched heuristically. - Oversized JSON for other schema families now warn-skips with a remediation pointer instead of crashing the verify process. Legacy cleanup artifacts point operators at the lazy-sidecar regeneration flow or a header-stub
jqfallback. header-tail-metadata-onlyis for schema families whose durable metadata is known to live near EOF and only needs a tiny root-level header/footer subset.targeted-field-extractionis for large JSON where root metadata lives near BOF but unbounded payloads must stay unparsed.- Tier
0bswitches from full parse to snippet extraction at 20 MB, even ifUSHMAN_VERIFY_LARGE_FILE_THRESHOLD_BYTESis set higher. The env var can lower that threshold globally, but it does not raise the schema-shape direct-read cap above 20 MB.
Severity
green: no warnings or failuresyellow: warning(s), no failuresred: failure(s)
Undefined references remain yellow by design. They are useful signal, but not always a hard stop during staged migrations.
tier1.runtime-seams warn-skips when no supported runtime-host bridge is detected, and tier1.vendor-residue warn-skips when vendor-extract has not produced usable mapping inputs yet.
Tier 1 Skip Cases
tier1.runtime-seams looks for the bridge patterns seen in the reference recoveries:
Object.assign(globalThis, { ... })Object.defineProperties(globalThis, { ... })Object.defineProperty(globalThis, key, descriptor)
The verifier first checks the common bridge paths (src/modules/runtime-host/index.*, src/bridge-access-runtime.*, src/runtime-host.*) and then falls back to nearby src/**/{runtime-host,bridge,runtime}.* files that actually publish onto globalThis.
When tier1.runtime-seams reports bridged, the name is published by the detected bridge and the warning is telling the operator that legacy global coupling still exists. When it reports missing, the name is not published by the bridge and should be treated as a real runtime regression unless the bridge was only partially understood.
When tier1.runtime-seams warn-skips:
- no bridge was detected: the workspace may not use a bridge, so no action is required unless one was expected
- bridge partially understood: inspect the bridge file for dynamic/computed publication shapes and either simplify it or extend the verifier heuristics
When tier1.vendor-residue warn-skips:
- vendor-extract has not run: rerun the vendor-extract stage before trusting the residue result
- a mapping-specific warning names a mapping file: fix that artifact or regenerate vendor-extract outputs so marker derivation has a usable vendor file or explicit
markerPatterns
Public API
Top-level exports:
runVerify(opts: {
workspaceRoot: string;
tiers?: VerifyTier[];
ignorePaths?: readonly string[];
excludeUndefinedRefPaths?: readonly string[];
}): Promise<VerifyReport>;
renderVerifyReport(report: VerifyReport): string;
writeVerifyResult(opts: { report: VerifyReport; workspaceRoot: string }): Promise<void>;
checkLedgerIntegrity(workspaceRoot: string): Promise<LedgerIntegrityReport>;ignorePaths is optional and only suppresses candidate-tree JS/TS discovery for Tier 0c, 0d, 0e, 1b, and 1c; ASL, schema, cross-reference, and ledger checks still read their normal v4 workspace inputs. Paths are exact workspace-relative paths, not globs. Directory ignores apply recursively, and ignorePaths: ['.'] disables candidate-tree discovery entirely.
Candidate discovery only considers JS/TS source files under src/, public/, and root config files. Declaration files such as .d.ts / .d.mts / .d.cts are intentionally excluded.
excludeUndefinedRefPaths is optional and only affects Tier 0d. The verifier always excludes mirrored vendor trees under public/_external/ and src/donor/_external/, and it also suppresses large or obviously minified vendor blobs from undefined-reference warnings. Any workspace-relative paths passed here are added to that default exclusion set.
LedgerIntegrityReport has the shape:
type LedgerIntegrityReport = {
issues: readonly string[];
ok: boolean;
workspaceRoot: string;
};issues is a flat list of human-readable verifier strings such as Missing blob sha256:... for 2026-05-12T00:00:02.000Z-agentpatch. or .lab/ledger/manifest.json: required schema file is missing.
Per-check helpers are also exported:
checkAslImmutabilitycheckSchemaShapescheckBabelParsecheckUndefinedReferencescheckDataBlobscheckCrossReferencescheckRuntimeSeamscheckVendorResidue
checkManifestHashes remains as a compatibility alias for checkAslImmutability.
CLI
ushman-verify <workspace> [--tier=0|1|all] [--ignore=<path>] [--baseline=<report>] [--json] [--write-result]
ushman-verify <workspace> --check-ledger [--json]--baseline=<report> filters each check to only NEW issue lines relative to a prior verify snapshot and recomputes verdict/counts from that diff.
--tier=all is synonymous with omitting --tier.
Exit codes:
0:greenoryellowverify report, or healthy ledger1:redverify report, or unhealthy ledger2: verifier/runtime error (including v3 refusal)
Typical exit-code 2 cases:
- the workspace is not v4-shaped
- the workspace is still v3 and needs migration
- the verifier itself crashed before producing a report
- invalid CLI flag combinations such as
--check-ledger --write-result
--write-result is opt-in. Without it, the CLI prints the report and exits without writing .lab/verify-result.json.
Oversized JSON guardrails:
USHMAN_VERIFY_LARGE_FILE_THRESHOLD_BYTES=<bytes>overrides the default 50 MB full-parse limit for allJSON.parse-style reads.- Oversized files are never silently skipped. The verifier emits a
Skipped ... exceeds the ... JSON parse limitissue with an operator remediation pointer. USHMAN_VERIFY_TRACE_MEMORY=1writes per-phase RSS/heap snapshots to stderr so operators can identify which check is growing the heap on pathological workspaces.
Heap Guard
The CLI respawns once with a larger Node old-space default when no explicit heap size is already set. This keeps large Babel parse runs from dying under the sandbox default heap.
USHMAN_VERIFY_NO_HEAP_GUARD=1disables the respawn for debugging.USHMAN_VERIFY_HEAP_GUARD=1marks the child process after respawn so the guard does not recurse.- An explicit
NODE_OPTIONS=--max-old-space-size=...ornode --max-old-space-size=...override wins over the default guard size.
Result File
When --write-result is used, the verifier writes:
.lab/verify-result.jsonThe durable report shape still carries reportVersion: "1.0.0".
Layout Refusal
If the workspace looks like v3, the verifier exits with the standard migration hint:
This workspace is in v3 layout (legacy stages/, .ushman/, handoff.json at root).
ushman v4 no longer ships the v3 layout readers or the live migrator.
`ushman migrate-v3-v4` is retained only as a diagnostic stub.
All known v3 workspaces were migrated during the v4 cutover.
If this workspace was not on that migration list, restore shibuk v2.x + ushman v3.x to migrate it first.
Workspace: <workspace>Migrating From v3
The v4 verifier is a hard cutover:
- v3 workspace layouts (
.ushman/,stages/,handoff.json) are refused - result files now live at
.lab/verify-result.json - Tier
0anow validatesasl/donor/**againstasl/.integrity.jsonand.lab/lab.json - candidate JS discovery now comes from the root app tree (
src/,public/, root configs) instead of staged v3 paths checkManifestHashesis still exported, but only as a compatibility alias forcheckAslImmutability--check-ledgeris a separate doctor-style mode for ledger integrity
