Skip to content

release: promote testnet-canary to main for 10.0.11 - #1999

Merged
Jurij89 merged 8 commits into
mainfrom
release/10.0.11
Jul 30, 2026
Merged

release: promote testnet-canary to main for 10.0.11#1999
Jurij89 merged 8 commits into
mainfrom
release/10.0.11

Conversation

@Jurij89

@Jurij89 Jurij89 commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Promotes the testnet-canary payload to main as the 10.0.11 release candidate. Frozen at canary tip e568ebe45.

8 commits · 39 files · +5,069 / −676. main is fully contained in testnet-canary (merge-base == main tip, 0 commits ahead), so this is a clean promotion with no conflict resolution.

No Solidity, ABI, or deployment-registry changes — no on-chain deployment required.
No dashboard schema changeSCHEMA_VERSION stays at 31, so no migration and no rollback question.

Contents

Three substantive PRs, all merged to testnet-canary:

The remaining commits are the #1986/#1993 syncs from main, a history-rejoin merge, and the review fixup c50b39235.

Why #1994 belongs here

#1991 landed the scoped-query starvation fix; #1994 is its review follow-up and touches cli, node-ui, query and storage (+1,077 / −579), including a net −175 rework of packages/query/src/dkg-query-engine.ts and a new packages/cli/src/daemon/api-query-priority.ts.

The two load-bearing invariants were already correct in #1991 as merged, and remain so:

  • API reads default to the background lane — packages/cli/src/daemon/routes/query.ts:358 returns 'background' unless a caller explicitly requests 'normal'.
  • Shared graph-discovery flights do not inherit a caller's abort signal — sharedDiscoveryStoreOptions() (packages/query/src/dkg-query-engine.ts:86-95) passes only priority and source, with raceAgainstCallerAbort() letting an individual caller bail without killing the shared flight.

#1994 adds the robustness layer on top: one QueryStoreReadContext built at query entry so option threading cannot drift, cancelled operations preserved in the dashboard health rate (success / (success + error)), class-based rather than string-matched StoreSchedulerBusyError mapping, and shared SPARQL scanner primitives.

CI status

