docs: make every example compile against the SDK the docs describe - #103
Merged
Merged
Conversation
…th setters `DataWrapper.getItems()` returns `Collection`, which has no `get(int)`, so the 27 `.getItems().get(0)` reads never compiled; the site's existing idiom is `.getItems().iterator().next()`. `Timeseries` has no static `of(...)` factory, and `NodeModel`'s setters are Lombok-generated and return `void`, so neither the factory nor the fluent chain that followed it existed. Build the series with plain setter statements. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: jgjesdal <jostein@intellistream.ai>
`ResourceForm` never existed — resources are created from `Resource` (a `NodeModel`), which is what `resources().create` takes. `ResourceSearch` was replaced by `SearchBody<F>`; its own javadoc names it as one of the four classes it folded together. `resources().create` answers with `GraphDataWrapper<NodeModel, EdgeProxy>`. `ResourceNetwork.nodes()` is a `Set<NodeModel>`, so the 16 traversals that mapped `Resource::getExternalId` over it named a receiver the stream never holds. `timeseries().list(int, long)` takes the data set's numeric id; there is no overload for an external id. `DataSetFilter` has no `externalIdPrefix`, so the retail page now looks its data set up with `datasets().byIds`, which is what its Python and Rust tabs beside it already did. The tutorial's step path used a `Metric` record that only appeared in the complete program at the end of the page, so a reader following the steps could not compile step 2. It is introduced where the steps first need it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: jgjesdal <jostein@intellistream.ai>
javac resolves neither an overload nor a target type through an argument it could not resolve, so an unresolved reader-supplied name is reported twice: once as the name, and again as a type error on the enclosing call — a different line, which is why the existing per-line suppression never caught it. Five pages were failing on calls that compile: `timeseries().ingest(Map.of(id, readings))` with `readings` left to the reader, and the tutorial's `host`. The stubbed pass already gives every such name a type, so it can now retract as well as add: a *typing* error that disappears once the reader's names are typed was theirs, not the page's. Lookups are untouched — a missing method or type still fails however the reader's values are typed — and `invalid method reference` stays hard, being a claim about the SDK's shape rather than about what flows into a call. The new `overload_with_reader_argument` control fails without this change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: jgjesdal <jostein@intellistream.ai>
…id is a method `Event::new(external_id, r#type, event_time)` takes three arguments, and the struct's `r#type` and `event_time` are plain values rather than `Option`s — the field's own doc comment says why: the server rejects an event with no type, so there is no useful default. 27 pages passed the external id alone and then assigned `Some(...)` to both. `docs/reference/events.md` already had it right and is the shape they now follow. `Node::external_id(&self) -> &str` is a method, not a field, and the `&str` it returns needs no `.as_str()`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: jgjesdal <jostein@intellistream.ai>
Rust pages carry their own imports — nothing is supplied for them — and the tutorial's step blocks showed only the ones for building a client, so a reader following the steps had no `IdAndExtId`, `DataWrapper`, `TimeSeries`, `HashMap`, `System` or `Utc`. The complete programs at the end of the page already listed them; the steps now name what each one uses, by the same paths. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: jgjesdal <jostein@intellistream.ai>
…r mutably `FileUpload::new_with_destination_path` answers `io::Result<Self>` — it reads the file's metadata and refuses a directory — so the four pages that build one need `?` before they can set a field on it. `DataWrapper::get_items` lends the vector (`&Vec<T>`); taking an item out of it needs `get_items_mut`. All 24 `get_items().remove(0)` reads were wrong, though only 10 were visible: rustc stops before the borrow checker on any unit that still has an unresolved name, so the rest were hidden behind other errors on their own pages. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: jgjesdal <jostein@intellistream.ai>
…types `Datapoint.value` is `Option<f64>` and `Datapoint.timestamp` a `DateTime<Utc>`, so five pages parsed strings that were never strings. `TimeSeries.value_type` is `Option<String>`, which `"numeric".into()` cannot reach on its own. `BasicEventFilter` is gone: the criteria are `EventFilter` and the request body that carries `limit`, `sort` and `cursor` is `EventFilterForm`. `docs/reference/events.md` already described it that way. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: jgjesdal <jostein@intellistream.ai>
The compile tier cannot infer through a function the page leaves to the reader: every constraint on `inflow` is another such call, so rustc has nowhere to infer from and asks for an annotation. Naming the type is what these pages owed the reader anyway — it is the only statement of what their `latest`, `sum_over`, `tolerance` and `trigger_level` are expected to return. An annotation does not survive being destructured — rustc does not carry it through `if let Some(x)` when the scrutinee came from a name it could not resolve — so the tailings page takes the level as a `&str` and tests it for emptiness instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: jgjesdal <jostein@intellistream.ai>
The Python client has no `BasicEventFilter`, and `filter()` is keyword-only: either `filter=` with an `EventFilter` or the individual criteria, never both, and paging is always an argument of the call rather than a field of the filter. Seven pages passed a positional `EventFilter` wrapping a `BasicEventFilter`, which is the Rust shape, not this one. `docs/reference/events.md` already described the Python call correctly. This clears the api-surface job: 222 checks, no failures. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: jgjesdal <jostein@intellistream.ai>
…atch the pages `docs/reference/labels.md`, `policies.md` and `tenant.md` had runnable Java and no plan, so coverage refused them. Each is a reference page whose blocks are separate examples — one of them deleting what an earlier one creates — so each gets `independent = true`, which is also what stops the two "variable already defined" compile errors. Seven plans' block counts had fallen behind their pages. `reference__timeseries` shows why the pin exists: its `exclude = [13]` was written for the signature listing, which is now block 16, so for some time it skipped the latest-datapoint example and compiled the prose. With the selection corrected, the example turns out to name a `DatapointDTO` that does not exist — `latest` answers `DataWrapper<DataCollection<DatapointString>>`. `reference__resources` also picks up the blocks #101 and #102 added for the `/functions` endpoints. They are appended, so the plan's `inject before = 8` still lands on "Traverse the graph", which is the block it is there for. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: jgjesdal <jostein@intellistream.ai>
JosteinGj
force-pushed
the
fix/docs-match-sdk-api
branch
from
September 28, 2026 11:33
1db5447 to
755705d
Compare
This was referenced Sep 28, 2026
…ng its type
rustc reports "type annotations needed" at the *use* of a value destructured out
of a call it could not resolve, and no annotation the page could write reaches
it: `if let Some(level) = trigger_level(..)` cannot carry one, and the value's
only other constraint is another function the page leaves to the reader. There is
no Rust counterpart of the Java stubbed pass to settle it either — a stub would
need a type of its own, from the same missing information.
So E0282 is dropped on any unit that leaves a name to the reader. It can never be
how a renamed or removed SDK symbol shows up; that is E0425, E0433, E0412 or
E0599, none of which this touches. What it does cost is naming: a page whose own
code is genuinely ambiguous stops being caught, if it also leaves a name to the
reader.
That trade is worth it because the alternative was contorting the prose. The
tailings page had grown `unwrap_or("")` and an `is_empty()` test in place of a
plain `if let Some(..)`, purely to satisfy this check. It reads as a reader would
write it again. The `reader_supplied_destructured` control fails without the
change.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: jgjesdal <jostein@intellistream.ai>
…on clients The sync client's `by_external_ids` was renamed to `by_external_id` (dataplatform-rust-sdk 96fe3ea), so it no longer differs from the async client, the blocking client or Rust. The page said the two spellings differed; the coverage table said so too. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: jgjesdal <jostein@intellistream.ai>
`DataWrapper.getItems()` answers a `List` (datahub-platform#141), so the first of one result is `getItems().get(0)` — which is what these pages said before they were rewritten to `getItems().iterator().next()` to compile against the `Collection` it used to be. All 35 reads go back, including the eight that were written that way from the start, so the site reads one way. `reference/client.md` now says the results are an ordered list, since that is what makes the index meaningful. `timeseries().list(int, long)` takes a numeric data set id and there is no external-id overload, so the example resolves the id through `datasets().byIds` rather than naming a bare `43L`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: jgjesdal <jostein@intellistream.ai>
`DataWrapper::get_items` lends the vector, so reading the first of one result in a single expression meant `get_items_mut().remove(0)` — a mutable borrow and a destructive take, in order to read. Binding the response first and indexing it says what the code does, and matches the Python and Java tabs beside it, which both index. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: jgjesdal <jostein@intellistream.ai>
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 three
Doc tutorialsjobs have been failing on every run in recent history. Theharness was right: the examples had drifted from the SDK across roughly a hundred
page/language pairs — 245 distinct compile errors from nine root causes — plus one
real harness bug and one stale plan selection that was hiding a defect.
Every claim was checked against source —
datahub-java-sdk/datahub-api-modelanddataplatform-rust-sdkatmain— rather than inferred from the error text. The localrun was first made to reproduce CI error-for-error (100 failed, 58 passed) so the
before/after means something.
What was wrong
Java.
DataWrapper.getItems()returnedCollection, so 27.get(0)reads nevercompiled. That envelope is now a
List(datahub-platform#141, merged), so those reads stand aswritten, and the eight pages that had worked around it with
.iterator().next()were brought intoline — 35 sites reading
getItems().get(0), the way the Python and Rust tabs index.Timeserieshas no staticof()andNodeModel's setters are Lombok-generatedand return
void, so neither the factory nor the 19 fluent chains after it existed.ResourceFormandResourceSearchare gone — resources are created fromResource, andSearchBody<F>'s own javadoc namesResourceSearchas one of the four classes it foldedtogether.
ResourceNetwork.nodes()is aSet<NodeModel>, so 16 traversals mappedResource::getExternalIdover a stream that never holds one.Rust.
Event::newtakes all three required fields, and the struct'sr#typeandevent_timeare plain values rather thanOptions — the field's doc comment says why —so 27 pages passed the external id alone and then assigned
Some(...)to both.Node::external_idis a method.FileUpload::new_with_destination_pathanswersio::Result.Datapoint.valueisOption<f64>and.timestampaDateTime<Utc>, sofive pages parsed strings that were never strings.
BasicEventFilteris nowEventFilter(the criteria) and
EventFilterForm(the request body). The tutorial's step blocks showednone of the
uselines they needed, so a reader following the steps could not compile them.Python.
events.filteris keyword-only, and there is noBasicEventFilter; seven pagesused the Rust shape.
docs/reference/events.mdalready described the Python call correctly.Two that are not doc fixes
A harness bug (
test(compile): a reader's value cannot fail the call it is passed to).javac resolves neither an overload nor a target type through an argument it could not
resolve, so an unresolved reader-supplied name is reported twice: as the name, and again as
a type error on the enclosing call — a different line, which is why the existing per-line
suppression never caught it. Five pages were failing on calls that compile. The stubbed pass
now retracts as well as adds, and narrowly: typing errors only, only in units that have
placeholders, only where the stubbed pass is clean at that line. Lookups are untouched, so a
missing method or type still fails however the reader's values are typed. The new
overload_with_reader_argumentcontrol fails without the change.A stale plan selection was hiding a bug.
reference__timeseries'sexclude = [13]waswritten for a listing of
IngestResult's signatures, which is now block 16 — so it had beenskipping the latest-datapoint example and compiling the prose instead. With the selection
corrected, that example turns out to name a
DatapointDTOthat does not exist:latestanswers
DataWrapper<DataCollection<DatapointString>>.docs/reference/labels.md,policies.mdandtenant.mdhad runnable Java and no plan.Each is a reference page of separate examples, one of which deletes what an earlier one
creates, so each gets
independent = true— which also clears their two "variable alreadydefined" compile errors.
Also in this branch
get_items()lends the vector, so taking the first result in oneexpression meant
get_items_mut().remove(0)— a mutable borrow and a destructive take, in orderto read. The 24 sites now bind the response and index it.
units.by_external_ids→by_external_idon three pages, its prose and the coverage table:the sync Python client was renamed (dataplatform-rust-sdk 96fe3ea) and no longer differs from the
async and Rust clients.
timeseries().list(100, 43L)resolves the data set id throughdatasets().byIdsrather thannaming a bare number.
if let Some(..). It had grown anunwrap_or("")and anis_empty()test purely to satisfy the compile tier; the tier now drops E0282 on a page thatleaves a function to the reader, which is information rustc cannot have. A control fails without
that change.
Verified
Run the way CI runs it, all zero-fail: the structure tier under system Python with no SDK
(440 passed),
test_compile.pyandtest_api_surface.pyagainst SDKmainand theplatform's default branch, and
test_harness.py. Whole suite: 741 passed, 78 skipped — theskips are the live tutorials, which need a stack.
Left alone deliberately
value_type = "numeric"on ~6 pages. The type error is fixed; whether the server accepts"numeric"rather than thefloat32/BIGINTused elsewhere is a question for the live tier.timeseries().list(100, 43L)— the Java client has no external-id overload, so the examplepasses a numeric id with a comment saying so. Whether the page should show resolving the id
first is a separate call.
tutorialsjob now reaches its gate for the first time in this history and skips:no
DOCTEST_BASE_URLis configured, so there is no stack to run against. Nothing here hasbeen proven against a live backend, and the two items above are the candidates for red when
one is configured. That is a different verdict from this one.
🤖 Generated with Claude Code