feat(manifest): add upstream_docs to watch vendor register sources - #48
feat(manifest): add upstream_docs to watch vendor register sources#48HuggeK wants to merge 2 commits into
Conversation
A driver decodes a device by following the vendor's own reference material
- a register map, a parameter changelog PDF. When that material changes
upstream, the driver can silently fall behind. upstream_docs records those
documents at a semi-persistent URL so a watcher can poll them and flag the
driver for review, instead of a human noticing months later.
- new optional manifest field: list of {url, title?, kind?} entries
- parse_upstream_docs() in manifest_parser.py, mirroring parse_tested_devices
- validate_manifest.py enforces an http(s) url and a known kind
- nibe_local + myuplink both declare NIBE's myUplink register changelog
- nibe_local manifest author corrected to its real provenance
- descriptive metadata only: never copied into index.yaml
- documented in spec/manifest-v2.md (V2.3); tests in test_upstream_docs.py
Co-authored-by: HuggeK <48095810+HuggeK@users.noreply.github.com>
Signed-off-by: Hugo Karlsson <48095810+HuggeK@users.noreply.github.com>
Adds the automation half of upstream_docs and a stability signal. Watcher: - tools/check_upstream_docs.py fetches each watched URL, hashes it, and diffs against a committed baseline (upstream-docs-state.json). - .github/workflows/watch-upstream-docs.yml runs weekly, opens a tracking issue when a document changes (review the registers) or goes missing (link rotted), and commits the updated baseline. - Notifies once per event: a change updates the baseline so it cannot re-fire; an outage alerts only on crossing a 3-run failure threshold; the workflow skips a title that already has an open issue. - Shared URLs are fetched once; detection is a raw-byte hash (a prompt to look, not proof registers moved) - the issue says so. url_stability field: - new optional upstream_docs field: committed | stable | volatile | unknown - records whether the manufacturer keeps the URL put; weights how loudly a broken link is reported. - both NIBE entries set to 'stable'; validated in validate_manifest.py. Baseline seeded for the two NIBE entries. Pure diff + rendering logic is covered by tests/test_upstream_docs_watch.py; make watch-upstream-docs runs a local dry-run. Co-authored-by: HuggeK <48095810+HuggeK@users.noreply.github.com> Signed-off-by: Hugo Karlsson <48095810+HuggeK@users.noreply.github.com>
|
Automated maintenance pass: not merging this one, flagging for a maintainer. The change itself reads well-scoped — descriptive metadata only, Two things stop it from going further autonomously:
Secondary note: the companion RFC (#47) still has open checklist items ("agree the surfacing mechanism," decisions to make "before the watcher is wired up") — worth confirming those are settled the way this PR settled them before merging. Flagging for a maintainer to approve the workflow run (or review the Action file directly) and confirm the RFC is considered resolved. Generated by Claude Code |
|
It is now done. |
What
Two halves of one feature for keeping drivers honest against the vendor
documents they decode a device by:
upstream_docs— an optional manifest field recording the vendorreference documents (register maps, parameter changelogs) a driver was built
against, at a semi-persistent URL, plus how durable that URL is.
watch-upstream-docs— a scheduled watcher that fetches each URL, noticeswhen a document changes or disappears, and opens a tracking issue so a
maintainer reviews whether the driver's registers are affected.
Populated for the two NIBE drivers (both watching NIBE's myUplink register
changelog), and corrects the
nibe_localmanifest author to its real provenance.Why
A driver decodes a device by following the vendor's own reference material. When
that material changes upstream — a register renumbered, a parameter added — the
driver silently falls behind, and it's usually a human noticing a wrong value on
a real site months later. This makes that visible: record the document, watch it,
and raise a reviewable issue the moment it moves.
Implements the pilot proposed in #47.
The field
upstream_docsis an optional list, modelled ontested_devices:urlhttp(s)URL to watchtitlekindchangelog,register_map,manual,api_docs,firmware_notes,otherurl_stabilitycommitted,stable,volatile,unknown(default)url_stabilityrecords whether the manufacturer keeps the URL put —committed(vendor promises it's permanent),
stable(stable in practice),volatile(rotates),
unknown. The watcher uses it to weigh a broken link: astableonegoing missing is a real signal the document moved; a
volatileone breaking canbe routine.
The watcher
tools/check_upstream_docs.py(stdlib only): fetches each distinct URLonce, SHA-256s it, and diffs against a committed baseline
(
upstream-docs-state.json, seeded here for the two NIBE entries)..github/workflows/watch-upstream-docs.yml: weekly (+ manual). On a changeit opens an issue labelled
upstream-doc-changedlisting old/new hash and areview checklist; on a document that has been unreachable for 3 runs it opens
one labelled
upstream-doc-unreachable. Then it commits the updated baseline.Notify-once, and the raw-hash caveat
so the next run sees the new hash as current and does not re-fire. The issue
title carries the new hash's short prefix, and the workflow skips a title that
already has an open issue — so even a failed baseline-commit can't double-post.
that crosses the 3-run failure threshold, not every run after; recovery
resets the count.
changing (rebuild timestamps). So a flagged change is a prompt to look, not
proof the registers moved — the issue says exactly that.
as a follow-up in RFC: watch manifest upstream_docs for changes and flag affected drivers #47; v1 surfaces the change and links the driver source.
Why it's safe to add and what it does not touch
generate_index.pycopies a fixed field set, soupstream_docsnever reachesindex.yamland never affects how a driverinstalls or runs.
devices.yamlandsupport-status.*are unaffected —regenerated and confirmed byte-identical.
sha256/size_bytesareunchanged and no driver version moves. Both drivers stay byte-identical to
their
baselines/ftwsources.validate_manifest.pyrequires anhttp(s)urland knownkind/url_stabilityvalues, and rejects unknown entry fields.contents: write/issues: writeare scoped to that workflow.Changes
tools/manifest_parser.py—parse_upstream_docs()tools/validate_manifest.py— validates url / kind / url_stability / unknown fieldstools/check_upstream_docs.py— the watcher (fetch, diff, render issues).github/workflows/watch-upstream-docs.yml— weekly jobupstream-docs-state.json— seeded baselinespec/manifest-v2.md— documents the field (V2.3)manifests/nibe_local.yaml,manifests/myuplink.yaml— entries;nibe_localauthor correctedMakefile—make watch-upstream-docs(local dry-run)tests/test_upstream_docs.py,tests/test_upstream_docs_watch.pyCHANGELOG.md—[Unreleased]Testing
python tools/validate_manifest.py→ 80 manifests, 0 errorspython tools/sync_manifests.py --check→ no driftgenerate_index.py/generate_devices.py/generate_support_status.py→ no content changepytest tests/test_upstream_docs.py tests/test_upstream_docs_watch.py→ 23 passedpython tools/check_upstream_docs.py --dry-run→ fetches both NIBE URLs live, 0 failuresPR evidence
nibe_local) and MyUplink heat pumps(
myuplink); watched document is NIBE's public myUplink register changelog(
nibe-n.pdf).registers, emits, control paths or driver bytes are modified.
branch protection blocks the Actions bot, either allow
github-actions[bot]for
upstream-docs-state.jsonor switch that step to open a PR — issues arestill filed correctly either way, and the open-issue dedup prevents duplicates.
RFC / discussion: #47