Skip to content

feat(queryspace): Batch F dual-surface integration - #219

Merged
fazpu merged 60 commits into
mainfrom
feat/queryspace-batch-f
Aug 6, 2026
Merged

feat(queryspace): Batch F dual-surface integration#219
fazpu merged 60 commits into
mainfrom
feat/queryspace-batch-f

Conversation

@fazpu

@fazpu fazpu commented Aug 6, 2026

Copy link
Copy Markdown
Member

Problem

Batch F completes the accepted Open Query Space dual-surface integration: the existing SQL, Cypher, discovery, and saved-query authorities need one deployment-bound facade and consistent HTTP, SDK, CLI, and MCP access while the legacy recipe surface remains frozen. The consumption guidance also needs to present the accepted two-layer retrieval model without starting the paid cutover benchmark.

Scope

  • Add a thin OpenQueryFacade over the existing Batch B–E authorities.
  • Compose the open surface into self-host, HTTP, SDK, CLI, local MCP, and remote MCP.
  • Expose exactly nine static open-query MCP tools; keep examples.* behind saved-query operations.
  • Preserve legacy recipe behavior while recording content-free dual-surface usage counters.
  • Publish the bound headline, retrieval choices, worked examples, and honesty guidance through discovery, the consumption skill, and OSS docs.
  • Add offline noninferiority evaluation and cost estimation that never starts a paid/model-backed run.

Batches D and E have merged as #211 and #215. This branch is aligned with their squash merges, so this PR's effective delta is Batch F only.

Important decisions

  • Reuse the existing executors, discovery, saved registry, authentication perimeter, and manifest authorities; do not add another parser, execution path, or capability endpoint.
  • Bind all composed surfaces to one deployment and fail closed on mixed composition.
  • Remote MCP asks GET /query/space whether the open surface is composed. It validates only the stable memory_v1 identity discriminants and fails closed on missing/malformed discovery; it does not duplicate the full discovery schema.
  • Keep the base SDK/CLI dependency-light through lazy server/eval imports.
  • Preserve the exact saved-result stamp {query_id, namespace, name, version, query_hash}.
  • No PostgreSQL RLS, dynamic saved-query tools, automatic cutover, or speculative compatibility framework.

Sources inspected

  • plan/designs/open_query_space_design.md §3.1, §4, §6, §8, §9, and §11
  • plan/implementation_notes/open_query_space_batch_f.md
  • Existing Batch B/C SQL sandbox and discovery authorities
  • Existing Batch D Cypher executor and Batch E saved-query registry
  • Existing HTTP authentication, SDK/CLI, MCP, self-host composition, and consumption-skill surfaces

