Close the v0.6.3 reward-verifier, trust-boundary, sidecar and streaming gaps - #46
Merged
Conversation
The static reward verifier audited only decorators and default arguments, so every other definition-time expression passed with no finding at all: class bases, metaclass and other class keywords, parameter and return annotations, annotated-assignment annotations and type-parameter bounds. `class Hidden(exploit())` was reported as a verified interface. Keyword-only parameters were never inspected either, so a required keyword-only `extra_info` -- which raises TypeError on verl's three-argument call -- passed as correct. Definition-time positions are now audited for expressions that would run where they appear, while ordinary type annotations and base classes stay acceptable. The strongest default level is renamed `interface_shape_verified`, because `interface_statically_verified` read as a safety claim the check cannot make; imports are recorded with `import_runtime_safety: not_verified`, relative bundle-local imports are rejected, and source bytes, AST nodes, AST depth and finding count are bounded so a hostile file yields a bounded diagnostic. The doctor also read `upstream_config_parse_passed`, `distributed_execution_tested` and `algorithm_semantic_parity` out of the bundle's own compatibility report and exposed them as top-level results. SHA256SUMS ships inside the bundle it describes, so anyone who edits a claim can reseal it. Bundle testimony now lives under `bundle_declared_claims` with an explicit `unsigned_self_consistent` trust level, the top-level flags reflect only what this process recomputed, and `--require-verl` performs the upstream parse/merge locally instead of comparing an installed commit id. Portable metadata privacy ran a single absolute-path regex, so a manifest holding an API key, a bearer token and a database URL with inline credentials passed. Structured metadata is now walked so a finding can name a JSON path, unstructured text reports a line number, and matched text is still never returned.
…grity An existing .miniverl.json sidecar was accepted whenever it happened to parse as a JSON object. An empty object, a list-valued rows field, a wrong namespace and an unsupported schema version all read as "this dataset has no extensions", so the file that existed to carry miniVERL provenance silently discarded it. A sidecar is now validated for schema version, exact namespace, a rows mapping, canonical non-negative integer keys inside the source row count, JSON-compatible values and unknown top-level fields, plus optional source_sha256/source_rows binding. Sidecars published by 0.6.0-0.6.2 still read. Diagnostics name the location and never the extension payload, which can hold teacher targets. Conversion called pq.read_table(source).to_pylist(), so a real verl dataset was materialized twice -- once as Arrow, once as Python objects -- before the first row was converted. It now streams record batches through a ParquetWriter into the staging file, with the output schema derived once from the source schema so an optional nested field appearing only in a later row group cannot produce a second, incompatible schema. Publication still happens only at commit, so strict conversion stays complete-or-nothing, and a rejected row now stops the run before the next row group is read. Rejection counts stay exact while their per-row detail is sampled. The release checklist shipped an em dash and the changelog shipped arrows as GBK-mangled CJK sequences: UTF-8 punctuation written back through a non-UTF-8 console. The result is valid UTF-8, so nothing ever raised. Three files also carried a byte-order mark. All are repaired, and scripts/check_text_integrity.py now fails CI on the mis-decoding leaders, on U+FFFD and on an unexpected BOM.
The bridge page now states what the reward check actually proves. The level is named interface_shape_verified rather than interface_statically_verified, because the old name read as a safety claim; the page lists every definition-time position that is audited and says plainly that imported modules are neither run nor proven safe. A new section separates what a bundle declares from what a doctor run recomputes, and states that a bundle's own SHA256SUMS can prove internal consistency only. Both READMEs carry the same scope in English and Chinese. Quality record: 1830 non-GPU/non-network tests, 2 skipped, 6 deselected, 86.10% branch coverage, 5 GPU tests on the RTX 4080 and 3 network tests, measured at e8a36db.
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.
Final correctness and trust-boundary pass before
v0.6.3is tagged. Everydefect below was reproduced against
b769251first; the reproducers are kept asregressions.
The static reward verifier accepted definition-time code
PR #45 stopped
bridge doctorimporting an untrusted reward scaffold, but thestatic policy only audited decorators and default arguments. Everything else
that runs when a module is imported passed with
status: ok,findings: []andthe strongest level:
Class bases,
metaclass=and other class keywords, parameter and returnannotations, annotated-assignment annotations and Python 3.12 type-parameter
bounds are now audited. Only expressions that actually evaluate — calls,
lambdas, comprehensions,
await, walrus — are rejected, so ordinaryannotations such as
-> floatand bases such as(object)still pass.Keyword-only parameters were never inspected either, so this passed as a
verified interface despite raising
TypeErroron verl's three-argument call:The strongest default level is renamed
interface_statically_verified→interface_shape_verified: the old name read as a safety claim the checkcannot make. Imports are listed with
import_runtime_safety: not_verified,relative bundle-local imports are refused, and source bytes, AST nodes, AST
depth and finding count are bounded so a hostile file yields a bounded
diagnostic. 20 new regressions; none of them ever creates the marker file.
A bundle's claims were reported as results
The doctor read
upstream_config_parse_passed,distributed_execution_testedand
algorithm_semantic_parityout of the bundle's owncompatibility-report.jsonand exposed them as top-level fields.provenance/SHA256SUMSships inside the bundle it describes, so anyone whoedits a claim can reseal it — the test builds exactly that bundle.
Output is now split into
bundle_declared_claims(testimony,trust: unsigned_self_consistent),locally_recomputed_checks(this process,against bytes on disk) and
provenance_trust(
signature_verification: not_available). Top-level flags reflect only what wasrecomputed.
--require-verlnow performs the upstream OmegaConf parse andstructured merge locally instead of comparing an installed commit id.
Portable metadata privacy ran one regex
A manifest holding an API key, a bearer token and a database URL with inline
credentials passed, because the only detector was an absolute-path pattern.
Structured JSON/YAML is now walked so a finding names a JSON path
(
$.nested.credentials.api_key), unstructured text reports a line number, andthe scan is bounded by file size, total bytes and finding count. Matched text is
still never returned. Status is
heuristic_passed/heuristic_failed— it is adetector, not de-identification proof.
Malformed sidecars were read as empty
{},{"rows": []}, a wrong namespace andschema_version: 999were allaccepted as "this dataset has no extensions", silently discarding the provenance
the sidecar exists to carry. Schema version, exact namespace, a
rowsmapping,canonical integer keys within the source row count, JSON-compatible values,
unknown top-level fields and optional
source_sha256/source_rowsbinding arenow validated. Sidecars published by 0.6.0–0.6.2 still read. Diagnostics name
the location, never the payload.
Conversion materialized the whole dataset
convert-datasetcalledpq.read_table(source).to_pylist(). It now streamsrecord batches through a
ParquetWriter, with the output schema derived oncefrom the source schema so an optional nested field appearing only in a later
row group cannot produce a second incompatible schema. Publication still happens
only at commit, so strict conversion stays complete-or-nothing, and a rejected
row stops the run before the next row group is read — both proven by
instrumented tests that fail if
read_tableis called or if a later batch isfetched.
Text integrity
docs/release-checklist.mdshipped— not applicableandCHANGELOG.mdshipped
base → SFTas GBK-mangled sequences; three files carried a BOM. Theresult is valid UTF-8, so nothing ever raised. All repaired, and
scripts/check_text_integrity.pynow gates CI on the mis-decoding leaders,U+FFFD and unexpected BOMs. Its allowlist is exactly two files: the detector and
its own tests, which must spell the sequences out.
Validation
not gpu and not network)mkdocs build --strictNo frozen scientific result, task JSONL or published adapter is touched. No new
benchmark, algorithm, distributed claim or OPD/PPO parity claim is added. Issue
#39 remains out of scope.