Repository navigation
fix: refuse a legacy export cursor ahead of the store - #25
Merged
Merged
Conversation
GKS-PIP-008 was an open owner decision in the P1 report. A
gks_stage_evidence_export call whose since_cursor was beyond anything the
store had issued returned an empty page. Now it is refused with
gks_invalid_request ("since_cursor is ahead of the stage evidence
cursor."), the same way gks_pipeline_evidence already refuses an
afterCursor that is ahead.
The bound is the store-wide graph_state.evidence_cursor, not the scope's
own last row:
- every cursor a scope's pages ever returned stays valid, and a scope with
no newer rows still reads an empty page;
- the refusal reveals nothing about another scope's rows.
The per-scope cursor rule in ADR-GKS-LEDGER-REPORTING is unchanged.
zuri-ai's importer only ever advances to a returned cursor, so it is
unaffected in normal operation. The one case that now surfaces is a store
restored from an older backup: the caller gets an error instead of a
silent empty page.
The conformance test that pinned the old empty page now expects the
refusal and covers the boundary cases. The C0.4 corpus gains an
aheadCursor step in TOOL-009, the only transcript that changes.
Docs updated: GKS-PORT-CONTRACT 0.10.3b and ADR-GKS-LEDGER-REPORTING
0.6.1b. The P1 report row is closed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Summary
This PR closes owner decision GKS-PIP-008 from the P1 report.
Before: when
gks_stage_evidence_exportgot asince_cursorbeyond anything the store had issued, it returned an empty page.gks_pipeline_evidencealready refused anafterCursorthat was ahead of the store, so the two exports behaved differently.Change (
packages/gks-persistence/src/index.mjs,exportStageEvidence)since_cursorgraph_state.evidence_cursorgks_invalid_request:since_cursor is ahead of the stage evidence cursor.The bound is the store-wide cursor, not the last row of the scope being read, for two reasons:
The per-scope cursor rule in ADR-GKS-LEDGER-REPORTING is unchanged.
Callers
knowledge-evidence-importer.jsonly ever moves its cursor to anext_cursoror a row cursor that a page returned, so it cannot send a cursor that is ahead in normal operation.The one situation that behaves differently is a GKS store restored from an older backup. A puller whose stored cursor is now ahead of the store gets an error instead of a silent empty page.
Golden corpus
C0.4-TOOL-009(the legacy export case) gains anaheadCursorstep. It sendssince_cursor: 3when the store's cursor is 2, and expectsgks_invalid_requestwith that exact message. That case is the only transcript that changes.Docs
GKS-PORT-CONTRACT0.10.3b: a new behavioural-requirement paragraph, and an updated row for the tool.ADR-GKS-LEDGER-REPORTING0.6.1b: a revision row.Test plan
tests/contract/persistence-port-conformance.test.mjs: this test pinned the old empty page (cursor 7 on an empty store). It now expects the refusal, and adds three checks:tests/contract/stage-evidence-export.test.mjs: after paging through all 5 rows,since_cursor: 6is refused with the exact message.npm test: vitest 298 passed and 2 skipped (the MSP suites needMSP_REPO_ROOT); security 12/12.npm run check:c0(PASS 24 / NOT_RUN 1),check:baselineandcheck:corpuspass.🤖 Generated with Claude Code