Validation and review

  • Grok 4.5 implemented Batch F and each bounded correction pass.
  • Focused Batch F/client-SDK verification at the final head: 43 passed under Codex; 47 passed under Grok when including consumption-skill tests.
  • Independent malformed/unavailable remote-discovery matrices passed, including recipe preservation and stdio continuity.
  • Import contracts, targeted Ruff/format, git diff --check, manifest identity, legacy-recipe freeze, no-RLS, and base-wheel safety checks passed.
  • Exact-head Codex review of 8121fd3b..6fd3fea7: APPROVE, no findings.
  • Exact-head Grok review of 8121fd3b..6fd3fea7: APPROVE, no findings.
  • CI exposed one test-only Pyright narrowing issue at the approved head; the correction preserves the exact headline assertions and leaves the SDK contract unchanged.
  • Exact correction review by Codex of 6fd3fea7..04eca84e: APPROVE, no findings; Pyright 3.12/3.13/3.14 and Ruff passed.
  • Exact correction review by Grok of 6fd3fea7..04eca84e: APPROVE, no findings; targeted Pyright passed.
  • The corrected Batch E stack was merged conflict-free so CI validates F against the final upstream corrections; the first-parent delta is exactly the four known D correction files.
  • Exact stack-sync Codex review of 04eca84e..1bdd5e27: APPROVE, no findings; F contract paths remained byte-identical to the first parent.
  • Exact stack-sync Grok review of 04eca84e..1bdd5e27: APPROVE, no findings; merge blobs matched the corrected E parent exactly.
  • After feat(queryspace): Batch E saved-query customer space #215 squash-merged, origin/main was joined with an ancestry-only merge; the resulting tree is byte-identical to 1bdd5e27 with zero content delta.
  • Exact final ancestry review by Codex of 1bdd5e27..5fe926d2: APPROVE, no findings.
  • Exact final ancestry review by Grok of 1bdd5e27..5fe926d2: APPROVE, no findings.
  • CI at 5fe926d2 passed Python 3.12 but exposed a test-harness connection leak before the next module's schema reset on 3.13/3.14; Grok implemented deterministic test-only closure of raw registry connections.
  • Exact cleanup review by Codex of 5fe926d2..29bbeef4: APPROVE, no findings; targeted Ruff, format, and Pyright passed.
  • Exact cleanup review by Grok of 5fe926d2..29bbeef4: APPROVE, no findings; scope and teardown ordering verified.
  • Final exact-head CI run 31098112042 passed Compose, Python 3.12/3.13/3.14, coverage, CLA, and docs gates; the connection teardown correction closed the former 3.13/3.14 stall.
  • Final Batch F head: 29bbeef4f416f416203d7fdd4b1e1b30af575a38.

Limitations and follow-up

Contributor agreement

fazpu and others added 30 commits August 5, 2026 22:30
…ead gate

`graph_neighborhood` and `graph_path` ship as bounded PostgreSQL functions
(design §3.4, bounds from §4.3). With no instants they read
`graph_edges_current`, so a traversal and a direct read of the current graph
cannot disagree about what is current; with `valid_at` or `believed_at` they
read the history view under both D41 clocks, each half-open. Every bound is
clamped inside the function and each walk is ordered before it is cut, so a
bound means one thing rather than a different subgraph per run.

Traversal is undirected — a relation is an assertion about two entities, and
answering only from the subject side would silently answer half the question —
and a relation is walked at most once per branch, paths never revisit an
entity, and the start is not reported as its own neighbour.

The Cypher gate is the mandatory pre-engine control. `read_only=True` blocks
writes but not `COPY`/`LOAD`/`INSTALL`-class file and extension actions, so
every mutation and external-action construct is rejected by name before the
engine sees the text — including one hidden in a UNION arm, behind a comment
boundary, or inside a subquery. Quoted prose and comments contribute nothing to
the scan, because a keyword inside a string is data.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKENhTLJg1HqhbdwCmmkbc
`query_cypher` and `explain_cypher` run one read statement against the
published graph snapshot and answer with grade `snapshot_graph` and the
`built_at` of the generation they ran against — a snapshot answer is exactly
correct for its cut and says nothing about what has happened since, so the cut
travels with it. The reader surfaces `built_at`, which it previously read from
the registry and dropped.

No published snapshot fails `p2_unavailable`: an empty graph and an absent
graph are different answers.

`confirm=true` checks live membership of top-level Entity and RELATES ids and
drops failing rows as units, without re-running the plan or re-grounding an
aggregate; asking for it with no PostgreSQL connection is refused rather than
ignored.

Structural values lose the engine's physical offsets, which are stable only
within one build. The engine spells those keys in upper case, so the first
implementation published every one of them and confirmed nothing — the test
that asserts a node carries no offsets is what caught it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKENhTLJg1HqhbdwCmmkbc
What the graph surface accepts and what it refuses is part of the public
contract, not an implementation detail: an agent needs to know this surface
reads and only reads, and which types `confirm=true` can check. A change to
either now rolls `surface_manifest_hash`, which is what makes the hash an
identity rather than a description of the SQL side alone.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKENhTLJg1HqhbdwCmmkbc
The process-isolated engine worker and `question_context` v4 are Batch D scope
and are not in this slice. The isolation gap is worth naming precisely: we have
observed the pinned engine fault mid-traversal rather than merely imagined it,
so the case for a supervisor that can outlive it is measured, not speculative.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKENhTLJg1HqhbdwCmmkbc
Batch C and Batch D each claimed revision p9_03_0024 while developing in
parallel. C merged first, so the graph helpers become p9_04_0025 on top of it,
and the quickstart gate's expected head follows.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKENhTLJg1HqhbdwCmmkbc
… paths whole

