Skip to content

fix(proof): expose read completeness - #254

Open
toeknee-figma wants to merge 2 commits into
mainfrom
stack/toeknee-figma/fix/proof-read-completeness/expose-read-completeness--4cbd9019
Open

fix(proof): expose read completeness#254
toeknee-figma wants to merge 2 commits into
mainfrom
stack/toeknee-figma/fix/proof-read-completeness/expose-read-completeness--4cbd9019

Conversation

@toeknee-figma

@toeknee-figma toeknee-figma commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator

Fixes #252

What now works

  1. Every Proof read envelope includes complete and cap_reasons.
  2. complete is true only when paging and hard caps did not omit data.
  3. Ordinary paging returns complete: false, cap_reasons: [], and page.has_more: true.
  4. Record, edge, and byte caps return stable, duplicate-free reasons.
  5. The JSON envelope, digest header, and summary use the same completeness state.

Add `complete` and `cap_reasons` to every Proof read envelope. Derive the JSON fields, digest header, and summary from the same state so pagination and hard caps cannot disagree.

Keep pagination out of `cap_reasons`; `page.has_more` and its cursor describe it. Report primary record, displayed edge, and byte caps as stable, duplicate-free values.

Tests:
- `pnpm verify`

Fixes #252

Change-Id: I4cbd9019dd5ef042482e5e5824211dc95d1e1592
@tonyketcham
tonyketcham marked this pull request as ready for review August 17, 2026 20:26
@tonyketcham
tonyketcham self-requested a review August 17, 2026 20:26
@mergify

mergify Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review verdict: COMMENT

Issue #252’s complete / cap_reasons fields land correctly on the JSON envelope for the tested singles (happy path, paging-only, each hard-cap reason, CLI bytes). No blocker. Non-test source changed and the coverage plan is still non-empty, so this is not a clean APPROVE.

Highest-signal gaps

  1. HIGH — No test stacks bytes on primary_records / displayed_edges after the byte-cap recompute (digest.ts:311). Singles stay green if that recompute regresses when reasons are already non-empty.
  2. MEDprimary_records still sets page.has_more: true with next_cursor: null, and YAML primary.has_more can disagree with envelope page.has_more (pre-existing quirk; does not falsify the new fields).
  3. MED — New hard-cap tests miss YAML/summary/next_cursor parity; the displayed_edges uniqueness assert is vacuous with one reason.
  4. LOW — CLI spawn covers complete / page / bytes only; add a proof relations path for displayed_edges (primary_records is unit-only because render() limit === CAP_RECORDS).

Coverage plan (ordered)

  1. Stacked hard caps + byte rebuild → sorted multi cap_reasons
  2. primary_records: assert next_cursor === null + YAML/envelope has_more parity (or fix policy)
  3. displayed_edges: assert page.has_more === false; replace vacuous Set check
  4. Combined hasMore + hard cap
  5. CLI displayed_edges spawn assert

Perspectives

correctness-and-contracts · test-coverage-robustness · cli-and-runtime · docs-and-positioning · release-discipline

Models: Cursor Grok 4.5 High (HIGH), Composer 2.5 (MED/LOW). Oven unavailable → Task fallback. Judge: /tmp/review-judge-final.md.

Open in Web View Automation 

Sent by Cursor Automation: Flatbread PR Review

].join('\n');
if (Buffer.byteLength(markdown) > CAP_BYTES) {
reasons.push('bytes');
completeness = digestCompleteness(Boolean(input.hasMore), reasons);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

HIGH — coverage: This recompute is the only place bytes joins an already non-empty reasons list. Current tests cover bytes-only and record/edge singles, not a stacked case.

Add one renderDigest fixture with record (or edge) overflow plus oversized bodies and assert complete === false and cap_reasons deep-equal the sorted multi-reason list (e.g. ['bytes', 'primary_records']). Without that, dropping this recompute when reasons were already set can ship while all existing tests stay green.

const reasons: ReadCapReason[] = [];
if (records.length > CAP_RECORDS) reasons.push('primary_records');
if (input.edges.length > CAP_EDGES) reasons.push('displayed_edges');
let completeness = digestCompleteness(Boolean(input.hasMore), reasons);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

MED — contract follow-up (pre-existing): primary_records still couples to page.has_more: true with next_cursor only when input.hasMore is set, so a hard-capped read can advertise “more” with no cursor. displayed_edges / bytes do not do this.

The new complete / cap_reasons fields correctly name the hard cap; this does not block #252. Prefer either (a) keep page.has_more false for hard caps, or (b) assert next_cursor === null and document the decision tree so callers do not treat has_more as “fetch next page.”

served_generation: input.generation,
consistency: input.consistency,
complete: completeness.complete,
cap_reasons: completeness.capReasons,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

MED — envelope vs digest drift: Envelope page.has_more still ORs records.length > CAP_RECORDS (below), while YAML primary.has_more stays Boolean(input.hasMore) only. A 26-record renderDigest can show JSON has_more: true and digest primary.has_more: false even though complete / cap_reasons now agree across surfaces.

Align YAML primary.has_more with envelope page.has_more, or stop OR-ing the hard cap into page.has_more, and add a parity assert.

hasMore: boolean,
reasons: readonly ReadCapReason[]
): DigestCompleteness {
const capReasons = [...new Set(reasons)].sort();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

MED — untested multi-reason path: Dedupe + sort here is the machine contract for stacked caps, but no renderDigest test drives ≥2 reasons. CLI cannot hit primary_records today (render() max limit 25 === CAP_RECORDS), so library coverage must prove sort/unique behavior.

Stack caps at the API (private helper) and assert exact sorted cap_reasons.

});
t.false(result.complete);
t.deepEqual(result.cap_reasons, ['displayed_edges']);
t.is(new Set(result.cap_reasons).size, result.cap_reasons.length);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

MED — weak assert: With a single reason, Set size === length is a no-op. This test also never asserts page.has_more === false (unlike the primary-record case, which forces has_more).

Replace with a real multi-reason / parity assert: page.has_more === false, digest YAML complete/cap_reasons, and next_cursor as applicable.

t.is(cappedResult.code, 0);
const capped = JSON.parse(cappedResult.stdout);
t.false(capped.complete);
t.deepEqual(capped.cap_reasons, ['bytes']);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LOW — CLI gap: Spawn covers complete / page-only / bytes. displayed_edges is reachable via proof relations (full edges before record paging) but unasserted at the JSON boundary. primary_records may stay unit-only (limit === cap).

Add one relations (or spawn) assert: complete: false, cap_reasons: ['displayed_edges'].

full body via the 600/12 excerpt).

Every read envelope carries `complete` and `cap_reasons`. A page with more
records has `complete: false`, an empty `cap_reasons`, and

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LOW — docs: Envelope-first guidance is right. Still missing: (1) primary_records can yield has_more: true with null cursor, (2) cap_reasons may hold several sorted values, (3) § What not to do should also ban parsing summary (not only the digest).

Add a short decision tree and sync the .agents twin via skills:sync.

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.

proof: expose completeness and cap reasons in read envelopes

2 participants