Skip to content

feat(contract): derived refs, output digests and the dashboard routes' codes - #30

Merged
jm-rivera merged 11 commits into
devfrom
feat/dashboard-build
Oct 29, 2026
Merged

jm-rivera merged 11 commits into
devfrom
feat/dashboard-build

Conversation

@jm-rivera

@jm-rivera jm-rivera commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

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, and python/client-contract/src/dfo_client_contract/refs holds the format 2 schema and examples. A derived member's parts is empty, and its root records its rendering, including the groupby DFO read a summed root with (root_rendering). The artifact selector refuses groupby. rules/output-digest.json pins the output digest (out2). Each row names its stat_var, and a variable that compare, sum_of, share_of or quotient_of writes is named mv_ 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.json gives the cases same_data must 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 the series-left-out rule says when a client issues SeriesLeftOutWarning.

registries/codes.json registers the analysis engine's refusal codes and maps them on datasets.analysis, maps timeout, payload_too_large (413) and the platform codes on presentation.shares, maps the share routes' validation refusals, and maps allowance_exhausted (429) on datasets.pin, presentation.shares and presentation.write. allowance_exhausted has the action wait_for_reset and is not retried, and the retry rule raises any refusal whose Retry-After exceeds 60 s. write_token_invalid takes a new action, stop, since a share made without a token refuses every token. pin_not_permitted is retired. The package mirror under python/spec-kit is 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 xhigh found 15 issues, and a second review found 4 more; all are fixed on this branch.

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.
…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
@jm-rivera
jm-rivera merged commit 6b606ec into dev Oct 29, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant