Verify science workloads within a tolerance, not by identical bytes #627
Open
opened 2026-10-21 17:15:11 +00:00 by rvnminers-A-and-N
·
10 comments
No Branch/Tag Specified
dev
ci/gitea-actions
dependabot/go_modules/go-f5e78d6b71
integration
feat/777-accelerators
fix/workspace-globe-pane-motion
feat/789-pending-action-attribution
feat/741-model-catalog-stream
fix/741-shared-state-reconnect-baseline
feat/741-bootstrap-peers-stream
feat/741-city-table-stream
fix/741-location-stream-client-metadata
fix/741-files-shared-state-coverage
fix/741-settings-stream-e2e-readiness
dependabot/npm_and_yarn/apps/sisyphus/electron-45.0.0
dependabot/npm_and_yarn/apps/sisyphus/desktop-ea22606fe9
agents/app-side-confirmation
feat/files-scoped-by-pool
feat/storage-replication-push-stream
codex/protobuf-v2-lending-state
fix/dev-preview-auth-forwarding
feat/chat-attachment-retention
No results found.
Labels
Clear labels
accessibility
all-platforms
area:agents
area:ai
area:chain
area:ci
area:client
area:daemon
area:p2p
area:project
area:protocol
area:runtime
area:storage
bug
chore
community
dependencies
discussion
discussion/Announcements
discussion/General
discussion/Ideas
discussion/Q&A
discussion/Show and tell
discussion/answered
documentation
duplicate
enhancement
good first issue
help wanted
i18n
infra
invalid
needs:decision
needs:hardware
paired
question
research
security
status:in-review
test
testing
tracking
wontfix
Barrier affecting people with disabilities
Run every platform's packaging and checks on this pull request, not only the three main ones
MCP server, skill, and thinking on the pool
Planner and model providers
Blockchain, SISY, verification
Continuous integration and build workflows
Desktop and web clients
sisyphusd coordinator, worker, scheduler
libp2p hosts, relays, discovery, connections between nodes
Project planning, roadmap, and governance
Protobuf schemas and RPC contracts
Workload execution and environments
Content-addressed storage, IPFS, Kubo, Cluster, S3, names, pinning
Something isn't working
Repository health, templates, Discussions, contributor experience
Updates to actions, Go modules or npm packages
Migrated from GitHub Discussions
GitHub Discussions category: Announcements
GitHub Discussions category: General
GitHub Discussions category: Ideas
GitHub Discussions category: Q&A
GitHub Discussions category: Show and tell
Q&A discussion with an accepted answer
Improvements or additions to documentation
This issue or pull request already exists
New feature or request
Good for newcomers
Extra attention is needed
Translations and right-to-left layouts
Build, CI, releases
This doesn't seem right
Waits on a decision from both owners
Waits on a machine we do not have yet
Built together by both maintainers, with co-authored commits
Further information is requested
Needs investigation or a design decision
Sealing, keys, access control, tokens, the security model
Built and in an open pull request; closes when it merges
Tests, test harnesses and the rehearsal
Roadmap and meta issues
This will not be worked on
type
Feature
A request, idea, or new functionality (GitHub issue type)
type
Task
A specific piece of work (GitHub issue type)
Milestone
No items
No Milestone
Real workloads
Projects
Clear projects
No projects
Sisyphus roadmap
Todo
No Assignees
rvnminers-A-and-N
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: Sisyphus/Sisyphus#627
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Why
The pool checks work by running a task twice, with
verifyon other workers oraudit_shareon the coordinator, and comparing the bytes. That only works for workloads whose results are the same to the last bit on any machine, so every science workload so far refuses checking. Measurements:md(OpenMM, #577): the same seed gives different energies between runs, even on one machine, because MD is chaotic.qchem(xtb 6.7.1, #626): results are bit-identical on one machine, run after run and however the job is split. But different processors disagree: under emulated CPU models, the R620/Sandy Bridge, Haswell/Skylake (AVX2+FMA) and AMD EPYC each gave a different set of bits. The differences are only in the last digits: the HOMO-LUMO gap in the 11th decimal, the free energy in the 14th, coordinates in the 10th. Total energies to 12 decimals, and frequencies, agreed.render,transcribeandocr: these vary too, through denoising, model maths and version drift.So exact comparison can't check useful science on a mixed pool. Comparing within a tolerance could, for any workload where honest results agree to a known precision. That's what proof of useful work (#589) needs.
What
Compare(a, b []byte) (same bool, why string). A workload that has it is checked with it instead of byte equality, andverify/audit_sharestop refusing it.qchemas the first user, with two tiers. Both tiers also require the same convergence and failure flags.mdlater, by challenge on short windows, as planned on #577. That needs checkpoints first.Done when
A
qchemjob withverify: 2succeeds when its two results come from different CPU types, and fails when one worker's energies are altered.The mechanism landed in #629 (
03c1556):runtime.Comparing, used by bothverifyandaudit_share, with results grouped around the one that agrees with the most others. What's left here is each workload's ownCompare, starting withqchem(xtb differs in the 10th to 14th decimal across processors), thenmd, then model-based forecasts.Before writing qchem's
CompareI checked it against what a qchem task returns, and #629's mechanism can't reach it as things stand. There are two blockers:ContainerOutput: the CIDs of stdout,summary.jsonandstructures.xyz.Compare(a, b []byte)sees only those CIDs and has noBlobsto open them with.Task.Samerequires compared results to have stored the same blobs (verify.go:67). Across processors xtb's energies differ in the 11th decimal and its coordinates in the 10th, sosummary.jsonandstructures.xyzhash differently.Samereturns "they stored different blobs" beforeCompareis ever called.Options:
Aggregate. qchem would run its container but return the summary and geometries inline, as JSON, instead of as files.Comparethen parses both outputs and holds energies, gaps, dipoles, frequencies and coordinates to a tolerance. #629 stays as it is. The cost is output size: an XYZ structure is about 50 bytes per atom, so a run of 25 drug-sized conformers is around 100 KB. Inline outputs are already capped, so a job would be split into runs small enough to fit.Comparethe blobs (Compare(ctx, blobs, a, b)) and drop the same-blobs rule for comparing workloads. This is more general, and md's trajectories will need it too. But the coordinator would have to fetch both workers' blobs to compare them, and a result that verifies would still name blobs the other worker never stored.I lean to A for qchem now, since it needs no change to #629 and keeps verification on the coordinator cheap. B can come later, when md needs it. Does that match how you pictured it?
Yes, A is how I pictured it for qchem. It keeps #629 untouched and verification on the coordinator cheap. B should wait until md actually needs it.
Two points for the
Compareitself, so cross-processor noise doesn't become false mismatches:On sizing, deciding the split from the atom count up front (roughly 50 bytes per atom per conformer, against the inline cap) is simpler than retrying a run that overflows.
/cc @rvnminers-A-and-N
qchem is now the first workload using the tolerance-based verification path: Austin’s #661 merged as
1fd8a53after its full CI, including coverage and real-image tests, passed. Its task returns the numeric results inline for comparison;Compareaccounts for aligned geometry and rotates dipoles into the same frame. This closes the qchem portion, not the tracking issue: MD and model-based forecasts still need workload-specific comparison, with the Chronos candidate work tracked in #665./cc @rvnminers-A-and-N
One spec/implementation mismatch surfaced in the open-issue audit. The original “What” section proposes qchem tolerances of 1e-8 Eh, 1e-6 eV for the gap, 0.1 cm⁻¹ for frequencies, and 1e-5 Å for coordinates. The merged implementation in #661 instead uses 1e-6 Eh for energies/free energy, 1e-3 eV for gaps, 1 cm⁻¹ for frequencies, and 1e-3 Å aligned RMSD (plus dipoles/intensities). The PR explains these as measured-drift-based tolerances, so I’m not changing the spec unilaterally. Austin, can we confirm the landed bounds are the intended contract and then update the issue’s proposed values? Also, the Done-when’s cross-CPU qchem scenario should be distinguished from the generic comparator tests in #629. /cc @rvnminers-A-and-N
Audit update: the Chronos forecast-comparison gap mentioned in the earlier status is now covered. Merged #667 adds tolerance-based
Comparefor the single-seriesforecastworkload; #668 extends it toforecasts, comparing each series against its own scale. Both use the pinned Chronos image, and #665 records the accepted design and benchmark follow-up. So I am no longer treating Chronos model forecasts as outstanding in this issue.\n\nRemaining scope here is MD-specific verification (which needs its challenge/checkpoint design) and confirming the qchem tolerance contract: the proposed values in this issue differ from the measured bounds implemented in #661. I have not changed those values without Austin’s confirmation.\n\n/cc @rvnminers-A-and-NLior, thanks for holding this for me. My answer is both: two tiers, and I've updated the issue body to match.
The comparator would pick the tier from the CPU model each worker reports, and record which tier settled the task for the ledger (#580). Agreed on keeping the cross-CPU qchem "Done when" separate from the generic comparator tests in #629.
One question: do results already carry the worker's CPU model somewhere the comparator can see, or does that need a small addition? If it needs one, I'm happy to write it.
I checked the current
devimplementation: no, the comparator cannot see the worker's CPU model today.worker.HardwareincludesCPUModel, butpb.TaskResultcarries only the task/attempt, outcome, blob references and model-use data;runtime.Comparing.Comparereceives only the two output byte slices. So choosing the same-CPU vs cross-CPU qchem tolerance tier needs an addition.I would avoid trusting a CPU model embedded in the output itself, since the worker controls that payload. The coordinator should associate each result with the hardware metadata of the worker that executed that attempt and provide that context to the comparator. Since you offered to write this piece, would you like to take the protocol/coordinator change? I’ll hold off on overlapping work until we coordinate.
/cc @rvnminers-A-and-N
Thanks for checking. Agreed: the CPU model has to come from the coordinator, never from the worker's own output. I'll take the protocol/coordinator change.
Rough shape:
CPUModelit already has fromworker.Hardwareat assignment time.Comparegrows a small context argument, or there's a sibling interface, so workloads that don't care are untouched.I'll put it up as its own PR once #771 (upscaling) is in, and tag you on it.
@excho0 #773 implements the two tiers. The coordinator takes each worker's CPU model from the Hello it joined with (
worker.Hardware.CPUModel), never from the output. It notes it when it hands out the attempt, and the comparator only uses the tight tier when both models are known and equal. The tier is stored per task (tasks.tier) for #580. Four open questions are in the PR body: whether to add the tier to the signed job record, the tight dipole/intensity values I picked, recording mixed tiers ascross-cpu+same-cpu, and the real two-CPU xtb run that "Done when" still needs.