The gate skipped `--` to end of line as a comment. The pinned engine does not
treat `--` as a comment at all, so the scan went blind to text the engine goes
on to parse — the one direction a gate must never be wrong in. Every statement
of that shape happens to fail the engine's own parser today, which is why it
had not shown up as a leak, but that is a property of this dialect rather than
something to depend on. The scan now recognises exactly `//` and `/* */`, which
is what the engine recognises, verified against it rather than assumed.

`graph_path` could also return a path cut in half. Paths were chosen as units,
their steps unnested, and only then was the edge bound applied as a row limit,
so a later path came back reporting `path_length = 3` with a single step — a
route that does not connect, presented as one that does. The bound is now spent
on whole paths, and a path that cannot fit is omitted rather than truncated.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKENhTLJg1HqhbdwCmmkbc
The engine runs `*` and `*1..` quite happily — its binder only refuses an
explicit upper bound above its own 30-hop limit — so the gate's hop cap was a
cap in name only, and `*1..` was worse than useless: the lower bound was read
as the maximum. A pattern that states no finite upper bound is now refused.

The `*` is only read as a traversal inside a relationship pattern's brackets,
so `count(*)` and multiplication are untouched, and §3.5's recursive modes
(SHORTEST, ALL SHORTEST, WSHORTEST(property), TRAIL, ACYCLIC) are stepped over
so the range after them is the one that gets read.

The note also records what `confirm=true` does not do: a scalar projection of
`Entity.id` comes back unconfirmed with all three counts at zero. Doing that
correctly needs the parsed Cypher AST to know which UUID column derives from
`Entity.id`; guessing from names or value shape would drop `Document` ids,
which §3.5 says are never confirmed. Reporting zero is honest, but a caller
reading zero as "all clear" would be misreading it, so it is written down.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKENhTLJg1HqhbdwCmmkbc
The note explained that a scalar `RETURN e.id` is not confirmed; the module a
caller actually reads did not. It now says so, and says what to do instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKENhTLJg1HqhbdwCmmkbc
…ally bind

`built_at` came from the registry row's `DEFAULT now()`, written before the
repeatable-read export opened. The instant every Cypher answer is scoped to
therefore preceded the data it described — and that instant is the entire basis
of the `snapshot_graph` grade. It is now the export transaction's own
`transaction_timestamp()`, captured when the cut is taken and carried through
publication.

`max_rows=-1` returned 1,499 rows against a 1,000 cap: `min(-1, 1000)` is -1
and `rows[:-1]` keeps almost everything. A row bound is clamped into the range
it describes before it is used as one, and the byte cap now enforces the tier's
DEFAULT rather than its hard ceiling, which was letting an unremarkable query
return eight times what the tier says it returns.

A reader serves one deployment, so it says which, and pairing it with a
different deployment id is refused. Taking the two as independent arguments let
a mismatched pair serve one deployment's graph labelled as another's.

Confirmation runs in one REPEATABLE READ transaction: under READ COMMITTED a
commit between the entity check and the relation check could keep a row whose
two halves were never simultaneously live at the disclosed instant. It also
reaches PostgreSQL even when nothing was confirmable, so zeros mean "nothing to
check" rather than "never asked", and `requested` counts confirmable ids rather
than rows.

The manifest no longer implies more than the code does: naming the confirmable
types read as a promise about any projection of them, so the projections that
ARE checked and the scalar one that is not are both named.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKENhTLJg1HqhbdwCmmkbc
Over-refusing is its own failure: it makes legal queries impossible, and four
shapes the pinned engine accepts were being turned away.

A `*` now counts as a hop bound only in the relationship pattern itself. Inside
a property map or an inline recursive predicate it is multiplication, so
`[r:RELATES {confidence: 2 * 31}]` and `(r,n | WHERE r.confidence * 100 > 50)`
were both being read as unbounded traversals. A comment may sit between the `*`
and its range. A terminal semicolon followed only by a comment is one
statement, which is how the engine reads it.

`UNINSTALL` is extension management the engine ACCEPTS, so it is refused by
name rather than falling through to `cypher_parse_error`, which made a refused
construct look like bad syntax.

Each case was checked against the pinned engine rather than reasoned about, and
the tests record the engine as the authority.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKENhTLJg1HqhbdwCmmkbc
… open

The helpers' history branch required a non-null lower endpoint on both clocks,
so a relation with no recorded start was hidden from every as-of question. A
null start means "as long as anyone knows", not "after every instant" — the
opposite reading — and both clocks now treat a null endpoint as open, matching
what the design says and what `facts_as_of` already did.

Naming one clock and letting the other default to now() answered a question the
caller did not ask: "as the world was then, as we believe it now" is a
legitimate third query, but returning it under a one-clock request misreports
what the rows mean. A guard refuses the half-specified form by name rather than
substituting a default.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKENhTLJg1HqhbdwCmmkbc
…e from

The connection and its provenance were read separately, so a refresh landing
between them produced rows from one generation labelled with another's
snapshot id, version, and cut. Provenance is the entire basis of the
`snapshot_graph` grade, so a result that misdescribes its own generation is
worse than one that returns nothing. Both are now taken as one act under the
reader's refresh lock.

§4.4's Cypher contract is honoured: `query_space_schema` is null, because a
Cypher answer did not read the memory_v1 views and crediting them would tell a
caller their rows came from somewhere they never queried; and the statement's
referenced projection types and properties are published, so a caller can see
which part of the graph contract their answer depends on.

`max_rows=0` asks for no rows — only an absent bound takes the tier default —
and the disclosed row cap is the one that actually applied rather than the tier
ceiling, which told a caller nothing about where their rows were cut.

Only `-[` opens a relationship pattern: every other `[` opens a list, so
`RETURN [2 * 31]` is arithmetic rather than a 62-hop traversal. A confirmed
result also carries its confirmation instant at the top level.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKENhTLJg1HqhbdwCmmkbc
…stant

The publication guard compared a candidate against `mine.built_at`, which at
that moment is still the registry-insert time — the export cut is written by
the publish immediately after. A genuinely newer snapshot could therefore be
superseded by an older one. It now compares against the cut being recorded.

The helpers disclosed `now()`, which in PostgreSQL is transaction start, while
`graph_edges_current` evaluates at statement time. Rows selected by one instant
were labelled with an earlier one, so both now use `statement_timestamp()`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKENhTLJg1HqhbdwCmmkbc
…versal

`MATCH (a)-/* gap */[r:RELATES*]->(b)` runs unbounded on the pinned engine and
the gate accepted it: the relationship-bracket check read the raw preceding
character, which the comment displaced. Classification now uses what the SCAN
saw, which steps over comments, and requires the pattern arrow on BOTH sides —
`1 - [2 * 31][1]` is subtraction of a list element, not a traversal.

Graph references are read by walking the statement rather than matching over
raw text, so quoted prose contributes nothing and a property map's keys count
as the properties they are.

This holds the line until the gate is replaced: the classification is still a
hand-rolled reading of Cypher syntax, which is the approach being retired.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKENhTLJg1HqhbdwCmmkbc
The hand-rolled character scanner tried to understand Cypher well enough
to classify constructs and read variable-length hop bounds. Three review
rounds found seven defects in it, four of them introduced by fixes to
earlier ones. It was a lexer doing a parser's job, and it enforced a
resource limit (hop count) through syntax analysis.

Measured against ladybug 0.18.2:

