Skip to content

YNU-900: stamp application_id on writes and expose via SDKs#696

Open
philanton wants to merge 4 commits intomainfrom
feat/app-id-transactions
Open

YNU-900: stamp application_id on writes and expose via SDKs#696
philanton wants to merge 4 commits intomainfrom
feat/app-id-transactions

Conversation

@philanton
Copy link
Copy Markdown
Contributor

@philanton philanton commented Apr 20, 2026

Summary

  • Treat ?app_id= on the WebSocket upgrade as an advisory origin tag: clearnode reads it in ServeHTTP, stores it in per-connection SafeStorage, and stamps it onto channel_states.application_id and transactions.application_id (nullable VARCHAR(66)) for writes originating from client requests.
  • App-session handlers use the session's own ApplicationID rather than the connection tag. rebalance_app_sessions now rejects batches that mix sessions from different applications.
  • Metrics user_states_total, transactions_total, transactions_amount_total carry an application_id label; unset clients bucket under _DEFAULT.
  • Go SDK (WithApplicationID) and TypeScript SDK (withApplicationID) append ?app_id= to the dial URL.

Notes

  • The application_id column is advisory — it is self-declared by the client and must not be used for access control.
  • Existing rows and clients that connect without ?app_id= continue to work; their writes store NULL.
  • Migration: clearnode/config/migrations/postgres/20260420000000_add_application_id_to_writes.sql.

Test plan

  • go vet ./... clean
  • go test ./... — 23/23 packages green, including new TestGetApplicationID, TestDBStore_StoreUserState_ApplicationID, TestDBStore_RecordTransaction/ApplicationID_*, TestRebalanceAppSessions_Error_DifferentApplications, TestWithApplicationID, TestAppendApplicationIDQueryParam
  • TS SDK typecheck introduces no new errors (pre-existing state_advancer.ts import-extension errors are unchanged)
  • Manual smoke: connect with and without ?app_id=; verify column value on resulting rows
  • Verify Prometheus scrape shows application_id label on the three affected metrics

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Clients can supply an application ID via the WebSocket query parameter; SDKs include helpers to set and append it. Server validates the ID and attaches it to session/request flows.
  • Database Changes

    • Added application_id columns and indexes to state and transaction storage; empty values are persisted as NULL.
  • Behavior Change

    • Operations that aggregate sessions now enforce a single application ID across involved sessions.
  • Metrics

    • Application ID added as a Prometheus label for user-state and transaction metrics.
  • Tests

    • Updated and added tests covering validation, propagation, persistence, and multi-session enforcement.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 20, 2026

📝 Walkthrough

Walkthrough

Threads a client-declared ApplicationID (WS query app_id) through RPC context, SDKs, handlers, Store/DB persistence, and metrics; adds nullable DB columns/indexes, updates interfaces/mocks/tests, and enforces a single ApplicationID for multi-session rebalances.

Changes

Cohort / File(s) Summary
App Session Handlers & Rebalance
clearnode/api/app_session_v1/handler.go, .../submit_app_state.go, .../submit_deposit_state.go, .../rebalance_app_sessions.go
Propagate applicationID into helper calls and persistence; rebalance enforces all sessions share the same ApplicationID.
App Session Interface, Mocks & Tests
clearnode/api/app_session_v1/interface.go, .../testing.go, .../*_test.go
Store interface adds applicationID arg for RecordTransaction/StoreUserState; mocks/tests updated; added rebalance error test for differing apps.
Channel API & Tests
clearnode/api/channel_v1/interface.go, .../handler.go, .../request_creation.go, .../submit_state.go, .../testing.go, .../*_test.go
Extract applicationID from RPC context and thread into StoreUserState, RecordTransaction, and receiver-state issuance; interface/mocks/tests updated.
Metrics & Exporter
clearnode/api/metric_store.go, clearnode/metrics/interface.go, clearnode/metrics/exporter.go
Metric APIs extended with applicationID; exporter adds application_id label and forwards applicationID to metric increments; noop exporter adapted.
Database Models, Store & Migrations
clearnode/store/database/state.go, .../transaction.go, .../interface.go, config/migrations/...add_application_id_to_writes.sql
Added nullable ApplicationID fields and indexes to State/Transaction; DBStore methods accept/persist applicationID; SQL migration adds columns/indexes.
Database Tests & Setup
clearnode/store/database/*_test.go, .../testing.go, .../postgres_integration_test.go, database.go
Updated many test call sites to pass applicationID (usually ""); added tests asserting persisted ApplicationID; adjusted AutoMigrate for tests.
RPC Context & Node
pkg/rpc/context.go, pkg/rpc/context_internal_test.go, pkg/rpc/node.go
Added ApplicationIDQueryParam and GetApplicationID; WebSocket node validates app_id and stores it per connection.
SDKs (Go & TS)
sdk/go/config.go, sdk/go/client.go, sdk/ts/src/config.ts, sdk/ts/src/client.ts, sdk/*_test.go
Added SDK config ApplicationID, helpers to append app_id to WS dial URL; clients use transformed dial URL; tests added/updated.
Mocks Across APIs
clearnode/api/*/testing.go, clearnode/store/database/testing.go
Mock method signatures updated to accept applicationID and include it in m.Called(...)/expectations.
App Validation
clearnode/api/app_session_v1/create_app_session.go, pkg/app/app_v1.go, pkg/app/app_v1_test.go
Added ApplicationIDRegex and IsValidApplicationID; create handler validates application ID format before unmarshalling.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant SDK
    participant WebsocketNode
    participant Handler
    participant Store
    participant DB
    participant Metrics

    Client->>SDK: connect (may include ApplicationID)
    SDK->>WebsocketNode: WS dial URL (app_id query)
    WebsocketNode->>WebsocketNode: parse & validate app_id
    WebsocketNode->>Handler: deliver request (context includes applicationID)
    Handler->>Store: StoreUserState(state, applicationID)
    Store->>DB: INSERT state (application_id = applicationID or NULL)
    Store->>Metrics: buffer IncUserState(..., applicationID)
    Handler->>Store: RecordTransaction(tx, applicationID)
    Store->>DB: INSERT transaction (application_id = applicationID or NULL)
    Store->>Metrics: buffer RecordTransaction(..., applicationID)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

