Skip to content

Commit 9eadd50

Browse files
mo4islonaclaude
andcommitted
chore(portal): wave-4 dead-code removal and simplifications
Removes the verified-dead code and never-fire machinery from the wave-4 review; no behavior change on any production path. Deletions (grep-verified zero importers): - portal/realtime.ts + realtime.test.ts — the RPC endpoint-probe module; nothing imported it and it shipped in the published npm artifact. - portal/config.ts — the pre-wiring-patch injection path; sync-upstream.sh already annotated it "(deleted)" and excluded it from the graft. Its sole remaining importer, harness/compat/analyze.test.ts's withPortal case, is dropped with it (getPortalDataset/withPortal were used only there) so the repo-root `node --test harness/compat/*.test.ts` job stays green. - StateDiff/toStateDiff + statediffs.json fixture — no producer or consumer. - DiscoveryState.status — written on every transition, read by nothing (and wrong as telemetry under chained extensions). - checksEnabled/checksStrict — unreferenced invariant-mode helpers. - rankTraces' strict INV-5 assert — ranks are strictly increasing by construction (the forEach counter); same rationale as INV-2's deliberately-omitted per-row assert. INVARIANTS.md cell updated. Simplifications: - reconcile()/portalRealtimeEvents' anchor is REQUIRED — the optional legacy mode preserved exactly the blind-append hole INV-10 closed, and production always passed an anchor. - FinalizedHead collapses to { number, hash? } (the bare-number variant was test-only). - streamHotBlocks' inline field-projection fallbacks are replaced by the shared BLOCK_FIELDS/LOG_FIELDS constants (single source, no drift). - traceSafeChunkBlocks loses its "compat" re-export in portal-transform and its env-reading default parameter (INV-14: env is parsed once into PortalConfig; the shell always passes cfg.traceChunkBlocks). - STREAM_REALTIME drops the always-true Boolean(chain.portal) conjunct. Graft suite green on 0.16.6 and 0.15.17 (15 files, 205 tests each); harness/compat green (6 tests, the withPortal case dropped with config.ts). Portal-layer coverage +1.0 stmts (the dead module leaves the denominator). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 06b9f99 commit 9eadd50

18 files changed

Lines changed: 76 additions & 545 deletions

PUBLISHING.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ field per chain that routes the historical backfill through SQD Portal (realtime
1414
- **We don't hand-maintain a fork.** This repo holds only the **Portal layer** (`portal/`): the
1515
`portal-*.ts` modules (an invariant-first functional core behind the `portal.ts` shell — see
1616
`portal/INVARIANTS.md`) + a per-version `wiring/<ver>.patch` (the 4 one-line touch-points). That's
17-
the entire diff against upstream. (`portal/config.ts` is a repo-side compat-harness utility — not
18-
part of the published build.)
17+
the entire diff against upstream.
1918
- **The fork is generated.** `scripts/sync-upstream.sh <ver>` clones `ponder@<ver>`, applies the layer,
2019
renames the package, and builds — producing the publishable package. Tracking a new ponder version is
2120
"author one small patch + run the script", not "merge a fork".

harness/compat/analyze.test.ts

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import assert from 'node:assert';
22
import { test } from 'node:test';
3-
import { getPortalDataset, withPortal } from '../../portal/config.ts';
43
import { analyzeConfig } from './analyze.ts';
54
import type { DatasetInfo } from './datasets.ts';
65

@@ -93,22 +92,3 @@ test('block-range caveat note surfaced (Optimism Bedrock)', () => {
9392
assert.equal(s.verdict, 'READY');
9493
assert.ok(s.notes.some((n) => n.includes('Bedrock')));
9594
});
96-
97-
test('withPortal: extracts portal into registry and strips it from the chain', () => {
98-
const cfg: any = {
99-
chains: {
100-
mainnet: {
101-
id: 1,
102-
rpc: 'x',
103-
portal: 'https://portal.sqd.dev/datasets/ethereum-mainnet',
104-
},
105-
},
106-
};
107-
withPortal(cfg);
108-
assert.equal(
109-
getPortalDataset(1),
110-
'https://portal.sqd.dev/datasets/ethereum-mainnet',
111-
);
112-
assert.equal(cfg.chains.mainnet.portal, undefined);
113-
assert.equal(cfg.chains.mainnet.rpc, 'x');
114-
});

portal/INVARIANTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Legacy `C#` tags from the pre-refactor comments are mapped where they existed.
2020
| **INV-2** (was C9 range) | **Interval exactness.** `syncBlockRangeData([lo,hi])` returns exactly the rows with `lo ≤ blockNumber ≤ hi` from its chunks — no leakage outside, no omission inside. | Chunks are wider than intervals; only the interval's rows may be written. | ENFORCED BY CONSTRUCTION: one pure `assembleRange()` where every emitting branch sits behind the single `inRange` predicate (deliberately no redundant per-row assert — it could never fire). || `portal-assemble.test.ts` — "INV-2: assembleRange returns exactly the in-range logs (vs brute-force filter)", "INV-2: trace assembly respects the interval's UPPER bound". |
2121
| **INV-3** (was C4 floor) | **Discovery-before-data.** A chunk's data request is issued only after factory discovery is complete through that chunk's last block. **A failed scan never advances the watermark, and a successor extension chained on a failing scan rejects rather than confirming over the gap** (fixes **G2**, incl. the interleaving hole found in review). | Data chunks are fetched out of order; a child created below a chunk must be known before that chunk fetches, else its logs are missed. An extension only scans `[through+1, to]` — swallowing a predecessor failure would certify coverage over an unscanned hole. | `portal-discovery.ts`: `await discovery.ensure(chunkTo)` precedes the fetch; `confirmed` advances ONLY on scan success; a failure rolls `through` back to `confirmed`; a predecessor failure PROPAGATES through the chain (`await earlier` — never swallowed) and the rejected promise is replaced. The floor that makes `ensure` actually scan is pinned from the SPEC at construction (`pinDiscoveryFloor`, FIX 2), so an early spanning-chunk fetch issued BEFORE `requiredFactoryIntervals` still discovers. | `portal.ts` asserts `discovery.through() ≥ desiredTo` after the await (fresh fetch AND extend); the former `discStartIdx === undefined` ESCAPE on both asserts is gone (FIX 2) — the check now fires on the very early-fetch case it used to skip. | `portal-discovery.test.ts` — "INV-3/G2: a failed scan rolls the watermark back; a later ensure recovers", "INV-3/G2 interleaving: a successor extension rejects when its in-flight predecessor fails — never confirms over the gap", "INV-3 property: random ensures + injected window failures → coverage below through() is always complete; retry converges"; `portal.test.ts` — "regression (FIX 2, BUG-A): an EARLY spanning-chunk fetch with requiredFactoryIntervals=[] still runs discovery…". |
2222
| **INV-4** (was C4) | **Earliest-creation child map.** `childAddresses[factory][child] = min(creation blocks seen)`; the floor clamps DOWNWARD. | Discovery windows are shuffled/overlapping and run concurrently; the child's earliest creation block must be recorded regardless of order. | `portal-discovery.ts` min-merges `rec.set(child, min(prev, bn))`; `portal.ts` lowers `discFloorBlock` monotonically (block-space; survives a grid rescale — FIX 2). | — (pure convergence) | `portal-discovery.test.ts` — "INV-4: shuffled/overlapping discovery windows converge to the same earliest-creation map". |
23-
| **INV-5** (was C6) | **Full-tree trace ranking.** `trace_index` = pre-order DFS rank over the transaction's FULL trace set; the Portal trace request carries NO trace filter (fetch-all); matching is applied only AFTER ranking. | Ponder's RPC path numbers EVERY frame then filters, so a matched trace keeps its full-tree position; a server-side trace filter would rank over the matched subset (a lone deep match → 0 instead of 7). | `rankTraces(allTraces) → RankedTrace[]` is the only producer the matcher accepts; `FetchSpec.traceQuery()` has no filter params. | `rankTraces` asserts per-tx ranks strictly increasing (`strict` mode — O(n)). | `portal-assemble.test.ts` — "INV-5: rankTraces sorts into pre-order DFS…"; `portal-filters.test.ts` — "INV-5 support: the trace request carries NO trace filter (fetch-all)"; `portal.test.ts` — "regression (C6): deep matched trace… index 7". |
23+
| **INV-5** (was C6) | **Full-tree trace ranking.** `trace_index` = pre-order DFS rank over the transaction's FULL trace set; the Portal trace request carries NO trace filter (fetch-all); matching is applied only AFTER ranking. | Ponder's RPC path numbers EVERY frame then filters, so a matched trace keeps its full-tree position; a server-side trace filter would rank over the matched subset (a lone deep match → 0 instead of 7). | `rankTraces(allTraces) → RankedTrace[]` is the only producer the matcher accepts; `FetchSpec.traceQuery()` has no filter params. | — (rank = position in the sorted list, strictly increasing BY CONSTRUCTION; the former `strict` assert could never fire and was removed in wave 4 — same rationale as INV-2's deliberately-omitted per-row assert). | `portal-assemble.test.ts` — "INV-5: rankTraces sorts into pre-order DFS…"; `portal-filters.test.ts` — "INV-5 support: the trace request carries NO trace filter (fetch-all)"; `portal.test.ts` — "regression (C6): deep matched trace… index 7". |
2424
| **INV-6** | **RPC-shape byte-identity of transforms.** Transform outputs are byte-equal to the RPC path's encodings (hex quantities, casing, null/undefined, accessList normalization, status mapping). | The sync store must be byte-identical whether backfilled from Portal or RPC. | Pure `portal-transform.ts` functions calibrated against captured fixtures. | — (external differential gate) | `portal-transform.test.ts` (golden fixtures + `hx` totality); external `harness/diff`. |
2525
| **INV-7** | **Bounded buffered rows.** Row-count is conservative — rows are registered as NDJSON batches ARRIVE (fixes **G3**), freed exactly once on eviction/rejection; `rows ≥ 0` always; read-ahead beyond depth-1 admits only when not saturated. | In-flight NDJSON arrays were invisible to backpressure; the memory cap must engage before the heap dies. | `portal-client.ts` `onRows` hook per batch; `portal.ts` keys accounting to a per-fetch `RowToken` freed exactly once (idempotent — a stale evicted fetch can neither register nor free against its replacement); the gate reducer clamps `rows ≥ 0`. | `gateReduce` asserts `rows ≥ 0`. | `portal-gate.test.ts` — "INV-8/INV-7: bounds hold under arbitrary event sequences"; `portal-client.test.ts` — "G3: onRows is called once per yielded batch, mid-stream"; `portal-shell.test.ts` — "G3: buffered rows are visible to the gate MID-CHUNK", "S1: rows return to baseline after chunks settle and are evicted". |
2626
| **INV-8** | **AIMD bounds.** `MIN ≤ limit ≤ MAX`; `active ≥ 0`; admission only while `active < limit`; waiters are FIFO and drained whenever capacity exists (no starvation) — including when a RAMP raises the limit. | The shared endpoint's live capacity is discovered by AIMD; the controller must never exceed its own bounds or starve a waiter. | Pure reducer `gateReduce(state, event) → state`; the shell pumps FIFO on release AND onOk. | `gateReduce` asserts `MIN ≤ limit ≤ MAX` and `active ≥ 0`. | `portal-gate.test.ts` — "INV-8/INV-7: bounds hold under arbitrary event sequences", "createGate: FIFO admission, no starvation while capacity exists", "createGate: an AIMD ramp PUMPS parked waiters". |

portal/__fixtures__/statediffs.json

Lines changed: 0 additions & 1 deletion
This file was deleted.

portal/config.ts

Lines changed: 0 additions & 43 deletions
This file was deleted.

portal/portal-assemble.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ import {
3232
} from '@/runtime/filter.js';
3333
import type { Interval } from '@/utils/interval.js';
3434
import type { ChildAddresses, FetchSpec } from './portal-filters.js';
35-
import { invariantStrict } from './portal-invariant.js';
3635
import {
3736
cmpTraceAddr,
3837
hx,
@@ -91,17 +90,15 @@ export function rankTraces(traces: RawTrace[]): RankedTrace[] {
9190
const sorted = [...traces].sort((x, y) =>
9291
cmpTraceAddr(x.traceAddress ?? [], y.traceAddress ?? []),
9392
);
93+
// Ranks are strictly increasing BY CONSTRUCTION (each rank is the forEach counter of a monotonically
94+
// walked array) — the same "an assert that could never fire" INV-2 deliberately omits, so none here
95+
// either (wave 4; the property is proven in portal-assemble.test.ts).
9496
const out: RankedTrace[] = [];
9597
sorted.forEach((t, i) => {
9698
const frame = parityToCallFrame(t, i) as CallFrame | undefined;
9799
if (frame) out.push({ frame, index: i });
98100
});
99-
invariantStrict(
100-
'INV-5',
101-
() => out.every((r, i) => i === 0 || r.index > out[i - 1]!.index),
102-
'trace ranks not strictly increasing',
103-
() => ({ ranks: out.map((r) => r.index) }),
104-
);
101+
105102
return out;
106103
}
107104

portal/portal-chunks.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,14 @@ export const scaleChunkBlocks = (base: number, head: number): number => {
4545
* cap is conservative. When a chain has trace (or includeAllBlocks) sources, cap the chunk to a
4646
* trace-safe width (`PORTAL_TRACE_CHUNK_BLOCKS`, default 2k).
4747
*
48-
* NOTE: this is the canonical home; `portal-transform.ts` re-exports it for compat. The `cap`
49-
* default reads env for the standalone signature — the shell always passes `cfg.traceChunkBlocks`.
48+
* The cap always comes from the caller (`cfg.traceChunkBlocks` — env is parsed ONCE into the
49+
* validated PortalConfig, INV-14); the old env-reading default parameter here was dead in
50+
* production and reintroduced the exact silent-NaN shape INV-14 was written to kill.
5051
*/
5152
export const traceSafeChunkBlocks = (
5253
base: number,
5354
needTraces: boolean,
54-
cap = Number(process.env.PORTAL_TRACE_CHUNK_BLOCKS ?? 2_000),
55+
cap: number,
5556
): number => (needTraces && base > cap ? cap : base);
5657

5758
/**

0 commit comments

Comments
 (0)