- Database(read_only=True) refuses SET/DELETE/CREATE/MERGE with
  "Connection exception: Cannot execute write operations in a read-only
  database!" so the gate need not detect mutations to be safe.
- read_only does not block COPY/LOAD/INSTALL/UNINSTALL/ATTACH/IMPORT/
  EXPORT/CALL — those die in a token scan before the engine sees them.
- The engine does not treat -- as a comment; the scan still does not.

What remains: a deny-scan for the file/network/extension family only,
one statement per request, and the 32 KiB text cap. Mutations that reach
the engine map through a pinned READ_ONLY_REFUSAL string to
cypher_not_allowed. No EXPLAIN compile step — it cost 49–74% of a
query's own runtime and bought nothing once read_only refuses writes.

Deleted: the hop-range parser, relationship-bracket classifier,
recursive-mode keyword stepper, and graph-reference walker. Tests that
encoded those (hop-bound parsing, bracket classification, reference
extraction) are gone because the new design makes them obsolete.
referenced_graph_types/properties stay empty (§4.4 gap). The hop cap
moves to timeout + row/byte caps — a DEVIATION from design §3.5 that
makes the unbuilt process-isolated worker load-bearing, recorded in the
Batch D implementation note.
`UPDATE fts` updates an extension and RUNS on a read-only database — verified
against the pinned engine. It is the same family as INSTALL and exactly what
`read_only=True` does not stop, so it has to die in the deny-scan. It was
missing from the eight keywords I specified; the rewrite flagged it rather than
quietly adding it, which is the right way round.

Also records the process-isolated worker as a decision rather than debt. The
fault that motivated it raises and is mapped like any other engine error; it
does not wedge the process, and a runaway traversal is bounded by the query
timeout and the row and byte caps. A supervisor would defend against a failure
mode nobody has observed. Two observations would reopen it, and they are named.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKENhTLJg1HqhbdwCmmkbc
…ords

A deny list only refuses what somebody remembered. The first one missed
`UPDATE`; the second still missed `BEGIN TRANSACTION READ ONLY` — which leaves
the shared connection in an open transaction across requests — along with
`ANALYZE`, `CHECKPOINT`, `USE` and `DETACH`, all of which the engine runs. The
same list also refused ordinary reads that merely used a denied word as an
alias, so `RETURN 1 AS update` failed.

A read statement can only BEGIN one of five ways. Requiring that refuses every
session, maintenance, extension, attachment and file construct at once —
including the ones nobody here has thought of — and stops punishing a caller
for their choice of alias. This is the third attempt at this gate and the first
that does not depend on having enumerated the danger.

The row and byte caps now bound the ENGINE, not just the answer. Draining every
row and trimming afterwards made them disclosure numbers: `UNWIND RANGE(1,
100000) AS n RETURN n` with max_rows=1 pulled a hundred thousand rows into
memory to return one. Reading stops at the cap, keeping one row past it so
truncation is still reported honestly. That matters more since the hop bound
moved to runtime — it was the bound I said was already there.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKENhTLJg1HqhbdwCmmkbc
The refusal was detected by substring, so `RETURN error('Connection exception:
Cannot execute write operations in a read-only database!')` was reported as
`cypher_not_allowed` — the surface telling a caller their own error was it
declining to run a write. The pinned engine prefixes a user-raised error with
"Runtime exception: ", and a genuine refusal is the exact string, so the
comparison is now equality.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKENhTLJg1HqhbdwCmmkbc
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
fazpu and others added 26 commits August 6, 2026 01:46
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Keep the full-v9 tool catalog frozen, correct the P2-edge deletion matrix coordinate, and bound planning for current-context live evidence hydration.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
A saved query is something other people's work comes to depend on, so editing
one adds a version rather than changing what an earlier caller ran. Identities
and versions are separate tables, versions are append-only, and every version
pins the `surface_manifest_hash` it was validated against.

`publish_surface_hash` moves every active version to `pending_revalidation` in
the caller's transaction, so the suspension and the publication of a new hash
are one act: there is no instant at which a version is executable while
claiming validation against a surface that has been replaced. That state is
non-executable on purpose, and `resolve` names the reason for every refusal —
not found, disabled, awaiting revalidation, incompatible — because a caller who
gets nothing back from a query that was silently not run cannot tell that from
an empty answer.

Authoring and approving are separate acts: an agent may draft within quotas,
activation records an approver, and the approver may not be the author. §5's
deployment and per-principal bounds are enforced with `quota_exceeded`.

Still to come in this batch: the validation fixtures, the automatic
revalidation path with its compare-and-swap on the manifest hash, and the
shipped `examples.*` queries.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKENhTLJg1HqhbdwCmmkbc
§3.1 maps seventeen `examples.*` names; this ships a body for every one, and
each parses through the same grammar an ad-hoc statement does. An example that
could not be run would be worse than shipping none.

They are deliberately plain SQL over the memory_v1 views. An example needing a
trick the surface does not otherwise support would teach the wrong thing.

A test cross-checks the shipped names against the bodies behind them: two lists
that can drift apart will, and mine already had — I wrote bodies for two
queries the design does not map and omitted two it does.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKENhTLJg1HqhbdwCmmkbc
§5 names four fixture classes a saving validation must execute. "It validated"
is not something a later reader can check, so the report records each fixture
by name and passes only when every one of them ran and passed — a validator
that ran three does not get to call that a pass, and a report that simply omits
a fixture is not a pass either.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKENhTLJg1HqhbdwCmmkbc
The registry, the pending_revalidation machine, the compare-and-swap
revalidation, the validation-report gate and the seventeen examples are built.
The validator that actually executes the four fixtures, discovery exposure, and
run_saved_query are not, and saying so here is cheaper than a reader finding it
in the diff.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKENhTLJg1HqhbdwCmmkbc
Execute all four operator-owned validation fixtures through the existing sandbox, expose active saved-query discovery without drafts, and advance the migration gate after Batch D. Keep run_saved_query and adapter work in Batch F.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Bind validation to database-authoritative surface state, execute real revalidation fixtures, enforce immutable registry content, and verify all shipped examples through the four required fixture classes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: handoff commit dc85cf0f
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: handoff commit dc85cf0f
@fazpu
fazpu enabled auto-merge (squash) August 6, 2026 10:08
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: handoff commit dc85cf0f
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  src/rememberstack/core
  consumption_skill.py
  open_query_prose.py
  src/rememberstack/eval
  __init__.py 159, 168
  open_query_noninferiority.py 93-96, 152, 238, 322
  src/rememberstack/profiles
  selfhost.py 174, 184, 192, 200-216, 239, 265-268, 281-291, 410-411
  src/rememberstack/surfaces
  __init__.py
  cli.py 55-58, 173-174, 176-186, 207-215, 217-228, 230-238, 251-256, 258-266, 268-276, 291-295, 304, 310-315, 375, 380-415
  http_api.py 207, 435-438, 459-464, 539-540, 549-574
  mcp.py 76
  recipe_surface.py
  remote_mcp.py 108, 117
  sdk.py 142, 145, 154-164, 175-187, 193-203, 213, 227, 236-246, 252-263, 277, 279, 284, 299-366, 610-614, 619-625
  src/rememberstack/surfaces/query_sandbox
  __init__.py 50-66
  audit.py
  cypher_executor.py
  discovery.py 189, 237
  examples.py
  executor.py
  limits.py
  mcp_tools.py 262, 265, 278, 300, 322, 340, 349-355, 373, 381, 388, 397, 414-488, 493-498, 503-512, 520-524, 532-538, 587, 598-604
  open_query.py 76, 83, 145-146, 164, 195, 253-258, 263
  saved_queries.py 803, 809, 825
  src/rememberstack/workers
  p2.py
Project Total  

This report was generated by python-coverage-comment-action

@fazpu
fazpu merged commit db654ad into main Aug 6, 2026
9 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.

1 participant