ready

Suggested reviewers

  • ihsraham
  • dimast-x

Poem

🐰 I hopped a query param into the stream,
From socket to store, a tiny shining beam.
AppID on each write, in metrics it sings,
Now every ledger hop has clearer wings.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.92% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main objective: adding application_id tracking on database writes and exposing it via SDKs. It directly reflects the primary changes across the codebase.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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 feat/app-id-transactions

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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
clearnode/store/database/database.go (1)

123-125: ⚠️ Potential issue | 🟠 Major

Propagate SQLite auto-migration failures.

migrateSqlite returns the AutoMigrate error, but connectToSqlite ignores it and logs success. If the new State/Transaction migration fails, startup continues with an incomplete schema.

🐛 Proposed fix
-	// Migrate sqlite
-	migrateSqlite(db)
+	// Migrate sqlite
+	if err := migrateSqlite(db); err != nil {
+		return nil, fmt.Errorf("failed to auto-migrate sqlite: %w", err)
+	}
 
 	log.Println("Successfully auto-migrated")

As per coding guidelines, Go error handling: always check and return errors, never ignore with _.

Also applies to: 217-217

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

In `@clearnode/store/database/database.go` around lines 123 - 125, connectToSqlite
currently calls migrateSqlite(db) and unconditionally logs "Successfully
auto-migrated"; instead capture and handle the error returned by migrateSqlite
(from function migrateSqlite) and propagate it up from connectToSqlite (or
return a wrapped error) so startup fails on migration errors; update the call
site to check the returned error and remove the misleading success log unless
migrateSqlite returned nil.
clearnode/api/channel_v1/request_creation_test.go (1)

106-119: ⚠️ Potential issue | 🟡 Minor

Assert the propagated connection application ID instead of accepting anything.

These tests now match the new arity, but mock.Anything would still pass if RequestCreation stopped using the connection’s app_id. Set ctx.Storage with a concrete value and expect that exact value in RecordTransaction/StoreUserState.

🧪 Proposed test tightening
+	applicationID := "client-app"
 	mockTxStore.On("RecordTransaction", mock.MatchedBy(func(tx core.Transaction) bool {
 		// For home_deposit: fromAccount is homeChannelID, toAccount is userWallet
 		return tx.TxType == core.TransactionTypeHomeDeposit &&
 			tx.ToAccount == userWallet &&
 			tx.FromAccount != "" // homeChannelID will be set by handler
-	}), mock.Anything).Return(nil).Once()
+	}), applicationID).Return(nil).Once()
 	mockTxStore.On("StoreUserState", mock.MatchedBy(func(state core.State) bool {
 		return state.UserWallet == userWallet &&
 			state.Asset == asset &&
 			state.Version == 1 &&
 			state.Epoch == 0 &&
 			state.NodeSig != nil &&
 			state.HomeChannelID != nil
-	}), mock.Anything).Return(nil).Once()
+	}), applicationID).Return(nil).Once()
@@
 	ctx := &rpc.Context{
 		Context: context.Background(),
+		Storage: rpc.NewSafeStorage(),
 		Request: rpc.Message{
 			RequestID: 1,
 			Method:    rpc.ChannelsV1RequestCreationMethod.String(),
 			Payload:   payload,
 		},
 	}
+	ctx.Storage.Set(rpc.ApplicationIDQueryParam, applicationID)

Apply the same pattern to the acknowledgement success case’s StoreUserState expectation.

Also applies to: 135-142, 261-269, 285-292

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

In `@clearnode/api/channel_v1/request_creation_test.go` around lines 106 - 119,
The test currently uses mock.Anything for the second argument of
mockTxStore.RecordTransaction and StoreUserState which lets RequestCreation
ignore the connection's app_id; instead set ctx.Storage to a concrete connection
application ID before invoking the handler and change the expectations to match
that exact value (e.g., expect the provided app_id in the matched Transaction
and State objects). Update the mock.MatchedBy predicates used in the
RecordTransaction and StoreUserState expectations to assert the concrete
ctx.Storage value (and do the same tightening for the acknowledgement-success
StoreUserState expectation referenced around the other ranges).
clearnode/api/app_session_v1/submit_deposit_state_test.go (1)

180-192: ⚠️ Potential issue | 🟡 Minor

Verify app-session writes use the session ApplicationID.

mock.Anything hides regressions where the handler might pass the connection app_id or an empty string. Since this path must stamp appSession.ApplicationID, assert that exact value; optionally set a different connection tag to prove it is ignored.

🧪 Proposed test tightening
 	mockStore.On("StoreUserState", mock.MatchedBy(func(state core.State) bool {
 		return state.UserWallet == participant1 &&
 			state.Version == incomingUserState.Version &&
 			state.Transition.Type == core.TransitionTypeCommit &&
 			state.NodeSig != nil
-	}), mock.Anything).Return(nil).Once()
+	}), existingAppSession.ApplicationID).Return(nil).Once()
@@
 	mockStore.On("RecordTransaction", mock.MatchedBy(func(tx core.Transaction) bool {
 		return tx.TxType == core.TransactionTypeCommit &&
 			tx.Amount.Equal(depositAmount) &&
 			tx.ToAccount == appSessionID
-	}), mock.Anything).Return(nil).Once()
+	}), existingAppSession.ApplicationID).Return(nil).Once()
@@
 	ctx := &rpc.Context{
 		Context: context.Background(),
+		Storage: rpc.NewSafeStorage(),
 		Request: rpc.NewRequest(1, string(rpc.AppSessionsV1SubmitDepositStateMethod), payload),
 	}
+	ctx.Storage.Set(rpc.ApplicationIDQueryParam, "connection-app")

Apply the same exact-value assertion in TestSubmitDepositState_AppRegistryDisabled.

Also applies to: 205-208, 662-667, 679-682

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

