Repository navigation
release: spec-kit b3ac9b0 to production - #41
Merged
Merged
Conversation
…' codes (#30) * feat(contract): add derived refs, an output digest and analysis rules 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. * feat(registry): register the analysis engine's refusal codes 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. * feat(registry): map the Datasets codes the analysis route serves 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. * feat(registry): map timeout on analysis and the platform codes on shares 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. * feat(registry): map the share routes' refusals and add the SDKs' left-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. * feat(registry): map the card allowance on presentation writes allowance_exhausted answers 429 on presentation.write, where creating or revising a card spends the caller's daily card allowance. * fix(contract): name each value's variable in the output digest 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. * fix(contract): name a computed variable by what was computed 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. * fix: name minted variables by a fixed-size digest and admit grouped roots 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. * fix: pin nested minted names and record grouped-root ids from a real run 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.
dfo-apis' PUT /api/presentation/shares/{id}/import, which the website's
share migration job calls once per share, refuses with share_id_taken
(409) when the id holds another share or the same share under another
write-token digest, and share_import_not_permitted (403) when the caller
lacks the import principal. Both sit on presentation.shares, with
actions.json rows fix_request and request_scope.
Adds the datasets.exports and datasets.export_link endpoints for the dfo-apis export routes, with provenance_unavailable and licence_not_redistributable. Adds the mcp_refusal channel and mcp.tools endpoint for refusals an MCP tool result carries, with tool_not_found, frame_ref_incomplete, frame_not_held, frame_expired and rolling_reanchor_unavailable.
A prepare that names only a spec_id resolves its newest version and can rebuild it, so datasets.exports carries the 21 codes datasets.definition answers for a rebuild, at the same statuses.
…sets.exports entities_unbound and resolution_ambiguous are catalogue entries no rebuild raises.
Definitions of frame_not_held, frame_expired, rolling_reanchor_unavailable and provenance_unavailable now state the conditions dfo-ai and dfo-apis serve them for, and provenance_unavailable takes the fix_request action. The mcp.tools endpoint and the mcp_refusal channel require each other in the schema. Eight codes only an MCP tool result carries join the registry, and rate_limited and transient_unavailable share their spelling with the proxy table, so the proxy check refuses only codes that reach a problem document or a no_data reason. datasets.export_link registers identity_quarantined, as datasets.files does.
…face mcp.tools now holds every code data-mcp, analysis-mcp, presentation-mcp and the combined server write, so a mapping states where a code appears. presentation-mcp also forwards platform codes it does not write itself. A proxy code may share a spelling only with a code whose every mapping is mcp_refusal, and rate_limited and transient_unavailable are worded to hold on both surfaces. provenance_unavailable takes the stop action, since a recipe root that cannot be cited survives a rebuild. Definitions name no store mechanics, and the README states every field of the mcp_refusal envelope.
…-mcp-codes feat(registry): register the export and MCP refusal codes
…rame.rows read them
…he canonical byte stream
…and cap a refused failed poll's Retry-After The README said a fetch warns series_left_out only for the rolling anchor's left-out series. The rule, its vectors and test_rules warn for any manifest's left_out and for left_out_complete false. LongBuild.polled decided whether to repost after an operation_failed refused poll with retryable(), so a Retry-After over the 60-second cap reposted at once. tries_again now decides for every refused poll. The CHANGELOG counts 148 active refusal codes in actions.json.
…nce under the cap
…t-doc-and-poll-cap fix(client-contract): state the series_left_out rule the vectors pin and cap a refused failed poll's Retry-After
…ation-read-endpoints feat(registry): map every Presentation route and state where a frame refusal lands
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.
Releases spec-kit at
b3ac9b0to production, cut onrelease/2026-10-31: five pull requests.POST /api/datasets/exportsandGET /api/datasets/exports/{export_id}, the rebuild refusals ondatasets.exports, and the newmcp_refusalchannel with every code dfo-ai's MCP servers write.series_left_outrule its vectors pin in the client-contract README, has the reference client raise a refusedoperation_failedpoll whoseRetry-Afterpasses 60 seconds, and counts 148 refusal codes in the CHANGELOG. No registry entry, action row or vector changes.presentation.frames,presentation.component_read,presentation.component_data), states where a frame refusal lands (service_unavailable503,frame_unavailable404 withcause.coderecipe_pending,internal_error500), registersover_ceiling(422) ondatasets.observationsanddatasets.files, and validates stored unit cells whereunit_cellsandFrame.rowsread them. It adds no code.ai on
devpins2dd2400, the head of #37's branch, and apis pinsafdae02, the head of #39's branch. This branch reaches both through their merge commits. Merge this first, with a merge commit, so both pins are onmainbefore the apis and ai releases build.Testing: CI passed on each pull request into
dev.