Skip to content

feat: test environment mode for historical pathfinding#16

Open
leinss wants to merge 5 commits into
mainfrom
feature/tx-simulator
Open

feat: test environment mode for historical pathfinding#16
leinss wants to merge 5 commits into
mainfrom
feature/tx-simulator

Conversation

@leinss

@leinss leinss commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds a "Test Environment" toggle to the path builder form for querying the pathfinder against historical blockchain state at a specific block number
  • Auto-creates test-env sessions, reuses across queries, shows session status (block, expiry)
  • Routes circlesV2_findPath calls through the test-env RPC proxy (which adds X-Max-Block-Number header)
  • Mutually exclusive with staging mode

New files

  • testEnvService.js — session lifecycle management (create, destroy, health, block check)

Key details

  • BigInt-safe response handling via stringifyBigInts
  • All FlowRequest parameters supported including simulatedConsentedAvatars
  • Null-result guard for empty RPC responses
  • Single source of truth for DEFAULT_TEST_ENV_URL
  • Session object explicitly constructed (no server field collision risk)

Known v1 limitations (documented in code)

  • Post-pathfinding enrichment (token info, profiles) still uses production endpoints
  • No abort/cancellation on concurrent requests (pre-existing pattern)

Related PRs

Test plan

  • Toggle "Test Environment" — block number and URL fields appear
  • Enter block number, click Find Path — session created, path computed
  • Session status shows block number and expiry time
  • Second query at same block reuses session (no new creation)
  • Changing block number creates new session
  • Invalid block number shows error warning
  • Toggling staging disables test-env (mutually exclusive)

leinss added 3 commits April 15, 2026 10:18
Adds a "Test Environment" toggle to the path builder form that enables
querying the pathfinder against historical blockchain state at a
specific block number.

- testEnvService.js: session management (create, destroy, health check)
- circlesApi.js: findPathViaTestEnv sends circlesV2_findPath through
  test-env RPC proxy (which adds X-Max-Block-Number header)
- PathFinderForm: test-env toggle, URL input, block number input,
  session status indicator
- FlowVisualization: auto-creates session on first query, reuses for
  subsequent queries, shows warnings on error

The test-env mode is mutually exclusive with staging mode.
Session auto-extends TTL on each query and expires after 30m idle.
- Add missing simulatedConsentedAvatars to findPathViaTestEnv
- Add BigInt-safe response handling (stringifyBigInts on RPC result)
- Validate targetFlow with String(BigInt()) before sending
- Add error logging (console.error) in findPathViaTestEnv
- Remove dead code: sessionTimer, sendRpcRequest
- Consolidate DEFAULT_TEST_ENV_URL to single source (circlesApi.js)
- Explicitly construct session object instead of spreading server response
- Validate sessionId exists before constructing rpcProxyUrl
- Add resolveBaseUrl helper to eliminate URL normalization duplication
- Guard against undefined rpcResponse.result in findPathViaTestEnv
- Log warning on session destroy failure (was silently swallowed)
@coderabbitai

coderabbitai Bot commented Apr 15, 2026

Copy link
Copy Markdown

Summary by CodeRabbit

  • New Features
    • Added Test Environment mode to enable historical pathfinding with customizable URL and block number inputs.
    • Session management support with status display (block number and expiration time) and close functionality.
    • Automatic session creation and reuse to optimise test environment operations.
    • Form validation warnings when required test environment fields are incomplete.

Walkthrough

Test-environment mode added to pathfinding: new form fields and handlers let users enable a test RPC proxy and specify URL/block. A test-env session is created/reused via a new service, session lifecycle is managed, and pathfinding calls route through the session's RPC proxy when enabled.

Changes