In `@clearnode/api/app_session_v1/submit_deposit_state_test.go` around lines 180 -
192, The mocks in submit_deposit_state_test.go currently use mock.Anything for
the connection/app ID which hides regressions; update the mocked expectations
for StoreUserState and RecordTransaction (and the other occurrences in the file
including TestSubmitDepositState_AppRegistryDisabled) to assert the exact app
session ApplicationID is used (i.e., replace mock.Anything for the
ToAccount/connection argument with a matcher that equals
appSession.ApplicationID or a MatchedBy(func(s string) bool { return s ==
appSession.ApplicationID }) and optionally add a different connection value on
the incoming request to prove it is ignored), ensuring the test verifies the
handler stamps appSession.ApplicationID rather than the connection app_id or
empty string.
clearnode/metrics/exporter.go (1)

175-189: ⚠️ Potential issue | 🟠 Major

Avoid raw client-controlled values as Prometheus labels.

applicationID is self-declared by clients, and the current getApplicationIDLabelValue() function only provides a fallback for empty values (_DEFAULT). It does not validate or constrain the applicationID against a bounded set. This allows arbitrary client values to flow directly as Prometheus label values, creating unbounded time-series cardinality and potential memory/storage pressure in Prometheus and the exporter.

Constrain applicationID to a bounded allowlist of registered applications, or bucket unknown values to a fixed set before calling WithLabelValues.

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

In `@clearnode/metrics/exporter.go` around lines 175 - 189, The Prometheus labels
(used by userStatesTotal, transactionsTotal, transactionsAmountTotal) currently
accept arbitrary client-provided application IDs via
getApplicationIDLabelValue(); replace that with a bounded mapping: implement or
use an allowlist/set of registered application IDs and a bucketing function
(e.g., isRegisteredApplication(appID) or registeredApps map) to return the appID
if present or a fixed sentinel like "_UNKNOWN_APP" or "_UNREGISTERED" otherwise,
and call that mapping before passing the label to WithLabelValues so untrusted
values cannot create unbounded label cardinality.
🧹 Nitpick comments (3)
clearnode/config/migrations/postgres/20260420000000_add_application_id_to_writes.sql (1)

1-12: Consider a partial index and harden the Down migration.

Two small suggestions:

  1. application_id is nullable and, per the PR objectives, most existing rows and clients without ?app_id= will store NULL. A partial index excluding NULLs will be substantially smaller and faster to maintain for this access pattern (lookups are only meaningful for non-NULL values).
  2. The Down migration uses IF EXISTS for the indexes but not for the DROP COLUMN statements — inconsistent, and will fail noisily if the column was already removed manually. Since index drops will also cascade when the column is dropped, the explicit index drops are arguably redundant.
♻️ Proposed diff
 -- +goose Up
 ALTER TABLE channel_states ADD COLUMN application_id VARCHAR(66);
 ALTER TABLE transactions ADD COLUMN application_id VARCHAR(66);
 
-CREATE INDEX idx_channel_states_app_id ON channel_states(application_id);
-CREATE INDEX idx_transactions_app_id ON transactions(application_id);
+CREATE INDEX idx_channel_states_app_id ON channel_states(application_id) WHERE application_id IS NOT NULL;
+CREATE INDEX idx_transactions_app_id ON transactions(application_id) WHERE application_id IS NOT NULL;
 
 -- +goose Down
 DROP INDEX IF EXISTS idx_transactions_app_id;
 DROP INDEX IF EXISTS idx_channel_states_app_id;
-ALTER TABLE transactions DROP COLUMN application_id;
-ALTER TABLE channel_states DROP COLUMN application_id;
+ALTER TABLE transactions DROP COLUMN IF EXISTS application_id;
+ALTER TABLE channel_states DROP COLUMN IF EXISTS application_id;

On large existing transactions/channel_states tables, CREATE INDEX (without CONCURRENTLY) will take an ACCESS EXCLUSIVE-blocking lock for writes. If these tables are sizeable in production, consider running index creation via a separate non-transactional migration using CREATE INDEX CONCURRENTLY (goose supports -- +goose NO TRANSACTION) to avoid write stalls during deploy.

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

In
`@clearnode/config/migrations/postgres/20260420000000_add_application_id_to_writes.sql`
around lines 1 - 12, Change the indexes to partial indexes that exclude NULLs
(e.g., create idx_channel_states_app_id and idx_transactions_app_id WITH WHERE
application_id IS NOT NULL) so they stay small and faster for lookups on
non-NULL application_id; update the Down migration to defensively use IF EXISTS
when dropping columns (DROP COLUMN IF EXISTS application_id on transactions and
channel_states) or remove explicit index drops since dropping the column
cascades indexes, and consider making the index creation non-transactional with
CREATE INDEX CONCURRENTLY (use goose NO TRANSACTION) for large tables to avoid
ACCESS EXCLUSIVE locks during deploy.
sdk/ts/test/unit/config.test.ts (1)

1-47: Align imports with path alias and prefer data-driven tests.

Two guideline deviations worth addressing:

  1. Path alias: '../../src/config' should use @/config per the test-config import convention.
  2. Data-driven pattern: the six appendApplicationIDQueryParam cases share identical shape (input URL + app_id → expected assertion) and are a good fit for a .forEach() table-driven test.

As per coding guidelines: "Use path alias @/ mapping to src/ in test configurations for import paths" and "Use data-driven tests with .forEach() pattern and manual mocks instead of jest.mock()".

♻️ Sketch
-import {
-  APPLICATION_ID_QUERY_PARAM,
-  appendApplicationIDQueryParam,
-  type Config,
-  withApplicationID,
-} from '../../src/config';
+import {
+    APPLICATION_ID_QUERY_PARAM,
+    appendApplicationIDQueryParam,
+    type Config,
+    withApplicationID,
+} from '@/config';

And for appendApplicationIDQueryParam, consolidate the happy-path cases into a table:

