docs/json-contracts.md:89 and skills/open-data-hub-cli/SKILL.md:99 both say "an empty end means ongoing". The key is not empty, it is absent:
$ odh traffic today --source content --json
of 101 events: key absent 32, key present but null 0
end carries omitempty, so an open-ended announcement has no end at all. A consumer following the documented contract with event["end"] gets a KeyError on exactly the records the sentence is about — the open ones. An agent hit this during a field test of v0.5.0.
Same shape as the outlier key issue fixed in pitstop v1.1.0: a conditionally-present key documented as conditionally-empty.
Two ways out
- Emit
"end": null for content events, matching the docs. Changes the wire shape for a field that is currently absent, so it is additive for anyone using .get() and fixes anyone using [].
- Keep
omitempty and correct both docs to say the key is absent when open-ended.
(1) is better here: end is a documented stable field, and absent-means-ongoing is a subtler contract than null-means-ongoing. But (2) is honest and cheaper.
Done when
- The docs and the emitted JSON agree.
- A test asserts whichever shape is chosen, so they cannot drift again.
docs/json-contracts.md:89andskills/open-data-hub-cli/SKILL.md:99both say "an emptyendmeans ongoing". The key is not empty, it is absent:endcarriesomitempty, so an open-ended announcement has noendat all. A consumer following the documented contract withevent["end"]gets a KeyError on exactly the records the sentence is about — the open ones. An agent hit this during a field test of v0.5.0.Same shape as the
outlierkey issue fixed in pitstop v1.1.0: a conditionally-present key documented as conditionally-empty.Two ways out
"end": nullfor content events, matching the docs. Changes the wire shape for a field that is currently absent, so it is additive for anyone using.get()and fixes anyone using[].omitemptyand correct both docs to say the key is absent when open-ended.(1) is better here:
endis a documented stable field, and absent-means-ongoing is a subtler contract than null-means-ongoing. But (2) is honest and cheaper.Done when