verify / @flop-lab/spec
Spec differ
Suite entry: flop spec. The README below lists the package options.
Reading progress
Spec drift
Does the running devnet match its yellowpaper? flop-spec compares a pinned paper with dated public catalog values and indexed call names. It shows the quoted evidence behind each result. Catalog agreement is not proof of deployed runtime state.
Quick start
Run from the repository root with Node 22 and pnpm:
pnpm install --no-frozen-lockfile
pnpm --filter @flop-lab/spec build
node packages/spec/dist/cli.js diff --section ACommands
node packages/spec/dist/cli.js diff --json
node packages/spec/dist/cli.js params
node packages/spec/dist/cli.js calls
node packages/spec/dist/cli.js diff --section H
node packages/spec/dist/cli.js diff --live --json
pnpm --filter @flop-lab/cli build
node packages/cli/dist/cli.js spec params --jsonThe package exposes flop-spec. The suite exposes flop spec after its binaries are built. Exit status is 1 when any selected row is DRIFT. Invalid arguments or an incomplete live collection return 2 unless a selected DRIFT already requires 1.
The default is an offline replay. --live reads the hosted MCP against the same paper pin. It never refreshes the paper silently. All JSON reports include the full paper commit, comparison time, individual source times and warnings.
Evidence model
The recording pins flop-labs/yellowpaper at 2a2cc8218048a2933071bb2f45d75335560e39d8. The raw paper is split at line boundaries into small JSON envelopes. Reassembly rejects gaps and mixed pins. Appendix A includes enforced parameters, reference parameters and summary rows. Appendix G preserves explicit pallet names and ordered argument names. Abbreviations and logical interfaces remain incomplete. Appendix H preserves the full informative status text.
The public money-path-v1.json and wire-format-v1.json files supply vector cases, pending drafts and wire families. Their inputs, status and expectations stay quoted. Locating them is not executing them. A wire family can contain several nested examples. The money-path file also declares its own older source commit; the raw record preserves that declaration.
The runtime view reads flop_knowledge_get with id_or_path: protocol-params, flop_get_stats and flop_indexer_query. It introspects Transaction before sampling top-level transactions and looking up one transaction by hash. Stats provide dated context. They do not establish parameter values or implementation status. Positional transaction arguments do not establish argument names. Nested batch contents are not treated as independently observed calls.
The catalog warns that repository sources are not mounted beside it. Its values are source claims. No public runtime metadata is part of this recording.
Results
| Result | Meaning |
|---|---|
| MATCH | Exact identifier and comparable value agree. For a name-only call entry, the exact fully qualified name was seen. |
| DRIFT | Both sides provide different values for the same exact parameter identifier and comparable unit. |
| SPEC_ONLY | A parameter is absent from the available catalog or a vector has no runtime execution record. |
| RUNTIME_ONLY | An observed catalog identifier or top-level call has no parsed spec entry. |
| UNOBSERVABLE | Evidence cannot settle the comparison. Each row names the evidence needed. |
Names are case-sensitive. There is no fuzzy matching. A small documented map in src/runtime.ts maps known indexer pallet spellings such as computeChannel to compute_channel. Method spellings are not converted.
Integer grouping underscores are removed. Fixed decimal values use exact integer fractions. The explicit unit table converts FLOP to its base unit, time units to milliseconds and percent/ppt/ppm/ppb to a common ratio. Blocks never become seconds. Unknown units stay distinct. Unknown expressions are exact strings. The generated catalog retains YAML scalar quotes; matching outer quotes are removed while the raw quote stays available. Numeric comparison never passes through a JavaScript floating-point number.
Library
import { recordedReport, recordedSpec, createRuntimeReader, compare } from "@flop-lab/spec";
const offline = recordedReport();
const read = createRuntimeReader();
const { runtime } = await read();
const fresh = compare(recordedSpec(), runtime, {
mode: "live",
at: new Date().toISOString(),
});
console.log(offline.sha, fresh.counts);The reader memoises a result for 60 seconds, including partial failures. It uses the shared MCP client's request spacing and one retry with backoff on transient failures. It samples at most 100 top-level transactions. There is no polling loop. A new CLI process starts with an empty live cache. Offline recordings are immutable snapshots with their original dates, not a freshness cache.
Refresh and checks
pnpm --filter @flop-lab/spec record
pnpm --filter @flop-lab/spec check
FLOP_SPEC_LIVE=1 pnpm --filter @flop-lab/spec checkThe recording script pins the commit in source and saves raw response text, source URL and reception time. Fixtures are capped below 200 KB per file. Review changes before accepting a new recording. Live tests skip when the catalog is unavailable. Normal checks use the bundled real data plus hostile and empty inputs.
What this does not verify
This does not verify deployed storage constants, runtime metadata, execution of test vectors, implementation-status claims, finality of the indexed sample or completeness of Appendix G. A call missing from a bounded sample is not absent from the runtime. A catalog mismatch is not proof of a consensus defect. A MATCH is not a safety verdict. No wallets or write transactions are used.