Cohort / File(s) Summary
UI Components
src/components/CollapsibleLeftPanel.jsx, src/components/PathFinderForm.jsx, src/components/FlowVisualization.jsx
Added UI for Test Environment (toggle, URL, block number). Prop interfaces extended to pass new handlers and testEnvSession/onDestroySession. FlowVisualization implements session lifecycle (getOrCreateSession/destroySession) and alters executeFindPath to use test-env session when enabled.
Form State Management
src/hooks/useFormData.js
Added defaults for UseTestEnv, TestEnvUrl (using DEFAULT_TEST_ENV_URL), and TestEnvBlockNumber. Added handlers handleTestEnvToggle, handleTestEnvUrlChange, handleTestEnvBlockNumberChange. Enforced staging/test-env interdependency (enabling test-env auto-enables staging; disabling staging clears UseTestEnv).
API / Services
src/services/circlesApi.js, src/services/testEnvService.js
Added DEFAULT_TEST_ENV_URL. circlesApi now short-circuits to a test-env path (findPathViaTestEnv) when UseTestEnv is true and requires testEnvSession. New testEnvService.js manages session creation/reuse/destruction, block checks, latest block, and health endpoints; exposes getOrCreateSession, destroySession, getActiveSession, checkBlockExists, getLatestBlock, getTestEnvHealth.
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: test environment mode for historical pathfinding' clearly and concisely summarizes the primary change: adding a test environment feature for historical pathfinding. It is directly related to all substantial changes in the changeset.
Description check ✅ Passed The description thoroughly documents the changes, including summary of the feature, new files, key implementation details, known limitations, related PRs, and a test plan. It is clearly related to the changeset and provides meaningful information about what was implemented.
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/tx-simulator

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai 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.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/FlowVisualization.jsx`:
- Around line 427-435: The code only checks that baseData.TestEnvBlockNumber is
non-empty but then calls getOrCreateSession(Number(...)) without validating
format; update the FlowVisualization.jsx logic before calling getOrCreateSession
to validate baseData.TestEnvBlockNumber is a whole non-negative integer (e.g.,
parse with parseInt/Number, ensure Number.isInteger and value >= 0 and not NaN),
and if invalid call setFormWarnings(['Enter a valid non-negative integer block
number for test environment mode']) and return; keep existing call to
getOrCreateSession with the validated numeric block number.
- Around line 425-443: The test-env session logic is only applied in
handleFindPath, so other callers of executeFindPath (e.g., quick-filter
auto-search) omit testEnvSession and bypass test mode; move the TestEnv handling
into executeFindPath itself (or add a small helper called by every caller) so
executeFindPath will: if baseData.UseTestEnv is true, validate
TestEnvBlockNumber, call getOrCreateSession(baseData.TestEnvUrl,
Number(baseData.TestEnvBlockNumber)), call setTestEnvSession(session) on
success, and include testEnvSession on the request payload; on error call
setFormWarnings([...]) and setTestEnvSession(null). Update executeFindPath
callers to stop duplicating this logic if present.

In `@src/services/circlesApi.js`:
- Around line 115-117: When formData.UseTestEnv is true but
formData.testEnvSession is missing, do not fall through to the live/staging RPC;
instead detect this condition near the existing check that calls
findPathViaTestEnv(formData) and explicitly fail (throw an Error or return a
rejected Promise) with a clear message (e.g., "testEnvSession required when
UseTestEnv is true") so callers cannot silently get live data; update the branch
that currently returns findPathViaTestEnv to first validate testEnvSession and
only call findPathViaTestEnv when present, otherwise throw/return the explicit
failure.

In `@src/services/testEnvService.js`:
- Around line 21-23: The code converts blockNumber with Number(blockNumber) into
numBlock without validation, allowing NaN, decimals or negatives; update the
session-creation logic (where const numBlock = Number(blockNumber)) to validate
blockNumber first: parse/convert to an integer, ensure it's a finite integer (no
decimals), >= 0, and not NaN, and if invalid return/throw a clear client-side
error before calling resolveBaseUrl/test-env session creation; apply the same
validation to the other occurrence around lines 41-44 so both code paths reject
invalid block numbers early.
- Around line 81-85: The DELETE fetch call to
`${baseUrl}/api/v1/session/${sessionId}` currently ignores non-2xx responses;
change it to capture the response (const res = await fetch(...)), check res.ok,
and when false log a failure including res.status, res.statusText and response
body (await res.text() or JSON) for debugging and then throw or handle as an
error so it flows into the existing catch; update the log message that
references sessionId to include those response details.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 97ab9f73-afeb-424c-b258-bfdfa476660a

📥 Commits

Reviewing files that changed from the base of the PR and between c8c51e6 and b8b66fa.

📒 Files selected for processing (6)
  • src/components/CollapsibleLeftPanel.jsx
  • src/components/FlowVisualization.jsx
  • src/components/PathFinderForm.jsx
  • src/hooks/useFormData.js
  • src/services/circlesApi.js
  • src/services/testEnvService.js

Comment thread src/components/FlowVisualization.jsx Outdated
Comment thread src/components/FlowVisualization.jsx Outdated
Comment thread src/services/circlesApi.js Outdated
Comment on lines +21 to +23
const baseUrl = resolveBaseUrl(testEnvUrl);
const numBlock = Number(blockNumber);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Validate block number before creating a test-env session.

Line 22 accepts any Number(...) value. Invalid values (NaN, decimal, negative) should be rejected client-side before sending the session-create request.

Suggested fix
 export async function getOrCreateSession(testEnvUrl, blockNumber) {
   const baseUrl = resolveBaseUrl(testEnvUrl);
   const numBlock = Number(blockNumber);
+  if (!Number.isInteger(numBlock) || numBlock < 0) {
+    throw new Error('Block number must be a non-negative integer');
+  }

Also applies to: 41-44

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/services/testEnvService.js` around lines 21 - 23, The code converts
blockNumber with Number(blockNumber) into numBlock without validation, allowing
NaN, decimals or negatives; update the session-creation logic (where const
numBlock = Number(blockNumber)) to validate blockNumber first: parse/convert to
an integer, ensure it's a finite integer (no decimals), >= 0, and not NaN, and
if invalid return/throw a clear client-side error before calling
resolveBaseUrl/test-env session creation; apply the same validation to the other
occurrence around lines 41-44 so both code paths reject invalid block numbers
early.

