Skip to content

feat(client-contract): add the SDK 0.2 rules and codes, adopt party_totals, and re-record at apis 133262c5e - #52

Merged
jm-rivera merged 6 commits into
devfrom
feat/client-contract-sdk-0.2
Nov 14, 2026
Merged

jm-rivera merged 6 commits into
devfrom
feat/client-contract-sdk-0.2

Conversation

@jm-rivera

@jm-rivera jm-rivera commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

The client contract gains the rules, client codes and saved-file schema that SDK 0.2.0 implements, adopts party_totals: false as the request spelling of the party totals cut, and is re-recorded against dev running DevelopmentFinanceObservatory/apis aacbe6a4, which accepts that spelling, serves licence beside license, and reports party totals kept per series and per derived root.

Part of DevelopmentFinanceObservatory/sdk#19

Changes

  • rules/timeout-and-retries.json (new): DFO_TIMEOUT and DFO_MAX_RETRIES, 42 vectors, precedence call > client argument > variable > default, an ASCII grammar, and with_options taking no variable. Listed in RULES, rules.schema.json and both READMEs.
  • rules/cache-dir.json: the platform default root is dfo, with v1/dfo/cache1 below it. With no explicit root a client reads the legacy readerkit directory, artifacts by digest and manifests under the cached-manifest checks, and copies a hit in. BBLOCKS_CACHE_DIR stays the lowest explicit root.
  • rules/cache-layout.json: the fetched/sha256/<hex> entry, holding the fetch time as UTC seconds, removed and counted with its artifact.
  • client-codes.json: the FormatError and BundleError reasons as codes (carried as code, with reason equal), ref_unavailable, proxy_invalid and match_unresolved, and invalid_argument covering settings variables. Both classes join the scenario class enum.
  • scenario.schema.json, tools/validate_client_contract.py, tools/capture_client_contract.py: a party_totals_left_out dataset outcome, derived by both tools, read leniently as "Strict fields" reads.
  • saved-file.schema.json and saved-files/ (new): the Parquet dfo.* keys, four accepted and nine rejected examples, checked by the validator, including the format version against the ref and party-totals members against the ref.
  • dataset-ref.schema.json, refs/, rules/file-selector.json, rules/output-comparison.json, the validator and the recorder: party_totals: false and without_party_totals: true both mark a cut in the same format version; a disagreeing pair or a keep value is invalid; builds post party_totals: false.
  • rules/role-keys.json: columns, the frame party columns that name each caller key (financingProvider and the other origin columns to origin, the recipient columns to destination), equal to dfo-apis ROLE_AXES, with vectors.
  • Party-totals entries in scenario.schema.json, saved-file.schema.json, the README and the validator carry an optional kept_in: each series once, with the sorted time periods in which the listed totals stayed, in the server's order. Readers drop an entry that breaks the order or holds an empty string. A derived member's saved entries name its roots in the member's root order, and its own id is refused. Five new saved-file examples cover kept series, root entries and each refusal.
  • served/openapi.json and every scenario: recaptured and re-recorded at apis aacbe6a4. The served document gains kept_in and the derived manifest root's party_totals_left_out; the long-build scenarios start one year later.

Notes for reviewers

  • Servers keep serving without_party_totals in renderings, and clients keep writing it in refs, until 0.1.x clients are retired, because SDK 0.1.0 rejects an unknown member there. The README states this transition.
  • Dev now answers "Kenya's GDP" as a definite part, so TWO_PLACES names Congo in both parts to keep two entity_ambiguous parts. That is a change in dev's search, independent of this PR.
  • No recorded scenario serves kept_in or a derived member's entries, so saved-file examples and validator tests pin those rules. Dev serves kept_in for "OOF to India by donor" (1968, DACOfficialDonors), which is not a recorded scenario.
  • feat!: adopt the client contract at spec-kit 2f7462a sdk#36 adopts this contract, and chore(registry): pin spec-kit 2f7462a, the client contract for SDK 0.2 apis#299 moves dfo-apis's nine spec-kit pins here and tests columns against ROLE_AXES.

Testing: in python/client-contract, ruff check, ruff format --check and pytest (307 passed); at the root, tools/validate_client_contract.py (valid, 126 scenarios) and pytest tools/tests (719 passed); the repo's pre-commit hooks. A differential check of 2,407 kept_in lists found the dfo-apis writer, this validator and both SDK readers in agreement on every accept and reject. SDK 0.1.0 and 0.2.0 live journeys against dev at 133262c5e: 8 passed and 2 skipped each.

…file schema

Adds the timeout-and-retries rule for DFO_TIMEOUT and DFO_MAX_RETRIES,
with a strict ASCII grammar and precedence call > client > variable >
default. The cache-dir rule roots the platform default at `dfo` and
reads the legacy readerkit directory, artifacts and manifests, when no
explicit root is set, copying a verified hit in. cache-layout gains the
`fetched/sha256/<hex>` entry.

client-codes.json gains the FormatError and BundleError reasons and
ref_unavailable, proxy_invalid and match_unresolved; invalid_argument
covers settings variables. Scenarios gain a party_totals_left_out
dataset outcome, read leniently as Strict fields reads. A new
saved-file.schema.json describes the Parquet dfo.* keys, with accept
and reject examples the validator checks.

`party_totals: false` is the request spelling of the party totals cut.
Refs accept it beside `without_party_totals: true` in the same format
version, a disagreeing pair or a keep value is invalid, and the
recorder posts `party_totals: false`. The README names `licence*` as
the preferred spelling on served citation and graph source shapes.
… apis 133262c5e

served/openapi.json is captured from DevelopmentFinanceObservatory/apis
133262c5e, which accepts party_totals on requests and serves licence
beside license. Every scenario is re-recorded against dev at that
commit, so builds post party_totals: false. The two-place question
names Congo in both parts, since dev now reads "Kenya's GDP" as
definite, and the long-build picks move to 1970 and 1971.
…mpossible saved-file dates

derived_identities compared raw root renderings, so a root spelling the
cut party_totals: false conflicted with the same root spelled
without_party_totals: true. It now folds each through served_rendering.
The saved-file check refuses a dfo.fetched_at or held_until date that
does not exist, such as 2026-02-30, as format_invalid, as both SDK
loaders do, with a reject example for each.
… totals per series

rules/role-keys.json gains `columns`, the frame party columns that
name each caller key (dfo-apis `ROLE_AXES`), so a client can show
`origin` beside a party-totals entry's `financingProvider`.

Party-totals entries carry an optional `kept_in`: each series once,
with the sorted time periods in which the listed totals stayed. Readers
take the server's order and drop an entry that breaks it or holds an
empty string. A derived member's saved entries name its roots, in the
order of the member's roots, and its own id is refused. New saved-file
examples cover kept series, root entries and each refusal.
…t apis aacbe6a4

The served document gains `kept_in` and the derived manifest root's
`party_totals_left_out`. The long-build scenarios start one year later,
as each re-record does.
@jm-rivera
jm-rivera merged commit 1100a0d into dev Nov 14, 2026
22 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