const cases: Array<{ name: string; url: string; appID?: string; check: (out: string) => void }> = [
    { name: 'no-op on empty id', url: 'ws://host/path', check: (o) => expect(o).toBe('ws://host/path') },
    { name: 'adds app_id with no query', url: 'ws://host/path', appID: 'my-app', check: (o) => expect(o).toBe('ws://host/path?app_id=my-app') },
    // ...
];
cases.forEach(({ name, url, appID, check }) => it(name, () => check(appendApplicationIDQueryParam(url, appID))));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sdk/ts/test/unit/config.test.ts` around lines 1 - 47, Update the imports to
use the path alias by replacing '../../src/config' with '@/config' for the
imported symbols (APPLICATION_ID_QUERY_PARAM, appendApplicationIDQueryParam,
Config, withApplicationID), then refactor the appendApplicationIDQueryParam
tests into a data-driven table: create an array of case objects (name, url,
optional appID, and a check function) and run
cases.forEach(({name,url,appID,check}) => it(name, () =>
check(appendApplicationIDQueryParam(url, appID)))); keep the existing
withApplicationID unit as-is referencing withApplicationID and Config and ensure
one of the case checks uses new
URL(out).searchParams.get(APPLICATION_ID_QUERY_PARAM) where needed.
clearnode/api/app_session_v1/submit_app_state_test.go (1)

355-993: Consider a stricter matcher for at least one test.

Using mock.Anything for the applicationID argument is fine for the majority of cases, but since the contract is that app-session handlers must stamp the session's ApplicationID (not the connection tag), at least one representative test (e.g., TestSubmitAppState_WithdrawIntent_Success or TestSubmitAppState_CloseIntent_Success) would be more valuable if it matched "test-app" explicitly — otherwise a regression that accidentally passes rpc.GetApplicationID(c) (empty in these tests) would still pass.

♻️ Example
-mockStore.On("RecordTransaction", mock.Anything, mock.Anything).Return(nil)
+mockStore.On("RecordTransaction", mock.Anything, "test-app").Return(nil)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@clearnode/api/app_session_v1/submit_app_state_test.go` around lines 355 -
993, The test suite uses mock.Anything for the applicationID in some GetApp
expectations which hides regressions; update at least one representative test
(e.g., TestSubmitAppState_CloseIntent_Success) so the mock expectation on
mockStore uses the explicit application ID "test-app" instead of mock.Anything —
locate the mock call mockStore.On("GetApp", ... ) in
TestSubmitAppState_CloseIntent_Success and replace the loose matcher with the
literal "test-app" to ensure the handler stamps the session's ApplicationID
correctly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@clearnode/store/database/transaction.go`:
- Around line 33-35: The model's ApplicationID (field ApplicationID on the
transaction/state structs) can exceed the DB VARCHAR(66) limit because it is
taken directly from r.URL.Query().Get(ApplicationIDQueryParam); add validation
at ingress where applicationID is read (the code that references
ApplicationIDQueryParam in the RPC node request handling) to enforce or sanitize
length: check len(applicationID) and if >66 either truncate to 66 bytes (or set
to nil/empty) before assigning to the model, or return a 4xx error; also add a
defensive guard right before persistence in the methods that populate
Transaction.ApplicationID / State.ApplicationID to ensure any programmatic
caller cannot bypass the check. Ensure you reference ApplicationIDQueryParam,
the local applicationID var, and the ApplicationID struct fields when applying
the changes.

In `@pkg/rpc/node.go`:
- Line 213: The request handler reads applicationID via
r.URL.Query().Get(ApplicationIDQueryParam) and forwards it to persistence where
transactions.application_id/channel_states.application_id are VARCHAR(66); add
ingress validation to enforce a max length of 66 (e.g., if len(applicationID) >
66 either truncate and process while logging a warning via the request logger or
reject with a 400 and clear error message), and ensure the same
validated/truncated value is used for downstream calls like StoreUserState and
RecordTransaction to avoid per-connection DB errors; update the handler around
the applicationID retrieval to perform this check and log accordingly.

---

Outside diff comments:
In `@clearnode/api/app_session_v1/submit_deposit_state_test.go`:
- Around line 180-192: The mocks in submit_deposit_state_test.go currently use
mock.Anything for the connection/app ID which hides regressions; update the
mocked expectations for StoreUserState and RecordTransaction (and the other
occurrences in the file including TestSubmitDepositState_AppRegistryDisabled) to
assert the exact app session ApplicationID is used (i.e., replace mock.Anything
for the ToAccount/connection argument with a matcher that equals
appSession.ApplicationID or a MatchedBy(func(s string) bool { return s ==
appSession.ApplicationID }) and optionally add a different connection value on
the incoming request to prove it is ignored), ensuring the test verifies the
handler stamps appSession.ApplicationID rather than the connection app_id or
empty string.

In `@clearnode/api/channel_v1/request_creation_test.go`:
- Around line 106-119: The test currently uses mock.Anything for the second
argument of mockTxStore.RecordTransaction and StoreUserState which lets
RequestCreation ignore the connection's app_id; instead set ctx.Storage to a
concrete connection application ID before invoking the handler and change the
expectations to match that exact value (e.g., expect the provided app_id in the
matched Transaction and State objects). Update the mock.MatchedBy predicates
used in the RecordTransaction and StoreUserState expectations to assert the
concrete ctx.Storage value (and do the same tightening for the
acknowledgement-success StoreUserState expectation referenced around the other
ranges).

In `@clearnode/metrics/exporter.go`:
- Around line 175-189: The Prometheus labels (used by userStatesTotal,
transactionsTotal, transactionsAmountTotal) currently accept arbitrary
client-provided application IDs via getApplicationIDLabelValue(); replace that
with a bounded mapping: implement or use an allowlist/set of registered
application IDs and a bucketing function (e.g., isRegisteredApplication(appID)
or registeredApps map) to return the appID if present or a fixed sentinel like
"_UNKNOWN_APP" or "_UNREGISTERED" otherwise, and call that mapping before
passing the label to WithLabelValues so untrusted values cannot create unbounded
label cardinality.

In `@clearnode/store/database/database.go`:
- Around line 123-125: connectToSqlite currently calls migrateSqlite(db) and
unconditionally logs "Successfully auto-migrated"; instead capture and handle
the error returned by migrateSqlite (from function migrateSqlite) and propagate
it up from connectToSqlite (or return a wrapped error) so startup fails on
migration errors; update the call site to check the returned error and remove
the misleading success log unless migrateSqlite returned nil.

---

Nitpick comments:
In `@clearnode/api/app_session_v1/submit_app_state_test.go`:
- Around line 355-993: The test suite uses mock.Anything for the applicationID
in some GetApp expectations which hides regressions; update at least one
representative test (e.g., TestSubmitAppState_CloseIntent_Success) so the mock
expectation on mockStore uses the explicit application ID "test-app" instead of
mock.Anything — locate the mock call mockStore.On("GetApp", ... ) in
TestSubmitAppState_CloseIntent_Success and replace the loose matcher with the
literal "test-app" to ensure the handler stamps the session's ApplicationID
correctly.

In
`@clearnode/config/migrations/postgres/20260420000000_add_application_id_to_writes.sql`:
- Around line 1-12: Change the indexes to partial indexes that exclude NULLs
(e.g., create idx_channel_states_app_id and idx_transactions_app_id WITH WHERE
application_id IS NOT NULL) so they stay small and faster for lookups on
non-NULL application_id; update the Down migration to defensively use IF EXISTS
when dropping columns (DROP COLUMN IF EXISTS application_id on transactions and
channel_states) or remove explicit index drops since dropping the column
cascades indexes, and consider making the index creation non-transactional with
CREATE INDEX CONCURRENTLY (use goose NO TRANSACTION) for large tables to avoid
ACCESS EXCLUSIVE locks during deploy.

In `@sdk/ts/test/unit/config.test.ts`:
- Around line 1-47: Update the imports to use the path alias by replacing
'../../src/config' with '@/config' for the imported symbols
(APPLICATION_ID_QUERY_PARAM, appendApplicationIDQueryParam, Config,
withApplicationID), then refactor the appendApplicationIDQueryParam tests into a
data-driven table: create an array of case objects (name, url, optional appID,
and a check function) and run cases.forEach(({name,url,appID,check}) => it(name,
() => check(appendApplicationIDQueryParam(url, appID)))); keep the existing
withApplicationID unit as-is referencing withApplicationID and Config and ensure
one of the case checks uses new
URL(out).searchParams.get(APPLICATION_ID_QUERY_PARAM) where needed.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7036bdb4-732d-4ab9-b33c-37f20a5eb9e3

📥 Commits

Reviewing files that changed from the base of the PR and between bbc4f55 and 3e7efe0.

📒 Files selected for processing (41)
  • clearnode/api/app_session_v1/handler.go
  • clearnode/api/app_session_v1/interface.go
  • clearnode/api/app_session_v1/rebalance_app_sessions.go
  • clearnode/api/app_session_v1/rebalance_app_sessions_test.go
  • clearnode/api/app_session_v1/submit_app_state.go
  • clearnode/api/app_session_v1/submit_app_state_test.go
  • clearnode/api/app_session_v1/submit_deposit_state.go
  • clearnode/api/app_session_v1/submit_deposit_state_test.go
  • clearnode/api/app_session_v1/testing.go
  • clearnode/api/channel_v1/handler.go
  • clearnode/api/channel_v1/interface.go
  • clearnode/api/channel_v1/request_creation.go
  • clearnode/api/channel_v1/request_creation_test.go
  • clearnode/api/channel_v1/submit_state.go
  • clearnode/api/channel_v1/submit_state_test.go
  • clearnode/api/channel_v1/testing.go
  • clearnode/api/metric_store.go
  • clearnode/config/migrations/postgres/20260420000000_add_application_id_to_writes.sql
  • clearnode/metrics/exporter.go
  • clearnode/metrics/interface.go
  • clearnode/store/database/blockchain_action_test.go
  • clearnode/store/database/channel_test.go
  • clearnode/store/database/database.go
  • clearnode/store/database/db_store_test.go
  • clearnode/store/database/interface.go
  • clearnode/store/database/state.go
  • clearnode/store/database/state_test.go
  • clearnode/store/database/test/postgres_integration_test.go
  • clearnode/store/database/testing.go
  • clearnode/store/database/transaction.go
  • clearnode/store/database/transaction_test.go
  • pkg/rpc/context.go
  • pkg/rpc/context_internal_test.go
  • pkg/rpc/node.go
  • sdk/go/client.go
  • sdk/go/config.go
  • sdk/go/config_test.go
  • sdk/ts/src/client.ts
  • sdk/ts/src/config.ts
  • sdk/ts/src/index.ts
  • sdk/ts/test/unit/config.test.ts

Comment thread clearnode/store/database/transaction.go
Comment thread pkg/rpc/node.go Outdated
Copy link
Copy Markdown
Contributor

@nksazonov nksazonov left a comment

Choose a reason for hiding this comment

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

Generally approve, although with some suggestions

Comment thread pkg/rpc/node.go Outdated
Comment thread clearnode/metrics/exporter.go
Comment thread clearnode/api/channel_v1/request_creation.go
Comment thread clearnode/api/app_session_v1/rebalance_app_sessions.go Outdated
Comment thread sdk/ts/src/index.ts Outdated
philanton and others added 3 commits April 21, 2026 15:21
Treat the WebSocket app_id query parameter as an advisory origin tag.
The clearnode reads it during the HTTP upgrade, stores it in per-connection
SafeStorage, and persists it on channel_states and transactions writes
originating from client requests. App-session handlers use the session's own
ApplicationID rather than the connection tag; rebalance now rejects batches
mixing sessions from different applications. Metrics (user_states_total,
transactions_total, transactions_amount_total) carry an application_id label,
using _DEFAULT when unset. The Go and TypeScript SDKs expose a
WithApplicationID / withApplicationID option that appends ?app_id= to the
dial URL.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- pkg/app: new ApplicationIDRegex (^[a-z0-9_-]{1,66}$) and IsValidApplicationID helper
- pkg/rpc: reject WS upgrade with 400 when app_id query param is malformed
- clearnode/api/app_session_v1: reject create_app_session with invalid application id
- clearnode/api/app_session_v1: move shared applicationID var into useStoreInTx scope in rebalance
- clearnode/api/app_session_v1: document why handlers use session's ApplicationID vs connection tag
- clearnode/metrics: document application_id label cardinality risk
- sdk/ts: re-export APPLICATION_ID_QUERY_PARAM and appendApplicationIDQueryParam

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@philanton philanton force-pushed the feat/app-id-transactions branch from f0c74cd to d427d73 Compare April 21, 2026 12:24
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
clearnode/store/database/database.go (1)

122-124: ⚠️ Potential issue | 🟠 Major

Return SQLite migration failures instead of logging success.

migrateSqlite now migrates State and Transaction, but connectToSqlite still ignores its returned error. If the new schema migration fails, startup proceeds with an incomplete schema.

Proposed fix
 	// Migrate sqlite
-	migrateSqlite(db)
+	if err := migrateSqlite(db); err != nil {
+		return nil, fmt.Errorf("failed to auto-migrate sqlite: %w", err)
+	}
 
 	log.Println("Successfully auto-migrated")

As per coding guidelines, Go error handling: always check and return errors, never ignore with _.

Also applies to: 216-220

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

In `@clearnode/store/database/database.go` around lines 122 - 124, connectToSqlite
is currently calling migrateSqlite and ignoring its error, so migration failures
(for State and Transaction) allow startup to continue with an incomplete schema;
update connectToSqlite (and the other call site around lines 216-220) to capture
the error returned by migrateSqlite, propagate it (return it) up to the caller
instead of discarding it, and ensure any callers of connectToSqlite handle that
error; locate the migrateSqlite and connectToSqlite symbols and change the call
sites to check "err := migrateSqlite(db)" and return that err if non-nil so
startup fails on migration errors.
🧹 Nitpick comments (4)
sdk/ts/src/config.ts (1)

84-88: Consider validating/trimming appID input.

withApplicationID('') will set config.applicationID = '', which appendApplicationIDQueryParam then treats as falsy and silently ignores. A whitespace-only value would be stored and sent verbatim to the server. Since the server column is VARCHAR(66), consider rejecting empty/whitespace inputs (or inputs exceeding 66 chars) early to fail fast at config time rather than silently dropping or producing a server-side error.

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

In `@sdk/ts/src/config.ts` around lines 84 - 88, withApplicationID currently
assigns the raw appID to config.applicationID allowing empty/whitespace or
too-long values; update withApplicationID to trim the input, validate that the
trimmed value is non-empty and no longer than 66 characters, and if invalid
throw a clear error instead of assigning; set config.applicationID =
trimmedValue when valid so appendApplicationIDQueryParam sees a normalized,
validated value.
sdk/go/config.go (1)

50-62: Optional: validate applicationID client-side before connecting.

The server rejects invalid app_id values with HTTP 400 during the WebSocket upgrade (see pkg/rpc/node.go ServeHTTP). The SDK user will only see this as an opaque rpcClient.Start failure far from where they set the option. Since pkg/app.ApplicationIDRegex is exported, you could surface a clearer error here when applicationID != "" and doesn't match, instead of deferring to a dial failure.

Not a blocker — advisory.

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

In `@sdk/go/config.go` around lines 50 - 62, The appendApplicationIDQueryParam
function should proactively validate non-empty applicationID against the
exported pkg/app.ApplicationIDRegex and return a clear error if it doesn't match
instead of deferring to a dial failure; update appendApplicationIDQueryParam to
import pkg/app, test applicationID against app.ApplicationIDRegex when
applicationID != "", and return a descriptive error (e.g., "invalid
applicationID: does not match ApplicationIDRegex") before attempting url.Parse
so callers get immediate, actionable feedback.
pkg/app/app_v1.go (1)

14-26: Clarify the relationship between AppIDV1Regex and the new ApplicationIDRegex.

AppIDV1Regex (^[a-z0-9][-a-z0-9]{0,65}$) and ApplicationIDRegex (^[a-z0-9_-]{1,66}$) look nearly identical but differ in three ways: the new one permits _, permits leading -/_/digit-only/single-char, and is used for the advisory-tag column. Neither is a subset of the other usage-wise (the advisory tag is looser, so a valid registered ID passes both, but a valid advisory tag may not be a valid registered ID).

Consider a short doc note on each regex cross-referencing the other and explicitly stating they are intentionally distinct (registered-identity vs. advisory-tag), so future maintainers don't accidentally use the wrong one. This directly ties into the create_app_session.go site where the choice matters.

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

In `@pkg/app/app_v1.go` around lines 14 - 26, Add clarifying comments next to
AppIDV1Regex and ApplicationIDRegex stating they are intentionally different:
document that AppIDV1Regex enforces the registered application identifier rules
(no leading dash, no underscore, length 1..66 with first char letter/digit),
while ApplicationIDRegex is the looser advisory-tag format (allows underscores
and leading dash/underscore and single-char/digit-only) used for the
advisory-tag DB column; cross-reference the other regex symbol and mention that
IsValidApplicationID uses ApplicationIDRegex for advisory checks and that
create_app_session.go must use AppIDV1Regex when validating registered IDs to
avoid mixing usages.
clearnode/metrics/interface.go (1)

56-56: Add a doc comment for the exported constructor.

NewNoopRuntimeMetricExporter is exported, so it should have a leading doc comment.

📝 Proposed fix
+// NewNoopRuntimeMetricExporter returns a RuntimeMetricExporter that discards all metric updates.
 func NewNoopRuntimeMetricExporter() RuntimeMetricExporter                                  { return noopRuntimeMetricExporter{} }

As per coding guidelines, exported names must have doc comments.

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

In `@clearnode/metrics/interface.go` at line 56, Add a doc comment above the
exported constructor NewNoopRuntimeMetricExporter describing what the function
returns and its purpose (i.e., it constructs and returns a no-op implementation
of RuntimeMetricExporter used when metrics are disabled or not available), so
the exported symbol has a proper leading doc comment per project guidelines.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@clearnode/api/app_session_v1/create_app_session.go`:
- Around line 44-47: Change the validation for Definition.Application to use the
V1 app ID rules: replace the current check that relies on app.ApplicationIDRegex
with a validation against app.AppIDV1Regex (or a helper that uses it), i.e.
update the condition around
app.IsValidApplicationID(reqPayload.Definition.Application) to validate using
AppIDV1Regex so registered app IDs follow the V1 pattern (`AppIDV1Regex`) and
will match registry lookups downstream (references: IsValidApplicationID,
reqPayload.Definition.Application, AppIDV1Regex).