Comment thread src/services/testEnvService.js Outdated
Comment on lines +81 to +85
await fetch(`${baseUrl}/api/v1/session/${sessionId}`, { method: 'DELETE' });
} catch (err) {
// Non-fatal — session will expire via TTL, but log for debugging
console.warn(`Failed to destroy test-env session ${sessionId}:`, err.message);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Log non-2xx session-destroy responses as failures.

At Line 81-85, HTTP error statuses are not treated as failures, so server-side destroy errors can pass silently.

Suggested fix
   try {
-    await fetch(`${baseUrl}/api/v1/session/${sessionId}`, { method: 'DELETE' });
+    const response = await fetch(`${baseUrl}/api/v1/session/${sessionId}`, { method: 'DELETE' });
+    if (!response.ok) {
+      const detail = await response.text().catch(() => '');
+      console.warn(`Failed to destroy test-env session ${sessionId}: HTTP ${response.status}${detail ? ` — ${detail}` : ''}`);
+    }
   } catch (err) {
     // Non-fatal — session will expire via TTL, but log for debugging
     console.warn(`Failed to destroy test-env session ${sessionId}:`, err.message);
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/services/testEnvService.js` around lines 81 - 85, The DELETE fetch call
to `${baseUrl}/api/v1/session/${sessionId}` currently ignores non-2xx responses;
change it to capture the response (const res = await fetch(...)), check res.ok,
and when false log a failure including res.status, res.statusText and response
body (await res.text() or JSON) for debugging and then throw or handle as an
error so it flows into the existing catch; update the log message that
references sessionId to include those response details.

leinss added 2 commits April 15, 2026 12:51
… routing

- Move test-env session management from handleFindPath into executeFindPath
  so all callers (quick-filter, auto-search) correctly route through test-env
- Validate block number as non-negative integer before session creation
- Throw explicitly when UseTestEnv is true but no session attached (prevent
  silent fallback to live RPC)
- Log non-2xx responses on session DELETE for debugging
- Only show Test Environment toggle when Use Staging is enabled
- Auto-enable staging when test-env is toggled on
- Normalize persisted form state (test-env implies staging)
- Add Close button to manually destroy session and free a slot
- Show TTL/max-sessions info when no session is active
- Surface max-sessions-reached error with actionable hint
- Muted session indicator styling (gray instead of bright green)

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/FlowVisualization.jsx`:
- Around line 361-372: The current try/catch wraps both getOrCreateSession and
loadPathData so any loadPathData failure is misreported as a session error;
change it to try/catch only around getOrCreateSession (call getOrCreateSession,
setTestEnvSession(session) inside that try) and keep the existing error handling
with the isMaxSessions hint and setTestEnvSession(null) only in that catch; then
call await loadPathData({...requestData, testEnvSession: session}) outside that
catch so its errors propagate through the normal request error path (do not
clear setTestEnvSession on loadPathData failures).
- Around line 376-377: The code currently only clears the local reference via
setTestEnvSession(null) and then calls loadPathData(requestData), leaving the
remote test session alive; update the logic to first check the existing test
session (the state referenced by setTestEnvSession/testEnvSession) and call its
shutdown method (e.g., destroy/close/terminate API on that session) and await
its completion, handling errors, before nulling it and calling loadPathData;
also add the same teardown when toggling UseTestEnv/UseStaging off in
PathFinderForm (watch the toggles and destroy the live session on exit) so no
orphaned server sessions remain.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 817218f3-fcfa-49cb-a096-ba12759d09d2

📥 Commits

Reviewing files that changed from the base of the PR and between b8b66fa and 153f6b5.

📒 Files selected for processing (6)
  • src/components/CollapsibleLeftPanel.jsx
  • src/components/FlowVisualization.jsx
  • src/components/PathFinderForm.jsx
  • src/hooks/useFormData.js
  • src/services/circlesApi.js
  • src/services/testEnvService.js
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/components/PathFinderForm.jsx
  • src/services/circlesApi.js
  • src/services/testEnvService.js

Comment on lines +361 to +372
try {
const session = await getOrCreateSession(requestData.TestEnvUrl, parsedBlock);
setTestEnvSession(session);
await loadPathData({ ...requestData, testEnvSession: session });
} catch (err) {
const isMaxSessions = err.message.includes('Maximum concurrent sessions');
const hint = isMaxSessions
? ' — close unused sessions or wait for them to expire (30 min TTL).'
: '';
setFormWarnings([`Test-env session error: ${err.message}${hint}`]);
setTestEnvSession(null);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Separate session creation failures from query failures.

loadPathData(...) is inside the same try as getOrCreateSession(...), so any downstream RPC/pathfinder failure is reported as a test-env session error and testEnvSession is cleared even though the session was created successfully. Catch only the session acquisition step here and let query failures surface through the normal request error path.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/FlowVisualization.jsx` around lines 361 - 372, The current
try/catch wraps both getOrCreateSession and loadPathData so any loadPathData
failure is misreported as a session error; change it to try/catch only around
getOrCreateSession (call getOrCreateSession, setTestEnvSession(session) inside
that try) and keep the existing error handling with the isMaxSessions hint and
setTestEnvSession(null) only in that catch; then call await
loadPathData({...requestData, testEnvSession: session}) outside that catch so
its errors propagate through the normal request error path (do not clear
setTestEnvSession on loadPathData failures).

Comment on lines +376 to 377
setTestEnvSession(null);
await loadPathData(requestData);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Destroy the live session when leaving test-env mode.

This branch only clears the local reference. Because PathFinderForm hides the session UI as soon as UseTestEnv is off, any still-live server session becomes unreachable and continues consuming one of the limited session slots until TTL expiry. Tear the session down before hiding the mode, or watch UseTestEnv/UseStaging and destroy on exit.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/FlowVisualization.jsx` around lines 376 - 377, The code
currently only clears the local reference via setTestEnvSession(null) and then
calls loadPathData(requestData), leaving the remote test session alive; update
the logic to first check the existing test session (the state referenced by
setTestEnvSession/testEnvSession) and call its shutdown method (e.g.,
destroy/close/terminate API on that session) and await its completion, handling
errors, before nulling it and calling loadPathData; also add the same teardown
when toggling UseTestEnv/UseStaging off in PathFinderForm (watch the toggles and
destroy the live session on exit) so no orphaned server sessions remain.

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