ci.yml now includes testnet-canary in both the push and pull_request branch filters (#1992, canary parity), closing the gap that left 10.0.10's 497 commits unseen by the vitest lane until the promotion PR. This payload is therefore validated on canary before promotion, and this PR is a confirmation run.

One item for reviewer awareness: #1994 was merged with two red checks — CI gate and Kosava: adapters + utilities + demo. The underlying failure is H-AC-31: re-run after replacement does not take a second backup (first-wins capture) in packages/adapter-hermes, which timed out at 5,029ms against a 5,000ms limit. #1994 does not touch packages/adapter-hermes at all (only cli, node-ui, query, storage), so this reads as a flaky timeout rather than a regression. The push-triggered run on the merged tip e568ebe45 should confirm; do not merge this PR until that run concludes green.

Reviewer attention

Test Plan

Follow-up (separate PR, before tagging)

Version bump to 10.0.11 across all 21 manifests plus the ## [10.0.11] CHANGELOG section. [Unreleased] is currently empty.

Not in this release: #1985 (node:sqlite runtime-floor enforcement) and #1971 (curated publish authz, which carries a _VERSION bump and needs a KAL redeploy) both remain open and correctly excluded from a patch release.

🤖 Generated with Claude Code

Jurij89 and others added 8 commits July 28, 2026 18:23
* Fix release CI test expectations

* fix(epcis): fail fast on invalid payloads

* Merge pull request #1984 from OriginTrail/release/10.0.10-bump

chore(release): bump version set to 10.0.10

---------

Co-authored-by: Viktor Pelle <vikpelle@gmail.com>
The 10.0.10 sync (#1986) was squash-merged, which flattened it into a single
commit parented on 8334c0a — a pre-release commit on main. The content came
across correctly (main and testnet-canary trees were already byte-identical),
but git no longer saw main's release commits as ancestors of testnet-canary, so
`git rev-list testnet-canary..main` reported four phantom commits:

  f61f335  Merge pull request #1984 (release/10.0.10-bump)
  f516586  Merge pull request #1983 (release/10.0.10)
  e89f8f6  fix(epcis): fail fast on invalid payloads
  0112e78  Fix release CI test expectations

This is a real merge commit, so the histories join and those stop being
reported as missing. It changes no files.

Squash is right for feature PRs; for a branch-sync PR it defeats the purpose,
because the ancestry is the payload. Future main -> testnet-canary syncs should
use 'Create a merge commit'.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
fix: prevent scoped API queries from starving store work
chore: sync main into testnet-canary after CI parity (#1992)
fix(integrations): conform the CLI to the published registry schema
…lowup

fix: address query scheduler follow-up review feedback
Comment thread packages/query/src/dkg-query-engine.ts Outdated
const promise = this.discoverScopedContentGraphAllowList(
contextGraphId,
subGraphName,
sharedOptions,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Bug: Shared graph discovery drops API cancellation and can leave orphan store work

What's wrong
The route promises that disconnected API callers cancel queued/in-flight store work, but this shared discovery path strips the signal before issuing the actual store reads. That means the expensive partition discovery can keep consuming scheduler capacity after the HTTP caller is gone.

Example
A client sends /api/query with includeContextGraphPartitions: true and a GRAPH ?g query, then disconnects while the allow-list discovery is running. The caller gets cancelled through raceAgainstCallerAbort, but the underlying discovery store reads continue because they were started without the caller signal.

Suggested direction
Use a shared-flight owner that tracks active subscribers and aborts the store discovery when the last subscriber cancels, or avoid sharing flights for caller-cancellable API reads.

For Agents
Look in packages/query/src/dkg-query-engine.ts around sharedDiscoveryStoreOptions and resolveScopedContentGraphAllowList. Preserve shared-flight behavior for concurrent callers, but ensure a single disconnected caller does not leave discovery work running. Add a test where the only subscriber aborts and the discovery store query observes the abort, plus a second test proving one aborted subscriber does not cancel another active subscriber.

Comment thread packages/node-ui/src/db.ts Outdated
error_message: string;
}): void {
this.stmt('cancelOp', `
UPDATE operations SET status = 'cancelled', duration_ms = @duration_ms,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Issue: Cancelled operations skew dashboard success-rate metrics

What's wrong
The PR adds a non-error terminal status for caller disconnects, but the existing metrics treat every row in operations as part of the denominator. Cancellations therefore lower success rates without increasing error counts, producing inconsistent operational health data.

Example
With one successful operation and one disconnected /api/query, getOperationStats() reports totalCount = 2, successCount = 1, errorCount = 0, and successRate = 0.5. The cancellation is not an error, but it still depresses the success rate as if it were a failed/incomplete operation.

Suggested direction
Update stats queries to either exclude terminal cancellations from success-rate denominators or expose them as a separate count and compute rates over completed success/error outcomes only.

Confidence note
This assumes the dashboard success-rate metrics are meant to exclude caller cancellations from failure-like outcomes, which matches the new tracker test wording but should be confirmed with product expectations.

For Agents
Look in packages/node-ui/src/db.ts at the new cancelled status and the operation stats queries. Decide whether cancelled operations should be excluded from rate denominators or surfaced as cancelledCount; add a DB-level test for one success plus one cancelled operation.

return Array.isArray(v) && v.every((x) => typeof x === 'string');
}

// INVARIANT: this must never be STRICTER than the registry's published JSON

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Issue: Do not keep hand-encoding the registry schema

What's wrong
This change fixes several schema drift cases by adding more manual schema logic. That makes the immediate behavior better, but structurally it doubles down on the design that caused the drift: the CLI, fixture copy, and registry schema now all describe the same contract independently.

Example
A future registry addition such as a new service runtime would need coordinated edits in the published schema, the vendored fixture, the hand-written switch, and the tests. Missing any one of those brings back the exact drift this PR is trying to prevent.

Suggested direction
Use the registry schema, or generate typed validators from it, instead of expanding a parallel hand-written validator plus fixture copy. The code-judo move is to delete the drift-prone mirror rather than add more tests around it.

Confidence note
This assumes the CLI can either consume the registry schema at runtime or generate a parser from it at build time; if runtime dependency size is a constraint, generation still addresses the same structure problem.

For Agents
Look at packages/cli/src/integrations/schema.ts and the new registry fixtures. Preserve the current lenient-read/installability split, but make the published schema or a generated projection the canonical source of readable shapes; keep installability checks such as resolveNpmGlobalService separate. Prove with the existing registry contract cases.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Issue: The registry parser still duplicates the schema it says must be canonical

What's wrong
The PR documents previous schema drift and then adds more hand-maintained schema knowledge to the same validator. That leaves the structural problem intact: every schema evolution still requires synchronized edits across interfaces, the type guard, install dispatch, installed detection, and fixtures.

Example
If the registry adds a new valid install kind, this parser still needs a TypeScript union update, isValidInstallSpec branch, command handling, and tests before the CLI can even read the entry. That is exactly the drift this PR is trying to prevent.

Suggested direction
Use the published schema, or a generated validator/model, as the canonical readability boundary instead of expanding the manual switch. If leniency for future fields is required, model that explicitly with an UnknownInstallSpec rather than encoding compatibility as comments around a closed union.

For Agents
Rework packages/cli/src/integrations/schema.ts so the registry schema, or a generated/derived validator from it, owns readability. Represent unknown-but-readable install specs explicitly, then let installer/dispatcher code decide whether a known kind is automatable. Keep behavior for existing known kinds the same.

* that as "not installed": it would tell a user an integration is missing when
* the truth is that their config could not be read.
*/
export function readRegisteredServerKeys(target: ClientTarget): ServerKeyProbe {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Issue: Extract MCP config parsing instead of expanding mcp-setup.ts

What's wrong
The PR turns a very large command/setup module into a shared utility boundary by exporting internal config parsing concepts. That makes the module less cohesive and gives unrelated integration code a dependency on a file that also owns interactive setup, serialization, and command behavior.

Example
detectInstalled now imports detectClients, readRegisteredServerKeys, and config-shape types from ../mcp-setup.js; a later change to setup flow or client target representation can now ripple into integration detection even though detection only needs a read-only config parser.

Suggested direction
Move shared MCP client config discovery/parsing out of the setup command file. The setup command should orchestrate writes; integration detection should consume a small read-only parser API owned by a neutral module.

For Agents
Extract the MCP client target model plus config read/parse helpers into a focused module such as mcp-client-config.ts. Have both mcp-setup.ts and integrations/detect-installed.ts import that module. Preserve existing setup behavior and the new registered-server-key tests.

}

/** Map retryable, pre-dispatch read shedding without changing write routes. */
export function respondIfApiQueryStoreBusy(res: ServerResponse, err: unknown): boolean {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Issue: Use a typed scheduler-busy boundary instead of a local magic string

What's wrong
The route now owns a copy of a storage-layer error code and reaches into an unknown object shape to decide HTTP semantics. That is a brittle boundary: the producer and consumer of the scheduler-busy contract can drift without type pressure.

Example
If the storage scheduler later renames the code or adds a typed retry hint, this route will still compile while silently mapping by stale string/object shape.

Suggested direction
Move the scheduler-busy detection contract to the storage package, or import a typed predicate/error constant from there. Keep the route responsible for HTTP serialization, not for reconstructing storage error shape by hand.

For Agents
Look at packages/storage/src/store-priority-scheduler.ts and packages/cli/src/daemon/routes/query.ts. Export a stable constant or predicate such as isStoreSchedulerBusyError, and use that in the route response mapper while preserving the 503/Retry-After response.

return -1;
}

function skipSparqlIriRef(sparql: string, start: number): number | null {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Issue: Avoid introducing a second SPARQL scanner

What's wrong
The extraction improves locality for the new VALUES logic, but it duplicates low-level parser rules that already exist in the query engine. Parser duplication is expensive debt because subtle lexical behavior has to stay identical across every graph-safety rewrite.

Example
A future fix to SPARQL IRIREF scanning or keyword-boundary handling would need to be applied in both files. If only one copy changes, callerGraphValuesAreAuthorized and the existing graph-scope rewriters can parse the same query differently.

Suggested direction
Centralize the reusable SPARQL token-scanning primitives instead of cloning them into the new graph-scope helper module.

For Agents
Move the shared lexical scanner helpers into packages/query/src/sparql-utils.ts next to skipSparqlStringLiteral, then import them from both dkg-query-engine.ts and sparql-graph-scope.ts. Preserve the new VALUES elision behavior and existing graph-scoping tests.

});
});

// ── Registry ↔ CLI contract ───────────────────────────────────────────────

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Issue: Split this test file before it crosses 1k lines

What's wrong
This PR pushes an existing 614-line file past the 1k-line threshold. The added suites are valuable, but they are not one cohesive test subject; keeping them together makes future failures and fixture setup harder to navigate.

Example
A reader looking for the existing installMcp tests now has to scan through registry schema compatibility, command-runner fixtures, process-exit spies, and install-dispatch coverage in the same file.

Suggested direction
Decompose the appended suites by responsibility instead of letting this general integration test file become the catch-all for registry, installer, and Commander behavior.

For Agents
Split the new suites into focused files, for example integrations-registry-contract.test.ts, integrations-mcp-install.test.ts, and integrations-commands.test.ts. Extract shared registry/server fixtures into a small test helper if needed. Preserve the same assertions.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Issue: This PR pushes integrations.test.ts past 1k lines instead of decomposing it

What's wrong
The added suites take an already broad test file from under the 1k-line threshold to well over it. That is a maintainability regression even though the tests are useful: this file is now a grab bag of registry client, installer, schema-contract, and command-dispatch coverage.

Example
A future change to installMcp or registry parsing now has to scan one 1k+ integration mega-suite containing registry-client tests, installer tests, registry-schema contract tests, and command-wiring tests.

Suggested direction
Decompose the new registry-contract and Commander tests before merging. Keeping each behavioral area in its own file will make failures and future edits much easier to localize.

For Agents
Split the newly added suites into focused files, for example integrations-registry-contract.test.ts and integrations-commands.test.ts. Preserve the current assertions and fixtures; only move shared test fixtures/helpers into a small test helper module if needed. The existing tests should pass unchanged after the split.

assertionName,
subGraphName,
callerAgentAddress,
signal: queryLifecycle.signal,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Issue: The new /api/query lifecycle wiring is not verified at the route boundary

What's wrong
The changed user-facing behavior depends on handleQueryRoutes actually threading the lifecycle into agent.query and mapping scheduler shedding in its catch block. Current coverage verifies the pieces in isolation, so the public endpoint could regress while the new tests still pass.

Example
A regression that removes signal: queryLifecycle.signal or priority: queryLifecycle.priority from the agent.query call would still leave the helper tests and lower-layer forwarding tests green, while /api/query would stop using the background lane or stop cancelling disconnected reads.

Suggested direction
Cover the actual route call site, not only the helper and downstream layers, so missing or miswired lifecycle options fail a test.

For Agents
Add a route-boundary test around handleQueryRoutes in the query route tests. Use a RequestContext with an agent query stub that captures options, then assert /api/query supplies signal, default background priority, and source: 'api.query'; also assert a StoreSchedulerBusyError thrown by that call becomes HTTP 503 with Retry-After. Keep lower-layer forwarding tests as they are.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Issue: Route-level priority override is not verified

What's wrong
The PR documents DKG_API_QUERY_PRIORITY=normal as a canary rollback path, but the tests do not prove the actual /api/query route honors that override. They only prove the helper can resolve it. That leaves the public operational contract vulnerable to a hardcoded route value while tests stay green.

Example
A regression that changed the route call to priority: 'background' would still pass the current lifecycle unit test for DKG_API_QUERY_PRIORITY=normal, because that test never drives /api/query through handleQueryRoutes with the override enabled.

Suggested direction
Add a /api/query handler test that proves the configured normal lane reaches the real route handoff, not just the lifecycle helper.

For Agents
In packages/cli/test/query-route-lifecycle.test.ts, add a route-level case that calls configureApiQueryPriority('normal', ...), invokes handleQueryRoutes, and asserts the stubbed agent.query receives priority: 'normal' plus source: 'api.query'. Preserve the existing default-background route test as the control.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Issue: GenUI scheduler-busy response path has no route test

What's wrong
The new behavior changes a user-facing route from a generic failure to a retryable 503 when store admission sheds the read. The only tests cover the shared helper and /api/query; they do not prove /api/genui/render is wired to that helper.

Example
Failing-test sketch: call handleQueryRoutes with path: '/api/genui/render', a valid body, configured llm.apiKey, and an agent.query stub that throws new StoreSchedulerBusyError(...); assert status 503, Retry-After: 1, and code: 'STORE_SCHEDULER_BUSY'.

Suggested direction
Cover the GenUI route branch directly so a future removal or misplacement of the helper call cannot regress to a 500 while helper-level tests still pass.

For Agents
Add a focused route test around the /api/genui/render entity-triple fetch branch in packages/cli/test/query-route-lifecycle.test.ts or the existing route test file. Keep the agent stub throwing the real StoreSchedulerBusyError, and assert the HTTP response contract rather than only the helper return value.

getApiQueryPriority,
type ApiQueryPriority,
} from '../api-query-priority.js';
export {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Issue: The query route widens its public surface just to expose startup-priority helpers

What's wrong
The route now exports unrelated daemon configuration helpers, which couples route consumers and tests to a module that should own HTTP behavior. This makes the module boundary less clear and normalizes using route files as convenience barrels.

Example
query-route-lifecycle.test.ts imports priority configuration through ../src/daemon/routes/query.js, making the HTTP route module a test-facing barrel for daemon startup configuration.

Suggested direction
Keep daemon priority configuration in api-query-priority.ts as the canonical module and avoid re-exporting it from the route. If the lifecycle helpers need a testable boundary, extract them into their own route-adjacent module rather than making routes/query.ts a mixed API surface.

Confidence note
This is about module boundary cleanliness; the behavior can remain exactly as-is.

For Agents
Update tests to import priority helpers from packages/cli/src/daemon/api-query-priority.ts directly. Keep routes/query.ts focused on request routing; if lifecycle helpers need direct tests, move them to a small api-query-lifecycle.ts module used by both the route and tests.

<div style={{ display: 'flex', gap: 4, marginBottom: 3, flexWrap: 'wrap' }}>
{phases.map((p: any, i: number) => {
const color = p.status === 'error' ? '#ef4444' : PHASE_COLORS[p.phase] ?? PHASE_FALLBACK_COLOR;
const color = p.status === 'error'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Issue: cancelled is bolted on as repeated string branches instead of a status model

What's wrong
The PR adds a new operation status by scattering literal checks across the UI and DB aggregation code. That works locally, but it makes operation status semantics harder to reason about because color, badge class, terminal-state display, and health-rate inclusion are now separate ad-hoc branches.

Example
Adding another terminal status would require hunting through DB SQL, badge classes, Gantt colors, legends, tooltips, and detail rows. Missing one branch would silently render or count that status inconsistently.

Suggested direction
Centralize status metadata and health-rate policy so the new status is represented once. The UI components should ask for status color/label/class from a helper, and the DB stats code should share a named health-denominator policy instead of repeating success/error literals.

For Agents
Introduce a shared operation status model in node-ui, for example OperationStatus, TERMINAL_HEALTH_STATUSES, and operationStatusMeta(status). Use it for badge classes, phase colors/labels, and health denominator helpers or SQL fragments. Preserve the current success/error/cancelled/in_progress behavior.

@Jurij89
Jurij89 merged commit 5b149f6 into main Jul 30, 2026
113 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

mainnet: rs.loop.tick-threw from Store scheduler queue wait timeout in blazegraph.query

3 participants