Repository navigation
Add the first Assess evidence-assessment slice - #52
Merged
Merged
Conversation
DragonSniff may now evaluate completed evidence against acceptance criteria that the product supplies. It still never defines product policy, and a finding is derived output, not a safety certification. The contract fixes the semantics before any code: sequence is arrival order, host monotonic time is the only duration arithmetic, polled observations are uncertain-time intervals, invalid evidence is unknown and never coerced, strict no-hold is the default, and deleting evidence must never move a finding toward PASS. Replaces the thermal-capture statement that DragonSniff never decides whether results pass.
Adds an import-isolated dragonsniff.assess package that takes evidence and profile bytes and returns a deterministic JSON report. It has no filesystem, network, process, or device access. This slice covers the evidence loader with SHA-256 identity and integrity checks, a closed-schema TOML profile, Dragon HTTP and PrusaLink observation intervals, a three-valued timeline with explicit bounded hold, holds_throughout, time-weighted time_in_band, and the report envelope with assess_semantics_version 1. Package re-exports are now lazy so importing the subpackage no longer loads the observer, client, and network stack. The release wheel check now requires the Assess package.
Require a closed, contiguous evidence prefix before deciding findings. Ignore post-terminal records consistently and reject error-bearing observations for both sources. Preserve integer criteria, convert seconds with exact ratios and documented conservative rounding, and compare duration thresholds without rounded fractions. Advance assessment semantics to version 2. Add regressions for all four review findings, expanded malformed-pair deletion checks, and reproducible old-head and mutation validation.
Mauker1
reviewed
Sep 25, 2026
The Findings section said every finding carries reason codes, which contradicted the later rule that decisive PASS and FAIL findings carry none. Only INCONCLUSIVE findings carry reason codes; FAIL is explained by its decisive evidence. No change to Assess semantics or implementation.
Mauker1
approved these changes
Sep 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The first, deliberately narrow slice of Assess: offline evaluation of completed DragonSniff evidence against acceptance criteria that the product supplies.
DragonSniff still never defines product policy. A finding is derived output, and PASS is not a safety certification. Every report says so.
The two original commits are preserved, followed by one correctness-fix commit:
docs: define the Assess evidence-assessment contract—docs/assess.mdfixes the semantics before any code. It also replaces thethermal-capture.mdsentence saying DragonSniff never decides whether results pass.assess: add the first offline evidence-assessment slice— the implementation and tests.assess: preserve uncertainty and exact numeric criteria— fixes the four review findings and advances the contract to semantics version 2.Contract highlights
sequenceis arrival order. Hostmonotonic_nsis the only duration arithmetic. Wall time is provenance only.[request, completion]for Dragon HTTP,[observed_monotonic_ns, monotonic_ns]for PrusaLink. No exact sample time is invented.max_hold_s, which the report echoes.holds_throughout: FAIL only on a proven violation fully inside the window. PASS only when the whole window is proven true. Otherwise INCONCLUSIVE, with reason codes.time_in_band: time-weighted in integer nanoseconds. The in-band fraction is reported as[lower, upper]. PASS only iflower >= min_fraction, FAIL only ifupper < min_fraction.min_fraction = 0is rejected, because it would pass with no evidence.Implementation
src/dragonsniff/assess/has five modules, about 1,000 lines. The API takes bytes and returns text:assess(evidence, profile, *, metadata=None, assessed_at=None).evidence.py: SHA-256 and byte length. Refuses corruption: duplicate or out-of-order sequence, torn tail, bad JSON, bad core fields, non-terminal session metadata. Reports gaps and cross-thread timestamp inversions without rejecting them.profile.py: closed-schema TOML via stdlibtomllib. Unknown keys are rejected at every level, soon_fail,action,webhook, and similar keys cannot enter a profile.engine.py: observation extraction, the three-valued timeline, and the two checks.report.py: the envelope, withassessment_format1,assess_semantics_version2, profile and evidence identity, assumptions, coverage, reason codes, and decisive record sequences. JSON is deterministic and has no timestamp unless the caller suppliesassessed_at.One change outside
assess/— please reviewdragonsniff/__init__.pyeagerly importedObserver. Any subpackage import therefore loadedclient,prusalink,socket,ssl,http.client, andurllib. Assess's own imports were clean, but the process still loaded the whole network stack.The package re-exports are now lazy (PEP 562).
from dragonsniff import Observerand__all__behave exactly as before;__version__stays eager.import dragonsniff.assessnow loads only its six modules, and a subprocess test enforces that.scripts/verify_release_wheel.pynow also requiresdragonsniff/assess/__init__.py.Validation after correctness fixes
5e20cf0325aa4137e88ba54908ed7722ee45f6d4with an assertion demonstrating its intended semantic defect, and passes unchanged on the fixed tree. No helper/API/import failures count as proof.compileallandgit diff --checkpass.python scripts/verify_assess_correctness.py. It operates in temporary copies without changing the checkout.Prior real-evidence gate: #95 Long Haul captures
These results were originally produced before the correctness fixes and are retained for provenance. The exact two captures were subsequently recovered, verified by SHA-256, and rerun against the corrected semantics-v2 head e9c32ad; the real-capture acceptance gate passed.
Both files were verified by content before use, not by filename.
7016ab13f3f449479d632125e32248771dd62a5fba694212b9e20315f14453a186175047…859346b7…mode == power_onfrom heater start to endmode == power_on, settled windowThe loader reproduces the independent manual analysis exactly from the observations it extracts. The time-weighted in-band intervals bracket the manual sample-weighted figures. The known lease-expiry truncation is found at the exact sequence the manual analysis identified.
The captures are 20 MB of device evidence, so they are not committed. The gate ran from a local script.
Not in this slice
Live evaluation, UI, server routes, a CLI, events and triggers, latency, other measurements, and multi-signal predicates. The contract says so explicitly.