mostlyright-data 0.29.5__tar.gz → 0.29.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/PKG-INFO +1 -1
  2. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/pyproject.toml +1 -1
  3. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/5-draft-one-recipe-document-one-call.md +6 -5
  4. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/making-a-table-incremental.md +9 -6
  5. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/sources.md +1 -1
  6. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/fast_features.py +3 -10
  7. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/recipe_lint.py +16 -15
  8. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/.gitignore +0 -0
  9. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/README.md +0 -0
  10. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/scripts/hatch_build.py +0 -0
  11. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/SKILL.md +0 -0
  12. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/agents/openai.yaml +0 -0
  13. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/1-open-the-page-and-the-link-to-it-in-the-first-message.md +0 -0
  14. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/2-brief-two-to-four-questions-each-with-a-recommended-answer.md +0 -0
  15. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/3-probe-read-a-source-before-committing-to-it.md +0 -0
  16. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/4-decide-say-what-you-chose-what-you-refused-and-ask-one-question.md +0 -0
  17. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/6-build-one-run-sized-to-acquire-every-measured-source-whole.md +0 -0
  18. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/7-interrogate-ask-the-run-what-it-actually-delivered.md +0 -0
  19. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/8-fix-revise-the-document-and-register-it-again.md +0 -0
  20. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/9-present-only-what-survived-inspection-with-caveats.md +0 -0
  21. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/agent-protocol.md +0 -0
  22. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/autonomous-delivery.md +0 -0
  23. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/before-the-first-tool-call.md +0 -0
  24. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/boundaries.md +0 -0
  25. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/cloud-authentication-preflight.md +0 -0
  26. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/commands.md +0 -0
  27. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/cross-repository-protocol-reference.md +0 -0
  28. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/installation-parity.md +0 -0
  29. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/live-run.md +0 -0
  30. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/narrating-the-run.md +0 -0
  31. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/not-hosted-yet.md +0 -0
  32. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/one-install.md +0 -0
  33. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/prediction-labels.md +0 -0
  34. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/preparing-table-search.md +0 -0
  35. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/promote.md +0 -0
  36. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/readers.md +0 -0
  37. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/receipts.md +0 -0
  38. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/recording-a-stream-venue.md +0 -0
  39. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/recovering-an-import-failure.md +0 -0
  40. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/reference-pages.md +0 -0
  41. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/required-protocol.md +0 -0
  42. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/source-credentials.md +0 -0
  43. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/the-one-thing-to-say-about-the-skill-itself.md +0 -0
  44. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/transforms.md +0 -0
  45. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/user-communication-contract.md +0 -0
  46. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/references/writing-a-decision-record.md +0 -0
  47. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/skills/mr-data-build/scripts/write_research_notebook.py +0 -0
  48. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/__init__.py +0 -0
  49. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/agent_protocol.py +0 -0
  50. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/canonical.py +0 -0
  51. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/formats.py +0 -0
  52. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/hosted_crawler_protocol.py +0 -0
  53. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/key_seam.py +0 -0
  54. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/page_coverage.py +0 -0
  55. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/part_check_evidence.py +0 -0
  56. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/session_probes.py +0 -0
  57. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/skill_assets.py +0 -0
  58. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/table_manifest.py +0 -0
  59. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/__init__.py +0 -0
  60. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/acquire.py +0 -0
  61. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/acquire_cancel.py +0 -0
  62. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/activity.py +0 -0
  63. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/approvals.py +0 -0
  64. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/categories.py +0 -0
  65. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/commands.py +0 -0
  66. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/dataset-categories-v1.json +0 -0
  67. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/download.py +0 -0
  68. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/narrative.py +0 -0
  69. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/parity.py +0 -0
  70. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/probe.py +0 -0
  71. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/progress_rate.py +0 -0
  72. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/progress_vocabulary.py +0 -0
  73. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/propose.py +0 -0
  74. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/recipe.py +0 -0
  75. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/recipe_brief.py +0 -0
  76. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/recipe_explain.py +0 -0
  77. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/recipe_forecast.py +0 -0
  78. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/research.py +0 -0
  79. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/router.py +0 -0
  80. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/run_diagnose.py +0 -0
  81. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/runs.py +0 -0
  82. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/session.py +0 -0
  83. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/stream.py +0 -0
  84. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/stream_venue.py +0 -0
  85. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/studio_capabilities.py +0 -0
  86. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/transport.py +0 -0
  87. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/user_agent.py +0 -0
  88. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/v4.py +0 -0
  89. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/v4_artifacts.py +0 -0
  90. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/v4_catalog.py +0 -0
  91. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/v4_connected.py +0 -0
  92. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/v4_connections.py +0 -0
  93. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/v4_dataset_covers.py +0 -0
  94. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/v4_datasets.py +0 -0
  95. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/v4_handoff.py +0 -0
  96. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/v4_narrative.py +0 -0
  97. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/v4_public.py +0 -0
  98. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/v4_query.py +0 -0
  99. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/v4_reader.py +0 -0
  100. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/v4_runs.py +0 -0
  101. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/v4_search.py +0 -0
  102. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/v4_secrets.py +0 -0
  103. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/v4_stream.py +0 -0
  104. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/v4_tables.py +0 -0
  105. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/thin/vocabulary.py +0 -0
  106. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/ux/__init__.py +0 -0
  107. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/ux/attendance.py +0 -0
  108. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/ux/clarification.py +0 -0
  109. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/ux/cloud_auth.py +0 -0
  110. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/ux/commands/__init__.py +0 -0
  111. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/ux/commands/auth.py +0 -0
  112. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/ux/commands/clarify.py +0 -0
  113. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/ux/commands/login.py +0 -0
  114. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/ux/commands/whoami.py +0 -0
  115. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/ux/credential_native.py +0 -0
  116. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/ux/credential_store.py +0 -0
  117. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/ux/credentials.py +0 -0
  118. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/ux/login.py +0 -0
  119. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/ux/path_kind.py +0 -0
  120. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/ux/plain_file.py +0 -0
  121. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/ux/remediation.py +0 -0
  122. {mostlyright_data-0.29.5 → mostlyright_data-0.29.7}/src/mostlyright/data_harness/ux/render.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mostlyright-data
3
- Version: 0.29.5
3
+ Version: 0.29.7
4
4
  Summary: Mostly Right hosted CLI for reviewed datasets
5
5
  Project-URL: Homepage, https://mostlyright.md/
6
6
  Project-URL: Documentation, https://mostlyright.md/docs/guides/cli/
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mostlyright-data"
3
- version = "0.29.5"
3
+ version = "0.29.7"
4
4
  description = "Mostly Right hosted CLI for reviewed datasets"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -455,11 +455,12 @@ from the accepted subset — `Cel`, `ug/m3`, `km/h`, `hPa`, `{count}` and the re
455
455
  out in [Units](https://mostlyright.md/docs/reference/units/). Write the code rather than a name:
456
456
  `ug/m3` composes and `microgram_per_cubic_meter` does not.
457
457
 
458
- **Nothing resolves the code, so there is no `UNIT_*` refusal to lean on.** The recipe schema bounds
459
- the length of `unit` and nothing else; registration checks only that `units[].column` names a
460
- declared column and answers `422 RECIPE_DOCUMENT_INCOHERENT` at `/units/N/column` when it does not;
461
- the run never reads `units` at all. A code outside the subset therefore costs nothing at build time
462
- and costs every reader afterwards, and a column declared in metres that holds feet is caught by
458
+ **Registration resolves the code and reads no data.** The recipe schema bounds the length of
459
+ `unit`; registration then checks that `units[].column` names a declared column, answering
460
+ `422 RECIPE_DOCUMENT_INCOHERENT` at `/units/N/column` when it does not, and resolves each
461
+ `units[].unit` against the subset, answering the same code at `/units/N/unit` when it cannot.
462
+ `mr-data recipe` does not resolve the code locally, so that refusal arrives from registration. The
463
+ run does not read `units`, so a column declared in metres that holds feet is caught by
463
464
  nothing. Convert in the statement, then declare the unit of what the column ends up holding. Leave a
464
465
  column out of `units` rather than declare something approximate — a density, a rate, anything whose
465
466
  unit is genuinely new. `none` is not a unit and does not become one. Remember that the two
@@ -105,8 +105,9 @@ Studio records the answer as one classification per source:
105
105
  | a `window` carrying a `request` | `window` | `acquire_incremental` |
106
106
  | none of those | `resync_only` | `resync_required` |
107
107
 
108
- The rows are in Studio's precedence order, and the first match wins. A source that states both
109
- `closed: true` and a request window is `closed`, and its window is never read. One `resync_only`
108
+ The rows are in Studio's precedence order, and the first match wins. A source may not state both
109
+ `closed: true` and a request window: registration refuses that pair with
110
+ `422 RECIPE_DOCUMENT_INCOHERENT` at `/sources/N/closed`. One `resync_only`
110
111
  source makes the whole table resync-only, however truthful its siblings are. Say which sources you
111
112
  left `resync_only` and why, because a recipe that never asked the question registers the same way
112
113
  as one that did.
@@ -318,10 +319,12 @@ call:
318
319
 
319
320
  - `parameter` is declared with `required: true`. `{id}` is the whole of one `static_query` value
320
321
  and appears nowhere else.
321
- - `key_column` is a column the pinned Reader declares. The worker splits the answer back to
322
- members by that column.
323
- - `batch` refuses a POST, a `body_template`, a `platform` credential and
324
- `pages.max_unavailable_members` above 0. The preflight names each before anything is sent.
322
+ - `key_column` is a column the pinned Reader decodes to: one of its `columns[]`, or the
323
+ `record_key_column` of a `json.tabular` 1.3.0 pin reading `records_from: object_values`. The
324
+ worker splits the answer back to members by that column.
325
+ - `batch` refuses a POST, a `body_template` and a `platform` credential. The preflight names
326
+ each before anything is sent. `pages.max_unavailable_members` above 0 is for Studio to answer
327
+ at registration, which admits it when its engine counts a batch's unavailable members.
325
328
  - Member ids and saved answers do not change, so turning `batch` on keeps every paid answer.
326
329
  - `absent: "failed"` fails a member the answer does not name, so the next run asks again. The
327
330
  default, `empty`, records it with no rows.
@@ -239,7 +239,7 @@ at 0 there is no second attempt, so the first answer too large fails the run. Ra
239
239
 
240
240
  If the API takes a list of ids in one query parameter, add `request.batch` and send up to 100
241
241
  members in one call. It keeps every member id and saved answer. It refuses a POST, a
242
- `body_template`, a `platform` credential and a failure budget above 0.
242
+ `body_template` and a `platform` credential.
243
243
  [`batch`](making-a-table-incremental.md#batch-many-rows-in-one-request) has the grammar.
244
244
 
245
245
  A collection whose calls are paid for is sized from evidence, not from its ceiling. Run
@@ -178,15 +178,8 @@ def _batch(sources: list[Mapping[str, Any]]) -> dict[str, Any]:
178
178
  if isinstance(request.get("batch"), Mapping):
179
179
  used.append(name)
180
180
  continue
181
- pages = _mapping(collection.get("pages"))
182
- tolerated = pages.get("max_unavailable_members")
183
181
  platform = _mapping(source.get("connector")).get("credential_mode") == "platform"
184
- if (
185
- request.get("method") == "POST"
186
- or "body_template" in request
187
- or platform
188
- or (type(tolerated) is int and tolerated > 0)
189
- ):
182
+ if request.get("method") == "POST" or "body_template" in request or platform:
190
183
  refused.append(name)
191
184
  else:
192
185
  open_to.append(name)
@@ -205,8 +198,8 @@ def _batch(sources: list[Mapping[str, Any]]) -> dict[str, Any]:
205
198
  return _entry(
206
199
  BATCH,
207
200
  NOT_APPLICABLE,
208
- f"{', '.join(refused)} is a POST, a body_template, a platform credential or a "
209
- "failure budget above 0, and batch refuses each",
201
+ f"{', '.join(refused)} is a POST, a body_template or a platform credential, and "
202
+ "batch refuses each",
210
203
  sources=refused,
211
204
  )
212
205
  return _entry(BATCH, NOT_APPLICABLE, "no source sends one request per upstream row")
@@ -944,7 +944,12 @@ def _request_placeholder_sites(request: Mapping[str, Any], at: str) -> list[tupl
944
944
 
945
945
 
946
946
  def _reader_columns(connector: Any) -> set[str] | None:
947
- """The column names the connector's pinned Reader declares, or ``None`` when unreadable."""
947
+ """The column names the connector's pinned Reader decodes to, or ``None`` when unreadable.
948
+
949
+ Options that state ``records_from: object_values`` with a ``record_key_column`` decode that
950
+ key column too (``json.tabular`` 1.3.0), as Studio's ``reader_pin_columns`` reads them. Which
951
+ Reader versions may state those options is left to Studio.
952
+ """
948
953
 
949
954
  parameters = connector.get("parameters") if isinstance(connector, Mapping) else None
950
955
  for parameter in parameters if isinstance(parameters, list) else ():
@@ -956,11 +961,15 @@ def _reader_columns(connector: Any) -> set[str] | None:
956
961
  columns = options.get("columns") if isinstance(options, Mapping) else None
957
962
  if not isinstance(columns, list):
958
963
  return None
959
- return {
964
+ names = {
960
965
  entry["name"]
961
966
  for entry in columns
962
967
  if isinstance(entry, Mapping) and isinstance(entry.get("name"), str)
963
968
  }
969
+ key = options.get("record_key_column")
970
+ if options.get("records_from") == "object_values" and isinstance(key, str):
971
+ names.add(key)
972
+ return names
964
973
  return None
965
974
 
966
975
 
@@ -970,8 +979,11 @@ def _row_request_batch_coherence(sources: Any) -> list[Finding]:
970
979
  Studio's ``_row_request_batch_details``, restated. The batched parameter is declared with
971
980
  ``required: true``, and ``{parameter}`` is the whole of one ``static_query`` value and appears
972
981
  nowhere else. The request is a GET with no ``body_template``. The source uses no ``platform``
973
- credential, and ``pages.max_unavailable_members`` is 0 or absent. ``key_column`` is a column
974
- the pinned Reader declares.
982
+ credential. ``key_column`` is a column the pinned Reader decodes to.
983
+
984
+ ``pages.max_unavailable_members`` above 0 is NOT judged here. Studio admits it beside
985
+ ``batch`` when its pinned engine counts a batch's unavailable members, and this client cannot
986
+ see which engine is pinned, so registration answers that one.
975
987
  """
976
988
 
977
989
  if not isinstance(sources, list):
@@ -1005,17 +1017,6 @@ def _row_request_batch_coherence(sources: Any) -> list[Finding]:
1005
1017
  "request cannot use",
1006
1018
  )
1007
1019
  )
1008
- pages = source["collection"].get("pages")
1009
- tolerated = pages.get("max_unavailable_members") if isinstance(pages, Mapping) else None
1010
- if type(tolerated) is int and tolerated > 0:
1011
- findings.append(
1012
- Finding(
1013
- DOCUMENT_INCOHERENT,
1014
- f"{base}/pages/max_unavailable_members",
1015
- f"is {tolerated}, and a batched request records no unavailable members, so "
1016
- "this must be 0",
1017
- )
1018
- )
1019
1020
  name = batch.get("parameter")
1020
1021
  if isinstance(name, str):
1021
1022
  parameters = request.get("parameters")