Record the mainnet v0.17.0 upgrade, and catch the next one automatically - #184
Merged
nickemmons merged 5 commits intoAug 24, 2026
Merged
Conversation
Mainnet applied the v0.17.0 upgrade plan at block 10511421 (2026-08-18T19:37:21Z, confirmed via /cosmos/upgrade/v1beta1/applied_plan/v0.17.0), so both networks now run the same build and both serve emissions/v10. The drift PR updated abci_version for both, which is all that check compares; the rest of the manifest and the prose built on it stayed on the pre-upgrade story. Three things were wrong and user-visible: - mainnet's emissions_namespace still read emissions/v9, which the network stopped routing. Every documented mainnet LCD path answered 501 Not Implemented, including the two curl commands on /build/forge/topics, and the nightly topics job had been failing on /emissions/v9/next_topic_id since the upgrade -- scripts/generateTopics.js reads the namespace from this manifest. - mainnet's deployed_version still read v0.16.0, with versions.json to match. - /reference/networks and /consume/rpc-grpc described a two-tier network where mainnet returned single unlabeled values under emissions/v9. That premise no longer holds. The namespace had no single source: <Version of="chain-mainnet"/> covers the release tag, but nothing covered the namespace, so pages hand-typed it and nothing connected the prose to the fact. components/NetworkValue.tsx gives it one, mirroring components/Version.tsx, with a matching renderer in scripts/lib/docsPages.js so the generated corpus carries the value rather than the tag. public/raw/get-started/cli.md changes on its own: that page already read the mainnet version through the component.
The nightly drift check compares abci_version and nothing else, because that was the only value it could read automatically. That is a build identifier, so it caught the mainnet v0.17.0 upgrade as a hash change and left the consequences to a paragraph of follow-up advice in the PR body. The advice was not acted on, and for a day mainnet's recorded emissions namespace stayed at emissions/v9 while the network no longer routed it: every documented mainnet LCD path answered 501, and the nightly topics job failed on the same call. The namespace is queryable, so it is queried. checkNetworkDrift.js probes <lcd>/emissions/v<N>/params from the recorded namespace upward and takes the highest routed one as what the network serves -- two requests in the steady state. A namespace move is written to the manifest like abci_version is, and reported in the PR body as the release upgrade it is, naming the deployed_version each network still records rather than mentioning the field in passing. Probing the LCD makes it a fetch target, so hostsOf now derives the allowlist from lcd as well as rpc, under the same own-property and type discipline. The URL vetting is shared rather than copied: a second copy of the SSRF guard is the hazard this file already names for the address ranges. abciInfoUrl keeps its signature and its messages. checkVersionStrings.js gains the other half. The release tag had a component and a gate; the namespace had neither, which is why emissions/v9 survived in four pages and two runnable curl examples with every check green. A namespace in an endpoint URL is judged against the network that URL names -- so a testnet path is caught while testnet is a release ahead and mainnet is legitimately still on the older one -- and a namespace in prose is judged against the lowest any network serves. Both are derived from the manifest, so there is no list to maintain and nothing to forget at the next upgrade. A source-tree path in a pinned GitHub permalink (x/emissions/proto/emissions/v1/reputer.proto) is a protobuf package, not a REST namespace, and is left alone. 17 new cases in testNetworkDriftGuard.js cover the walk, the statuses (501 and 404 are answers, 5xx is not), and the namespace's path into a URL.
✅ Deploy Preview for alloradocs ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Contributor
There was a problem hiding this comment.
1 issue found across 15 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="scripts/checkNetworkDrift.js">
<violation number="1" location="scripts/checkNetworkDrift.js:625">
P3: When the LCD returns a redirect or non-retryable 4xx, this catch retries the deterministic failure three times despite the retry policy comment. Retry only transport failures and retryable 5xx responses so endpoint errors fail promptly.</violation>
</file>
Architecture diagram
sequenceDiagram
participant LiveNet as Allora Network (RPC/LCD)
participant DriftScript as scripts/checkNetworkDrift.js
participant Manifest as public/api/networks.json
participant BuildScript as scripts/checkVersionStrings.js
participant MDX as MDX Pages / Components
participant DocSite as Rendered Docs (HTML/LLM files)
Note over LiveNet, DocSite: Automated Drift Detection & Manifest Update
DriftScript->>Manifest: Read recorded "emissions_namespace" (e.g., v9)
DriftScript->>LiveNet: CHANGED: Fetch abci_info (RPC) for build hash
loop NEW: Namespace Probe Walk (vN to vN+3)
DriftScript->>LiveNet: NEW: GET /emissions/v[N]/params (LCD)
alt HTTP 200
LiveNet-->>DriftScript: Routed (Namespace Valid)
else HTTP 501 / 404
LiveNet-->>DriftScript: Not Implemented (Stale)
end
end
opt NEW: Drift Detected
DriftScript->>Manifest: NEW: Update "emissions_namespace" to highest routed version
DriftScript->>Manifest: CHANGED: Update "abci_version"
end
Note over LiveNet, DocSite: Build-time Validation & Rendering
BuildScript->>Manifest: Read current namespaces & calculate "floor" version
BuildScript->>MDX: Scan for hardcoded "emissions/vX" strings
alt Stale literal found (< Floor)
BuildScript->>BuildScript: Throw Error: Fails build
else Literal matches host in URL
BuildScript->>BuildScript: Validate against host-specific namespace
end
MDX->>Manifest: NEW: Lookup field via <NetworkValue /> component
Manifest-->>MDX: Return dynamic string (e.g., "emissions/v10")
MDX->>DocSite: Prerender static content with injected values
Note over MDX, DocSite: Result: llms-full.txt and docs show live network state automatically
Tip: instead of fixing issues one by one fix them all with cubic
Re-trigger cubic
All eight from the PR review, none declined: - A missing or malformed emissions_namespace now fails the manifest check loudly instead of silently disarming the stale-namespace gate: the matcher derived its floor from the field, so a broken manifest was the one state in which the gate matched nothing. checkManifestsAgree enforces the shape, next to the deployed_version agreement it already owns, and the failure headline now covers both problem classes. - A manifest host is never judged "foreign", whatever its domain: the host map test runs before the allora.network test, so an LCD moved off allora.network keeps its URLs judged against its network rather than skipped. - A version number past MAX_SAFE_INTEGER is rejected before the walk. version++ stops changing the value up there, and the manifest can arrive from the machine-owned drift branch, so the hang was reachable from outside this repository. - A 2xx alone no longer proves a namespace is routed: the params body every emissions version answers with is required, so a catch-all gateway that 200s every path becomes a probe error instead of a fabricated namespace written by --write. - A redirect is now a settled refusal the retry loop rethrows immediately, which is what the retry-policy comment already claimed; the comment and the code agree again. The abci probe keeps its existing behavior. - When nothing at or above the recorded namespace answers, the walk now looks below it before giving up, so a manifest recorded past the chain -- a hand-bump that overshot, or a rollback -- reports as ordinary drift and is repaired by --write rather than surfacing as an unreachable network. - Two wording fixes on /build/forge/topics: the generated-tables note no longer reads as if /api/networks.json were itself the namespace, and the verify section no longer asserts the segment "differs by network" now that both networks serve the same one; it says the segment is per-network and moves with upgrades, which is true in both states. testNetworkDriftGuard grows from 143 to 148 cases: body validation (non-JSON and JSON-without-params 200s refused), the deterministic redirect flag, the unsafe-number rejection with zero probes, the downward walk with its exact probe order, and the v1 floor of the downward range.
Contributor
There was a problem hiding this comment.
All reported issues were addressed across 6 files (changes from recent commits).
Tip: instead of fixing issues one by one fix them all with cubic
Re-trigger cubic
The second review pass found three defects in the previous commit's fixes and
two quality problems. All five are addressed.
The infinite loop was still reachable. The safe-integer guard checked only the
starting version, so a `from` that is itself safe could still have
`from + maxNamespaceLookahead` fall outside the range, where `version++` stops
advancing and the walk never ends. The ceiling is now checked too. This is
demonstrated rather than argued: with the ceiling check removed, a walk from
`emissions/v9007199254740991` runs past fifty probes without terminating.
The params body check accepted an array. `typeof [] === 'object'` and a
non-empty array is truthy, so `{"params":[]}` passed as a routed namespace --
exactly the catch-all-gateway response the check exists to reject.
`Array.isArray` now excludes it, and the case list in the test covers `[]`,
`[1,2]` and `null` alongside the shapes it already had.
The per-network host judgment ignored ports. `urlHostAt` captured `host:port`
with a regex while the manifest map is keyed on `hostname`, so an LCD on a
non-default port matched nothing in the map and its own endpoint URLs were
skipped as foreign -- the judgment silently off for precisely the URLs it
describes. Both sides now use `new URL().hostname`.
Manifest problems are reported by kind. A malformed `emissions_namespace` was
printed under guidance about keeping `deployed_version` in step across two
files, which sends the reader to the wrong field in the wrong file. Namespace
problems now carry their own explanation and their own fix, and point at
`checkNetworkDrift.js` for the namespace each network actually routes.
Tests go from 148 to 152, and the new ones were checked by removing the
behaviour they name: dropping the `Array.isArray` guard fails the body case,
and dropping the ceiling guard produces the non-terminating walk above. The
boundary cases cover `MAX_SAFE_INTEGER` and the two values below it whose
lookahead overflows, plus a safe start ten below it that must still walk and
stop.
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.
Mainnet applied the
v0.17.0upgrade plan at block10511421(2026-08-18T19:37:21Z), so both networks now run the same build and both serveemissions/v10. #183 updatedabci_versionfor both, which is everything the drift check compares. The rest of the manifest, and the prose built on it, stayed on the pre-upgrade story.This PR includes #183's commit, so it supersedes it.
What was wrong
emissions_namespacefor mainnet still reademissions/v9, which the network no longer routes:Consequences, all live:
501, including both mainnetcurlcommands on/build/forge/topics.2026-08-19T04:15Z.scripts/generateTopics.jsreads the namespace from this manifest:GET https://allora-api.mainnet.allora.network/emissions/v9/next_topic_id failed after 3 attempts: HTTP 501 Not Implemented/api/topics.jsonis therefore frozen at2026-07-31, and drifting. Testnet is at 41 active topics; the published table says 39.deployed_versionfor mainnet still readv0.16.0, withversions.jsonto match./reference/networksand/consume/rpc-grpcdescribed a two-tier network where mainnet served single unlabeled values underemissions/v9. That premise no longer holds.Why it survived every check
The release tag has a component and a gate behind it. The namespace had neither, so five pages hand-typed it and nothing connected the prose to the fact.
components/NetworkValue.tsxgives it a single source, mirroringcomponents/Version.tsx, with a matching renderer inscripts/lib/docsPages.jsso the generated corpus carries the value rather than the tag.Stopping the recurrence
scripts/checkNetworkDrift.jsnow probes<lcd>/emissions/v<N>/paramsupward from the recorded namespace and takes the highest routed one as what the network serves. Two requests in the steady state. A namespace move is written to the manifest likeabci_versionis, and reported in the PR body as the release upgrade it is, naming thedeployed_versioneach network still records instead of mentioning the field in passing.Probing the LCD makes it a fetch target, so
hostsOfderives the allowlist fromlcdas well asrpc, under the same own-property and type discipline. The URL vetting is now shared rather than copied.abciInfoUrlkeeps its signature and its messages.scripts/checkVersionStrings.jscovers the other half. A namespace inside an endpoint URL is judged against the network that URL names, so a testnet path is caught while testnet is a release ahead and mainnet is legitimately still on the older one. A namespace in prose is judged against the lowest any network serves. Both are derived from the manifest, so there is no list to maintain.A source-tree path in a pinned permalink (
x/emissions/proto/emissions/v1/reputer.proto) is a protobuf package, not a REST namespace, and is left alone.One decision for review
deployed_versionis set tov0.17.0, notv0.17.1.Both networks report build
HEAD-b6104eda6b2b009ea0714d2f724d53f4f0365fc0, which is #982, thev0.17.1hotfix candidate. Butv0.17.1is still a draft release and its plan never ran:If you would rather name the running binary, say so and I will change
networks.jsonandversions.jsontogether.Verification
npm run buildpasses, 61/61 pages prerendered. Rendered/reference/networksshowsemissions/v10for both networks and noemissions/v9.yarn testdrift: 143/143 and 37/37. 17 new cases cover the namespace walk, the statuses (501and404are answers,5xxis not), and the namespace's path into a URL.mainnet: recorded emissions/v9 -> serves emissions/v10and emits a body namingmainnet still records deployed_version: v0.16.0.Merging the first commit alone unbreaks the nightly topics job.