In `@clearnode/api/app_session_v1/rebalance_app_sessions.go`:
- Around line 108-114: The current check in rebalance logic uses applicationID
and appSession.ApplicationID and can produce a confusing message when one side
is empty; update the mismatch branch (where rpc.Errorf is returned) to detect if
either applicationID or appSession.ApplicationID is empty and return a clearer
message—e.g. when applicationID == "" return rpc.Errorf("cannot rebalance tagged
session %q with untagged sessions", appSession.ApplicationID) and when
appSession.ApplicationID == "" return rpc.Errorf("cannot rebalance tagged
session %q with untagged sessions", applicationID) otherwise keep the existing
cross-application message; make this change in the same block that compares
applicationID and appSession.ApplicationID so the behavior remains within the
transaction scope.

In `@clearnode/metrics/interface.go`:
- Around line 18-24: getApplicationIDLabelValue currently returns any non-empty
applicationID verbatim (used by metrics in exporter.go for user_states_total,
transactions_total, transactions_amount_total), which risks unbounded Prometheus
label cardinality; change getApplicationIDLabelValue to check the applicationID
against a configured allow-list (or set of knownAppIDs) and return the
applicationID only if it is allowed, otherwise return a stable bucket label like
"unknown_app" or a coarse hashed bucket (e.g., "app_hash_<N>")—ensure the
allow-list source is configurable and referenced by getApplicationIDLabelValue
and update exporter.go to rely on this sanitized value for all metrics.
- Line 39: Rename the parameter in the Metrics interface method
ObserveRPCDuration from durationSecs to duration to satisfy staticcheck ST1011;
locate the ObserveRPCDuration(method, path string, success bool, durationSecs
time.Duration) declaration in the Metrics interface and change the final
parameter name to duration so it matches the implementation in exporter.go and
avoids the unit-suffixed parameter name.

In `@sdk/ts/src/config.ts`:
- Around line 96-103: appendApplicationIDQueryParam currently calls new
URL(wsURL) which will throw a raw TypeError for invalid input; wrap the URL
parsing in a try-catch inside appendApplicationIDQueryParam and rethrow a new,
descriptive Error (e.g. indicating the provided wsURL / url configuration is
malformed) while preserving the original error message or including the invalid
wsURL for debugging; update error text to reference APPLICATION_ID_QUERY_PARAM
context so callers (and Client.create) get a clear, user-facing message instead
of the raw "Invalid URL".

---

Outside diff comments:
In `@clearnode/store/database/database.go`:
- Around line 122-124: connectToSqlite is currently calling migrateSqlite and
ignoring its error, so migration failures (for State and Transaction) allow
startup to continue with an incomplete schema; update connectToSqlite (and the
other call site around lines 216-220) to capture the error returned by
migrateSqlite, propagate it (return it) up to the caller instead of discarding
it, and ensure any callers of connectToSqlite handle that error; locate the
migrateSqlite and connectToSqlite symbols and change the call sites to check
"err := migrateSqlite(db)" and return that err if non-nil so startup fails on
migration errors.

---

Nitpick comments:
In `@clearnode/metrics/interface.go`:
- Line 56: Add a doc comment above the exported constructor
NewNoopRuntimeMetricExporter describing what the function returns and its
purpose (i.e., it constructs and returns a no-op implementation of
RuntimeMetricExporter used when metrics are disabled or not available), so the
exported symbol has a proper leading doc comment per project guidelines.

In `@pkg/app/app_v1.go`:
- Around line 14-26: Add clarifying comments next to AppIDV1Regex and
ApplicationIDRegex stating they are intentionally different: document that
AppIDV1Regex enforces the registered application identifier rules (no leading
dash, no underscore, length 1..66 with first char letter/digit), while
ApplicationIDRegex is the looser advisory-tag format (allows underscores and
leading dash/underscore and single-char/digit-only) used for the advisory-tag DB
column; cross-reference the other regex symbol and mention that
IsValidApplicationID uses ApplicationIDRegex for advisory checks and that
create_app_session.go must use AppIDV1Regex when validating registered IDs to
avoid mixing usages.

In `@sdk/go/config.go`:
- Around line 50-62: The appendApplicationIDQueryParam function should
proactively validate non-empty applicationID against the exported
pkg/app.ApplicationIDRegex and return a clear error if it doesn't match instead
of deferring to a dial failure; update appendApplicationIDQueryParam to import
pkg/app, test applicationID against app.ApplicationIDRegex when applicationID !=
"", and return a descriptive error (e.g., "invalid applicationID: does not match
ApplicationIDRegex") before attempting url.Parse so callers get immediate,
actionable feedback.

In `@sdk/ts/src/config.ts`:
- Around line 84-88: withApplicationID currently assigns the raw appID to
config.applicationID allowing empty/whitespace or too-long values; update
withApplicationID to trim the input, validate that the trimmed value is
non-empty and no longer than 66 characters, and if invalid throw a clear error
instead of assigning; set config.applicationID = trimmedValue when valid so
appendApplicationIDQueryParam sees a normalized, validated value.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: aad01075-aa40-4a5d-8f95-02d3588c4b38

📥 Commits

Reviewing files that changed from the base of the PR and between f0c74cd and d427d73.

📒 Files selected for processing (44)
  • clearnode/api/app_session_v1/create_app_session.go
  • clearnode/api/app_session_v1/handler.go
  • clearnode/api/app_session_v1/interface.go
  • clearnode/api/app_session_v1/rebalance_app_sessions.go
  • clearnode/api/app_session_v1/rebalance_app_sessions_test.go
  • clearnode/api/app_session_v1/submit_app_state.go
  • clearnode/api/app_session_v1/submit_app_state_test.go
  • clearnode/api/app_session_v1/submit_deposit_state.go
  • clearnode/api/app_session_v1/submit_deposit_state_test.go
  • clearnode/api/app_session_v1/testing.go
  • clearnode/api/channel_v1/handler.go
  • clearnode/api/channel_v1/interface.go
  • clearnode/api/channel_v1/request_creation.go
  • clearnode/api/channel_v1/request_creation_test.go
  • clearnode/api/channel_v1/submit_state.go
  • clearnode/api/channel_v1/submit_state_test.go
  • clearnode/api/channel_v1/testing.go
  • clearnode/api/metric_store.go
  • clearnode/config/migrations/postgres/20260420000000_add_application_id_to_writes.sql
  • clearnode/metrics/exporter.go
  • clearnode/metrics/interface.go
  • clearnode/store/database/blockchain_action_test.go
  • clearnode/store/database/channel_test.go
  • clearnode/store/database/database.go
  • clearnode/store/database/db_store_test.go
  • clearnode/store/database/interface.go
  • clearnode/store/database/state.go
  • clearnode/store/database/state_test.go
  • clearnode/store/database/test/postgres_integration_test.go
  • clearnode/store/database/testing.go
  • clearnode/store/database/transaction.go
  • clearnode/store/database/transaction_test.go
  • pkg/app/app_v1.go
  • pkg/app/app_v1_test.go
  • pkg/rpc/context.go
  • pkg/rpc/context_internal_test.go
  • pkg/rpc/node.go
  • sdk/go/client.go
  • sdk/go/config.go
  • sdk/go/config_test.go
  • sdk/ts/src/client.ts
  • sdk/ts/src/config.ts
  • sdk/ts/src/index.ts
  • sdk/ts/test/unit/config.test.ts
✅ Files skipped from review due to trivial changes (4)
  • clearnode/config/migrations/postgres/20260420000000_add_application_id_to_writes.sql
  • clearnode/api/app_session_v1/submit_deposit_state_test.go
  • sdk/ts/test/unit/config.test.ts
  • pkg/rpc/context_internal_test.go
🚧 Files skipped from review as they are similar to previous changes (20)
  • clearnode/store/database/channel_test.go
  • clearnode/api/app_session_v1/submit_app_state.go
  • clearnode/api/app_session_v1/submit_deposit_state.go
  • sdk/ts/src/index.ts
  • clearnode/store/database/test/postgres_integration_test.go
  • sdk/ts/src/client.ts
  • sdk/go/config_test.go
  • clearnode/api/app_session_v1/submit_app_state_test.go
  • clearnode/api/channel_v1/handler.go
  • sdk/go/client.go
  • clearnode/api/app_session_v1/interface.go
  • clearnode/store/database/interface.go
  • clearnode/api/app_session_v1/handler.go
  • clearnode/store/database/transaction.go
  • clearnode/api/app_session_v1/testing.go
  • clearnode/store/database/state.go
  • clearnode/metrics/exporter.go
  • clearnode/api/metric_store.go
  • pkg/rpc/context.go
  • clearnode/api/app_session_v1/rebalance_app_sessions_test.go

Comment thread clearnode/api/app_session_v1/create_app_session.go
Comment thread clearnode/api/app_session_v1/rebalance_app_sessions.go
Comment thread clearnode/metrics/interface.go
Comment thread clearnode/metrics/interface.go Outdated
Comment thread sdk/ts/src/config.ts
- clearnode/api/app_session_v1/rebalance: quote applicationIDs in mismatch error so empty (legacy) tag stays visually distinct from named apps
- clearnode/metrics/interface: rename ObserveRPCDuration(durationSecs) -> duration (staticcheck ST1011)
- sdk/ts/src/config: wrap new URL(wsURL) with try/catch and rethrow a descriptive error instead of leaking raw TypeError

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

Inline comments:
In `@clearnode/metrics/interface.go`:
- Line 56: Add a godoc comment above the exported constructor
NewNoopRuntimeMetricExporter describing its purpose and return value (e.g.,
"NewNoopRuntimeMetricExporter returns a RuntimeMetricExporter that performs no
operations, useful for tests or disabling metrics") and mention the concrete
type returned (noopRuntimeMetricExporter) so tools and readers understand that
it returns a no-op exporter.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5dff2749-9af6-40da-a5fb-89c5574645a2

📥 Commits

Reviewing files that changed from the base of the PR and between d427d73 and 01ae4d5.

📒 Files selected for processing (4)
  • clearnode/api/app_session_v1/rebalance_app_sessions.go
  • clearnode/metrics/interface.go
  • sdk/ts/src/config.ts
  • sdk/ts/test/unit/config.test.ts
✅ Files skipped from review due to trivial changes (1)
  • sdk/ts/test/unit/config.test.ts

func (noopRuntimeMetricExporter) ObserveRPCDuration(string, string, bool, time.Duration) {}
func (noopRuntimeMetricExporter) SetRPCConnections(string, string, uint32) {}
func (noopRuntimeMetricExporter) IncAppStateUpdate(string) {}
func NewNoopRuntimeMetricExporter() RuntimeMetricExporter { return noopRuntimeMetricExporter{} }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Verify the exported constructor has an adjacent godoc comment.
# Expected: line before NewNoopRuntimeMetricExporter starts with "// NewNoopRuntimeMetricExporter".
awk 'NR>=52 && NR<=58 { printf "%d:%s\n", NR, $0 }' clearnode/metrics/interface.go

Repository: layer-3/nitrolite

Length of output: 528


Add a doc comment for the exported constructor.

NewNoopRuntimeMetricExporter is exported but lacks a godoc comment.

Proposed fix
+// NewNoopRuntimeMetricExporter returns a no-op runtime metric exporter.
-func NewNoopRuntimeMetricExporter() RuntimeMetricExporter                                  { return noopRuntimeMetricExporter{} }
+func NewNoopRuntimeMetricExporter() RuntimeMetricExporter { return noopRuntimeMetricExporter{} }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func NewNoopRuntimeMetricExporter() RuntimeMetricExporter { return noopRuntimeMetricExporter{} }
// NewNoopRuntimeMetricExporter returns a no-op runtime metric exporter.
func NewNoopRuntimeMetricExporter() RuntimeMetricExporter { return noopRuntimeMetricExporter{} }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@clearnode/metrics/interface.go` at line 56, Add a godoc comment above the
exported constructor NewNoopRuntimeMetricExporter describing its purpose and
return value (e.g., "NewNoopRuntimeMetricExporter returns a
RuntimeMetricExporter that performs no operations, useful for tests or disabling
metrics") and mention the concrete type returned (noopRuntimeMetricExporter) so
tools and readers understand that it returns a no-op exporter.

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.

2 participants