Repository navigation
feat(contract): derived refs, output digests and the dashboard routes' codes - #30
Merged
Merged
Conversation
DatasetRef format 2 names derived members: an ops_ spec with its recipe hashes, the ocv_ version, an output digest (out_), the root versions with their renderings, the execution identity and resolved periods. Format 1 refs validate unchanged. New rule vector sets pin the output digest (JCS over roles, period, value and unit, leaving out stat_var and provenance), output comparison (== against same_data), operation outputs (share_of in percent, join in long format, compare as data minus other, growth as a fraction), rolling composition (rolling_populations_differ) and share publication (slot URLs survive a live replace; a snapshot cannot be replaced). The registry gains the datasets.analysis and presentation.shares endpoints and the codes allowance_exhausted, rolling_populations_differ, several_members, share_not_replaceable, write_token_required and write_token_invalid. operations.json states each verb's output shape and pairs sum and compare by role.
The datasets.analysis endpoint gains a row for each of the 34 refusal codes the analysis engine raises, including compare_no_key_matched and sum_of_no_key_matched for paired calls, each 422 with the fix_request action. operations.json lists unmatched_key under sum's and compare's left-out reasons and describes their paired form: `on` pairs data's members with other's by role, and compare returns data minus other.
datasets.analysis also answers 27 existing Datasets codes, for roots it cannot read or build (snapshot_not_found, artifact_expired, recipe_not_found, rendering_not_recorded and others) and for platform faults. Each maps at the status it has on the Datasets endpoints.
datasets.analysis answers timeout at 504 when a run passes its deadline. presentation.shares maps not_found, request_invalid, frame_unavailable, edit_conflict, service_unavailable, internal_error and timeout at the statuses the presentation write endpoint uses.
…-out warning presentation.shares maps binding_invalid, schema_invalid, constraint_violation and resource_exhausted at 400 and release_mismatch at 503, the statuses the components routes use, and a new payload_too_large at 413 for a share body over the routes' limit. pin_not_permitted is retired: the pin route admits any caller under its allowance. The client contract gains the payload_too_large action row and the series_left_out warning, which a client issues when a derived frame left series out for missing data.
allowance_exhausted answers 429 on presentation.write, where creating or revising a card spends the caller's daily card allowance.
The output digest (out2) holds each row's stat_var, so frames that pin the same numbers to different variables differ; every derived identity in refs/ and output-comparison.json is computed by the dfo-apis runner, and the validator checks that equal identities agree across fixtures. allowance_exhausted is never retried and a Retry-After above 60 s raises at once. write_token_invalid takes a new action, stop. The series-left-out rule fires on a derived manifest's left_out, growth's left-out reasons are stated with vectors, a derived member's parts are empty, a growth window starts before it ends, and a scenario fetches dataset refs only. share lists unmatched_key among its left-out reasons.
The output digest names a variable that compare, sum_of, share_of or quotient_of writes by its verb and its inputs' variables, so equal computations over equal variables share a digest across recipes, engine releases and rebuilds that move no number, and swapped sides differ. Output-digest vectors carry a variables map; three new vectors pin the naming.
This was referenced Oct 29, 2026
…oots
A minted variable is named mv_ plus the first 32 hex of SHA-256 over the
RFC 8785 JSON of {verb, slot: sorted input names}, 35 characters at any
depth. rules/README.md states the form, three output-digest vectors are
regenerated, and rules.schema.json requires the mv_ form in vectors.
A derived ref's root takes its own root_rendering, which admits the
groupby (by, op sum, levels) DFO read a summed root with. The artifact
rendering selector still refuses groupby. Three ref vectors cover a
grouped root, a groupby with another op, and groupby on an artifact.
The client contract validator compares a root's groupby with the one
its scenario posted, and leaves it to the schema when none was posted.
Output-digest vectors carry name_documents, the document each mv_ name hashes, and a new quotient-of-a-sum-of vector names a minted variable whose input is another minted variable. The validator checks that each name hashes from its document and that every nested mv_ name has one. The grouped-root ref vectors record by sorted, as DFO writes it, with ids from a dfo-apis run_analysis. rendering and root_rendering share one selector definition, and root_rendering adds only groupby. The validator's derived-identity check includes each root's rendering.
# Conflicts: # python/client-contract/CHANGELOG.md # python/client-contract/README.md # python/client-contract/src/dfo_client_contract/contract.py # python/client-contract/src/dfo_client_contract/rules/README.md # python/client-contract/src/dfo_client_contract/rules/rules.schema.json # python/client-contract/tests/test_rules.py # tools/tests/test_validate_client_contract.py # tools/validate_client_contract.py
This was referenced Oct 29, 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.
The client contract gains derived refs and the rules both SDKs and dfo-apis share for computed data, and the registry gains the codes the analysis, pin, card and share routes answer. A ref may name derived members (
ops_subject,ocv_version) beside dataset members, one kind per ref, andpython/client-contract/src/dfo_client_contract/refsholds the format 2 schema and examples. A derived member'spartsis empty, and its root records its rendering, including thegroupbyDFO read a summed root with (root_rendering). The artifact selector refusesgroupby.rules/output-digest.jsonpins the output digest (out2). Each row names itsstat_var, and a variable that compare, sum_of, share_of or quotient_of writes is namedmv_plus 32 hex of SHA-256 over its verb and its inputs' variable names, 35 characters at any depth. Each vector carries the name documents, including one minted variable built on another, so equal computations over equal variables share a digest across recipes, engine releases and rebuilds that move no number, while swapped sides differ.rules/output-comparison.jsongives the casessame_datamust answer. The dfo-apis runner computes every derived identity in the fixtures, and the validator checks that equal identities agree across fixtures. The analysis rules describe the recipe tree, its normal form, growth's left-out reasons and the window's order, and theseries-left-outrule says when a client issuesSeriesLeftOutWarning.registries/codes.jsonregisters the analysis engine's refusal codes and maps them ondatasets.analysis, mapstimeout,payload_too_large(413) and the platform codes onpresentation.shares, maps the share routes' validation refusals, and mapsallowance_exhausted(429) ondatasets.pin,presentation.sharesandpresentation.write.allowance_exhaustedhas the actionwait_for_resetand is not retried, and the retry rule raises any refusal whose Retry-After exceeds 60 s.write_token_invalidtakes a new action,stop, since a share made without a token refuses every token.pin_not_permittedis retired. The package mirror underpython/spec-kitis a byte copy.This merges first, since the dfo-apis, dfo-ai and SDK PRs pin it. The served OpenAPI capture, strict-field pointers and scenario steps for the new routes follow in a separate PR, captured from the deployed service once dfo-apis deploys them to dev.
Testing:
uv run tools/validate_client_contract.py,uv run tools/validate_registry.py(248 entries, mirror matches),pytest tools/tests(572 passed), and lint and tests on 3.12 and 3.13 for every package,python/client-contract(216) included. dfo-apis replays every output-digest and operation-outputs vector through its runner, and both SDKs replay the contract's rules and scenarios./code-review xhighfound 15 issues, and a second review found 4 more; all are fixed on this branch.