Skip to content

Keep an AND group's estimate finite when a sibling condition is filter-only - #3724

Merged
kriszyp merged 32 commits into
mainfrom
fix/estimate-condition-filter-only-sibling
Nov 2, 2026
Merged

kriszyp merged 32 commits into
mainfrom
fix/estimate-condition-filter-only-sibling

Conversation

@kriszyp

@kriszyp kriszyp commented Oct 28, 2026 •

Copy link
Copy Markdown
Member
A route setter chalks a grade on a route card with its unclimbable hold crossed out and sets the impossible stamp aside

⊙ Problem

Choosing the leading AND condition failed three ways:

  • A filter-only condition (IS NULL, LIKE '%x%') estimates Infinity, which made SQL !=/NOT IN and nested FIQL groups fail with 403 under allowFullScan: false.
  • in, an empty starts_with and an unindexed range scan every row, yet could lead before an indexed condition.
  • A relationship condition inside an OR restricted which related records a row selects (harper#3762).

Changing the lead also changed which related record two conditions on one relationship had to meet, so a finite estimate could widen a collection DELETE.

🤔 Is the requirement right?

Yes: both rules are the owner's decisions.

💡 Solution

⚖️ Alternatives

Rejected approaches
  • Infinity estimates for full-scan legs — count: 'estimated' and the lazy index switch read them as counts.
  • Rank every leg by "can drive" — reorders the record filters behind the lead.
  • Keep rows lead-dependent, as on main — the framing review found the finite estimate could widen a collection DELETE.

🤔 Same-record matching changes a result main pinned

Fix wrong rows, unfiltered selects and ignored sorts in relationship queries pinned that a non-leading AND matches a parent whose children meet the conditions separately. That test now expects no match, as a leading join gave.

🤔 An unindexed foreign key never drives

Its scan reads the local table once per related record, which the estimate does not price, so an indexed condition leads even under allowFullScan: true.

🔧 Changes

  • resources/search.ts:
    • conditionDrivesIndex follows searchByIndex's full-scan and missing-index decisions, and relationshipScanRuns extends it hop by hop. Look hardest here: it must stay in step with the executor, and a test checks them leaf by leaf.
    • executeConditions and mapConditionsToFilters take a scope where main threaded inUnion; filterByType registers sibling filters per scope under a symbol key, and the first condition checks the whole set per related record. A to-one relationship shares only its inner scope.
    • Join and selection restrictions moved behind relationshipRestriction, keyed by symbol, so a relationship may be named filters or get.
    • A key condition still rejects a record before any related record loads; an omitted or singleton-null attribute reads as the primary key, and a one-element ['id'] path estimates 1.
  • resources/Table.ts: the lead promotion, which keeps a synthetic sort (or a user condition on the sort attribute unless allowFullScan is false) in front; a nested select's conditions follow the same rule.
  • resources/DESIGN.md: the estimator, lead, scope and OR rules.

🤔 Async relationship selection still allocates per row

Selecting a to-many relationship whose related records load asynchronously builds a match arrow and a matchingIds closure for each parent row, the same as main. Hoisting the arrow is a separate cleanup.

✅ Verification

Fixes #3725
Closes #3739
Closes #3813

🤖 Generated by Claude Opus 5.5 via Claude Code; posted via @kriszyp.

Release target: v5.4 — fixes a regression from #3601, which is milestoned v5.4
Related PRs: #3601 overlaps (fixes a regression it introduced); #3776 overlaps (merged first); #3775 overlaps (merged first); #3772 overlaps (search.ts and Table.ts); 6 others independent
Complexity: high
Framing-Verdict: chosen-approach-sound

Deferred findings

  • db316ad3c3eb6566 major performance — resources/search.ts — Allowed full scans lose an executable relationship lead with an unindexed foreign key — NOT FILED
  • 6ce214f314a60636 major correctness — resources/Table.ts — A non-driving sort-aligned lead suppresses sorting or rejects a null-equality query — NOT FILED
  • b1c07dbbe9115cd7 minor performance — resources/search.ts — conditionDrivesIndex recomputed recursively per ancestor, O(depth^2) — NOT FILED
  • a4bee76312e168cf minor performance — resources/Table.ts — a narrower non-driving condition displaces the synthetic sort, and promotion then skips the sort and promotes another indexed condition — NOT FILED
  • 563aa49357eaca44 minor correctness — resources/search.ts — starts_with null/undefined value: TypeError in searchByIndex on lead or lazy index switch; filter path matches 'null' prefix — NOT FILED
  • de7af54d4747481c minor performance — resources/search.ts — async to-many selection allocates a match closure and a matchingIds closure per parent row — NOT FILED
  • e937c699d7582749 nit test-coverage — unitTests/resources/estimateFilterOnlySibling.test.js — broad-in plus sort case asserts only the plan, not the rows — NOT FILED
  • 052305fc5f7fa204 nit reliability — resources/search.ts — Sibling predicates on a leading join rely on lazy iteration of the lead — NOT FILED
  • c98b870701ea83f7 nit performance — resources/search.ts — intersectionEstimate multiplies Infinity into the incoming-row hint — filed intersectionEstimate multiplies Infinity into the incoming-row hint used by filter index switching #3726

🤔 defer this PR's major performance finding db316ad3c3eb6566 (Allowed full scans lose an executable relationship lead with an unindexed foreign key) to a separate issue instead of fixing it here?

Origin — the dispatch brief this PR was written from

In estimateCondition (resources/search.ts ~2214-2222), the AND branch multiplies the running estimate by each sub-condition's estimated_count / N without checking that it is finite. Filter-only legs get estimated_count = Infinity (~2283), so any filter-only sibling (IS NULL, LIKE '%x%', LIKE '%x', NOT (...)) turns a finite index-backed estimate into Infinity. Since harper#3601 lowers SQL != and NOT IN into compound AND groups, SQL SELECT/UPDATE/DELETE with != or NOT IN after a filter-only predicate, and nested FIQL AND groups, now fail with 403 under allowFullScan: false, and count: 'estimated' returns null. Skip non-finite sub-estimates in the AND intersection; if every leg is Infinity the group stays Infinity.

Acceptance

Unit test on rocksdb and lmdb covering SQL SELECT/UPDATE/DELETE with != and NOT IN after IS NULL / LIKE '%x%' / LIKE '%x' / NOT(...), a nested FIQL AND group under allowFullScan:false (200, not 403), Table.search({count:'estimated'}) non-null, and orderConditions picking the indexed leg. Show each new test failing on origin/main sources (forced rebuild) before the fix.

Dispatch: task harper-estimate-and-infinite-sibling · queued by finding-triage/wave-42 · ran by claude/sonnet/xhigh · worker kzyp-xps-1

Late Grok findings

2 surviving (highest major) — Grok reviewed 4931740, ruled against e864fea
  • major — resources/search.ts:2218 — An AND group that previously estimated Infinity now takes a finite estimate from a leg that cannot drive a scan: an unindexed or empty starts_with, an unindexed range, or an indexed in. The parent AND then sorts that group ahead of an indexed sibling. Example: indexed c = common (50 of 100 r
  • nit — resources/search.ts:2216 — Open comment finding about the new line that says what Infinity means in the reducer. It is the only comment the diff adds, and it states a convention that estimateConditionForTable shares across functions, which the code cannot express on its own; author's call

Not standing: 1 merged. Grok ran 15m (16m from launch to report); the fold adjudication (cursor-grok@4931740106a6-37ccf37f, claude) took 1m.

Late Grok findings

4 surviving (highest minor) — Grok reviewed b1cdfad, ruled against 0e74d46
  • minor — resources/search.ts:1056 — a starts_with condition whose value is null or undefined throws a TypeError from value.toString() once searchByIndex runs it, either as the lead or through the lazy index switch at resources/search.ts:2092; when it only filters, it matches values beginning with the text "null"/"undefin
  • minor — resources/search.ts:71 — when OR branches constrain the same to-many relationship, selection projects related records from the first branch's slot only, so parents matched by a later branch come back with children: []
  • minor — resources/search.ts:2221 — conditionDrivesIndex re-walks descendant groups at every ancestor, so planning is O(depth²) in nesting depth
  • nit — unitTests/resources/estimateFilterOnlySibling.test.js:317 — comment cleanup is mostly done; the column-narration comment is still there

Not standing: 2 accepted-known. Grok ran 12m (13m from launch to report); the fold adjudication (cursor-grok@b1cdfad2fa38-48603d22, claude) took 1m.

Late Grok findings

2 surviving (highest major) — Grok reviewed 6aa3504, ruled against a36d1b7
  • major — resources/search.ts:2300 — Composite (array) primary keys: once an AND group with an infinite-estimate leg gets a finite estimate, the group can lead ahead of id = [...] (estimate 1, search.ts:2329). The id condition then becomes a post-filter. Equality compares with === against a freshly decoded array (search.ts:1938
  • major — resources/search.ts:1900 — Selection on an async to-many relationship still allocates a new (value) => value != null && match(value) arrow per parent row, plus the matchingIds closure at :1901. It could be hoisted once per condition. No measurement covers it, so the hot-path floor applies.

Not standing: 1 resolved. Grok ran 18m (18m from launch to report); the fold adjudication (cursor-grok@6aa3504fda13-83a12601, claude) took 1m.

Late Grok findings

1 surviving (highest major) — Grok reviewed cfda0d1
  • major — resources/search.ts:1880 — An AND group of two conditions on the same to-many relationship, placed inside an OR, now admits a parent whose related rows meet the conditions separately. When the label condition leads, its join is written to a fresh map (resources/search.ts:161), and the !inUnion gate keeps the tier conditio

Not standing: none. Grok ran 13m (14m from launch to report); the fold adjudication (cursor-grok@cfda0d1eedfc-775b5c75, claude) took 1m.

Late Grok findings

5 surviving (highest major) — Grok reviewed 1f74746
  • major — resources/search.ts:1885 — When two conditions on the same to-many relationship are ANDed inside an OR, they no longer have to be met by the same related record. Example: (children.label=sw=match & children.tier=gold) | id=nobody returns parent-3, because one of its children matches the label and a different child is gold
  • major — resources/Table.ts:7333 — The exemption that keeps a sort-aligned condition first only covers the synthetic sort pseudo-condition. A user's own condition on the sort attribute (e.g. priority=in=(1) with sort(priority)) cannot drive an index, so :7334 promotes a broader indexed condition ahead of it. Then :7427 sets
  • major — resources/search.ts:2356 — A multi-hop relationship path always returns false from conditionDrivesIndex, so when the estimate already sorted a relationship join first, findIndex at resources/Table.ts:7334 promotes any broader local driving condition ahead of it. Example: group='g1' (100 rows) displaces kids.name='a'
  • minor — resources/search.ts:2356 — A condition with attribute [] unwraps to undefined, which classifies it as driving the primary store, so it can be promoted to lead. Code-trace only: I did not confirm that searchByIndex then full-scans; reachability depends on a caller sending an empty path.
  • nit — resources/search.ts:160 — New comments at resources/search.ts:160, resources/search.ts:1884 and unitTests/resources/relationshipAsyncReads.test.js:418 repeat what resources/DESIGN.md:276 and the test title at :402 already say.

Not standing: none. Grok ran 15m (16m from launch to report); the fold adjudication (cursor-grok@1f74746b6a26-f10ad633, claude) took 1m.

Late Grok findings

3 surviving (highest major) — Grok reviewed eb07c09
  • major — resources/search.ts:1989 — With two AND conditions on the same to-one relationship, the id-set shortcut is turned off, so every candidate row loads its related record
  • nit — resources/search.ts:1016 — Added comments describe the code next to them
  • nit — resources/Table.ts:7389 — The sort-streaming exemption (syntheticOrderCondition / orderAlignedCondition) is not mentioned in resources/DESIGN.md. Grep finds both names only in Table.ts

Not standing: 1 merged. Grok ran 16m (16m from launch to report); the fold adjudication (cursor-grok@eb07c0931360-5eadf0c6, claude) took 1m.

Late Grok findings

1 surviving (highest minor) — Grok reviewed 7005532
  • minor — resources/Table.ts:7777 — In a nested select, two AND conditions that go through the same to-many relationship can still be satisfied by different related records. Top-level queries now require both conditions to match the same related record, so the two paths disagree

Not standing: 1 merged. Grok ran 18m (18m from launch to report); the fold adjudication (cursor-grok@700553240f78-8afde2c0, claude) took 1m.

Review-Coverage: authored=claude; ran=gemini,cursor-composer,codex,cursor-grok; pending=cursor-grok; late=cursor-grok:pending; adjudicated=domain,domain(codex); blocked=claude(fallback)(out-of-budget); declined=muse; rounds=32; full=10 @ 90ebd4e

Review-Attention: deep ~45m (critical: Table.ts, search.ts; decisions: same-record-and-semantics, or-condition-decides-rows-only, promote-driving-lead-unconditionally, and-estimate-ignores-filter-only, pr-scope, do-less-alternative, deferred-db316ad3) @ 90ebd4e

gemini-code-assist[bot]

This comment was marked as resolved.

kriszyp and others added 19 commits October 30, 2026 18:48
…stimate into Infinity

estimateCondition multiplied an AND group's running estimate by every
sub-estimate, so one filter-only leg (Infinity) made the whole group Infinity
(and 0 x Infinity NaN). orderConditions sorts a nested group's children
finite-first before the parent estimates it, which is the order that poisons
the group. SQL `!=` / NOT IN lower to such a group, so after a filter-only
predicate (IS NULL, LIKE '%x%', LIKE '%x') they failed 403 under
allowFullScan: false, nested FIQL AND groups did the same, and
count: 'estimated' reported null.

The intersection now skips non-finite sub-estimates; a group stays Infinity
only when every leg is.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Dispatch-Task: harper-estimate-and-infinite-sibling
(cherry picked from commit f8634f2)
…r gaps

Pin that the SQL cases run under allowFullScan: false, bound the REST
estimated total, drop comments that restate test names, and shrink the
DESIGN note to the invariant plus the known gaps (`in` / empty starts_with
estimate a finite cardinality yet full-scan; intersectionEstimate).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Dispatch-Task: harper-estimate-and-infinite-sibling
(cherry picked from commit eb1690c)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Dispatch-Task: harper-estimate-and-infinite-sibling
(cherry picked from commit 4931740)
… the test

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Dispatch-Task: harper-estimate-and-infinite-sibling
(cherry picked from commit e864fea)
…scan

`in`, an empty `starts_with` and a range on an unindexed attribute estimate a
finite count but searchByIndex answers them with a full scan, so they could lead
an AND ahead of an indexed sibling (403/404 under allowFullScan: false, a full
scan otherwise). `conditionDrivesIndex` mirrors searchByIndex's full-scan
decisions and is the first sort key in orderConditions; estimates are unchanged,
so count: 'estimated' and the lazy index switch read the same numbers.

Leading with the primary-key range exposed a nested relationship selection that
read `filtered[attribute]` once at preparation; a relationship condition that
filters registers it on its first match, so the selection now reads it per record.

Fixes #3725

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dispatch-Task: harper-3724-prfix-fold-3725
(cherry picked from commit 9ef7c46)
…index scan

searchByIndex resolves a `from` relationship on the local primary key with a
primary-store lookup, so conditionDrivesIndex must not require a secondary index
for it. Also trims comments that restated the sort keys.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dispatch-Task: harper-3724-prfix-fold-3725
(cherry picked from commit 1df7720)
searchByIndex full-scans the synthetic `sort` condition, so conditionDrivesIndex
now reports it as non-driving. orderConditions keeps main's rule for it: it leads
only when its estimate is below every other condition's. Ranking it above
non-driving legs dropped rows missing the sort attribute; ranking it below every
driving leg would lose index-order streaming of a sorted page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dispatch-Task: harper-3724-prfix-fold-3725
(cherry picked from commit 3d9ed2d)
Only the first AND condition executes as an index scan; the rest are record
filters that short-circuit in order. Instead of ranking every condition by
whether it can drive, orderConditions keeps the estimate order and moves the first
condition that can drive to the front, unless the synthetic sort already sorts
first. Plans match main whenever main's lead could already drive, and filters keep
their estimate order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dispatch-Task: harper-3724-prfix-fold-3725
(cherry picked from commit d3264d9)
…d and ready

searchByIndex rejects a full-text comparator whose @fulltext index is undeclared
(400) or not ready (IndexRebuildingError), so the lead must not go to it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dispatch-Task: harper-3724-prfix-fold-3725
(cherry picked from commit acbd60c)
…efixes out of the lead

A one-element `['id']` path seeks the primary store but estimated Infinity, so
leading with it handed its sibling filters an Infinity incoming count and the
lazy index switch fired on their first miss. A `starts_with` with a null or
undefined value cannot drive a scan. Also trims comments.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dispatch-Task: harper-3724-prfix-fold-3725
(cherry picked from commit b1cdfad)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dispatch-Task: harper-3724-prfix-fold-3725
(cherry picked from commit 0e74d46)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dispatch-Task: harper-3724-prfix-fold-3725
(cherry picked from commit cff9c78)
A relationship condition inside an OR group decides which rows match. It no
longer registers a select restriction (first branch won), no longer pushes its
related-level filter into a leading join on the same relationship, and an OR
branch's own leading join stays out of the AND scope's `filtered` map. The
related records a row selects now depend only on the AND scope's conditions,
not on which condition or branch runs first.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7groWP5o828Tt7QJHAnB2
Dispatch-Task: pr-maint-6969638615aeffe18e5ba9386e33648b
…d attribute as the primary key

Promoting a relationship condition to the lead changes which related record its
sibling conditions on that relationship must meet, so a row matched through
different related records disappeared. A relationship path no longer counts as
able to drive, which leaves its place in the estimate order as on main.

A finite group can now estimate below an implicit primary-key condition's 1 and
lead ahead of it, which demoted that condition to a filter reading
`record[undefined]`. `filterByType` now reads an omitted attribute as the primary
key, as `searchByIndex` does.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7groWP5o828Tt7QJHAnB2
Dispatch-Task: pr-maint-6969638615aeffe18e5ba9386e33648b
…ep a user sort-aligned lead

Excluding relationship paths from the lead promotion also let it displace a
relationship seek the estimate order had already put first. Promotion now skips
a query whose lead is a relationship condition (or a group holding one). A
user condition on the sort attribute that leads keeps its place when full scans
are allowed, as the synthetic sort does, so it still streams a sorted page.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7groWP5o828Tt7QJHAnB2
Dispatch-Task: pr-maint-6969638615aeffe18e5ba9386e33648b
…, and keep a sort-aligned lead unless full scans are forbidden

A group holding a relationship only as a later filter no longer blocks promotion,
which turned an indexed lead into a 403. A user condition on the sort attribute
keeps the lead whenever allowFullScan is not exactly false, as REST leaves it
unset. An empty attribute path is not the primary key.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7groWP5o828Tt7QJHAnB2
Dispatch-Task: pr-maint-6969638615aeffe18e5ba9386e33648b
…leton null path as the primary key

An OR group's branches never share a relationship join with their siblings, so
only an AND's executing lead decides whether promotion leaves the lead alone.
A one-element null attribute path now resolves to the primary key as an omitted
attribute does.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7groWP5o828Tt7QJHAnB2
Dispatch-Task: pr-maint-6969638615aeffe18e5ba9386e33648b
… an AND group by its executing lead

The relationship-lead exemption kept a lead whose scan was unusable under
allowFullScan false (a 404 where main found the row), and an AND group counted as
driving when any leg did, so a group led by a relationship join was promoted
ahead of a local index. Both now follow the group's first ordered condition.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7groWP5o828Tt7QJHAnB2
Dispatch-Task: pr-maint-6969638615aeffe18e5ba9386e33648b
…stating comments

A two-hop path was always classified as unable to run, so a broader local index
displaced a relationship lead and admitted a parent whose employees met the two
conditions separately. Each hop's local join index and the leaf's scan are now
checked.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7groWP5o828Tt7QJHAnB2
Dispatch-Task: pr-maint-6969638615aeffe18e5ba9386e33648b
kriszyp and others added 12 commits October 30, 2026 18:48
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7groWP5o828Tt7QJHAnB2
Dispatch-Task: pr-maint-6969638615aeffe18e5ba9386e33648b
… the DESIGN.md budget

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7groWP5o828Tt7QJHAnB2
Dispatch-Task: pr-maint-6969638615aeffe18e5ba9386e33648b
…ted record whichever leads

The first non-leading condition on a to-many relationship registers the whole
set of sibling filters and the rest only add to it, as a leading join already
takes them, so rows no longer depend on the lead. An AND inside an OR gets its
own scope; a condition in an OR still decides rows only.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7groWP5o828Tt7QJHAnB2
…a runnable relationship scan drive

Sibling filters of a relationship now live in a per-scope registry under a symbol key,
so a relationship named like the maps that track relationships, and a to-one hop before a
to-many one, meet one related record too. conditionDrivesIndex asks relationshipScanRuns
for a related path, which replaces the lead-retention special case in orderConditions and
lets a runnable relationship scan pass an `in` that would full-scan.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7groWP5o828Tt7QJHAnB2
…y be named like the maps that track them

relationshipRestriction now reads a symbol-keyed registry instead of string-keyed own
properties of the join and selection maps, so a relationship named filters, get or
fromRecord no longer collides with their members, and a promoted two-hop lead no longer
pushes a sibling filter into a Map. The promotion loop and the relationship scan check
no longer allocate, and a later sibling of a shared relationship does not build an id set.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7groWP5o828Tt7QJHAnB2
… two planning callbacks

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7groWP5o828Tt7QJHAnB2
…s keep their id shortcut

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7groWP5o828Tt7QJHAnB2
…e the relationship

A key condition among several conditions on one to-many relationship now rejects
a record before any related record loads, and the whole set still decides for the rest.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7groWP5o828Tt7QJHAnB2
…me related record

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7groWP5o828Tt7QJHAnB2
…s a relationship

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7groWP5o828Tt7QJHAnB2
…ed-filter fixtures

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7groWP5o828Tt7QJHAnB2
@kriszyp
kriszyp force-pushed the fix/estimate-condition-filter-only-sibling branch from b822e44 to ac43c5a Compare October 31, 2026 01:21
…elationship

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7groWP5o828Tt7QJHAnB2
@kriszyp
kriszyp merged commit 509ff2c into main Nov 2, 2026
97 of 102 checks passed
@kriszyp
kriszyp deleted the fix/estimate-condition-filter-only-sibling branch November 2, 2026 12:07
kriszyp added a commit that referenced this pull request Nov 2, 2026
…ilings

Dispatch-Task: pr-maint-4ea3ff57cdacd1640c5b5f6e1f084d80

Co-Authored-By: Gemini <noreply@google.com>
kriszyp added a commit that referenced this pull request Nov 2, 2026
…ilings

Dispatch-Task: pr-maint-4ea3ff57cdacd1640c5b5f6e1f084d80

Co-Authored-By: Gemini <noreply@google.com>
kriszyp added a commit that referenced this pull request Nov 2, 2026
…/DESIGN.md from 339 KB to 44 KB of invariant notes (#3856)

* Load a resources/ concept map with the first file read, and trim resources/DESIGN.md to its invariants

resources/DESIGN.md had grown to 339 KB, mostly symbol inventory and
incident narrative. It is now 40 KB of invariant notes, one per original
heading: the rule, why it holds, the enforcing symbol and the pinning test.
Navigation moves to resources/MAP.md, which resources/CLAUDE.md imports so
Claude Code loads it on the first read in the directory; AGENTS.md lists
the map for agents that do not load subdirectory CLAUDE.md files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dispatch-Task: harper-resources-design-map-trim

* Restore the negative and cross-symbol rules review found missing from resources/DESIGN.md

Corrects the commit-clock statement (the per-attempt clock drives load
shedding), the equal-version walk rule, the full-PUT fallback on an
invalidated head, the sharding switch prerequisites and LMDB write
takeover; restores dropped rules such as primitive-get exact-class
matching, X-Replicate-From staying open, copy bounds before rows and the
registration-boundary exceptions. Folds four one-line notes into their
neighbours and shortens headings only the root index links.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dispatch-Task: harper-resources-design-map-trim

* Restore the remaining failure-guarding rules review round 2 named in resources/DESIGN.md

Single-record resumes check only the generation, listeners never wait on
the source commit, a read verdict names its gate, readableInFull proofs
stay within one permission source, received-key dedup skips unnamed ids,
and the struct-mode note keeps its structon companion.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dispatch-Task: harper-resources-design-map-trim

* Qualify the cached-read options rule in resources/DESIGN.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dispatch-Task: harper-resources-design-map-trim

* List the write.skipped outcomes and the attribute-slot acknowledgement in resources/DESIGN.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dispatch-Task: harper-resources-design-map-trim

* Restore the replica-walk, branch-ref and single-record-resume details review round 4 named

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dispatch-Task: harper-resources-design-map-trim

* Say the replica audit walk continues after commit

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dispatch-Task: harper-resources-design-map-trim

* Compact #3724's estimator and relationship notes and lower #3857's ceilings

Dispatch-Task: pr-maint-4ea3ff57cdacd1640c5b5f6e1f084d80

Co-Authored-By: Gemini <noreply@google.com>

* Restore gap qualifications and map attributions from review

Dispatch-Task: pr-maint-4ea3ff57cdacd1640c5b5f6e1f084d80
Co-Authored-By: Gemini <noreply@google.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Gemini <noreply@google.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant