Conversation
…keystroke The Manual ABI text area lost focus after 1-2 characters because the TemplateBadgeTextarea's React key included `value?.length || 0`. Every keystroke changed the value length, which changed the key, which made React unmount and remount the textarea -- killing focus mid-word. Pasting "worked" only because it's a single change. Drop `value.length` from the key. The textarea's internal effect already syncs parent-driven `value` changes on blur, and the toggle-driven parts of the key (`useProxyAbi`, `useDiamondAbi`) still trigger the remount that proxy/diamond source switches actually need.
Hard-deleting a workflow removed its listed_slug from the idx_workflows_listed_slug unique index, letting any other workflow immediately re-claim the freed slug and inherit its traffic + x402 revenue. Workflows are now soft-deleted: the delete handler sets deleted_at (and is_listed = false) instead of deleting the row, so the row keeps its slug bound in the unique index forever. The index is intentionally unchanged -- the surviving row is what blocks re-claim. Execution history is still hard-deleted on force; schedules are removed explicitly since the ON DELETE CASCADE no longer fires on soft-delete. All workflow reads are audited to filter deleted_at IS NULL: public listing, payment binding, slug call route, catalog, x402 discovery, public feed, and executor lookups. Mutation/execution/export routes reject deleted workflows. The owner-facing workflow list deliberately keeps showing soft-deleted rows, marked "Deleted" in the sidebar, so the user has an audit trail and recovery window. Stat/analytics surfaces (metrics, leaderboard, earnings) are not yet filtered -- tracked as follow-up; they are correctness-of-stats, not a security boundary.
Review found trigger-driven execution paths and a discovery surface the
first pass missed -- all places that resolve a workflow without a
deleted_at filter:
- webhook route: a soft-deleted workflow was still executable via its
webhook URL (enabled is not cleared on delete, only is_listed).
- internal/executions: created a running execution row for a
soft-deleted workflow with no deleted_at check.
- events + block-workflows internal endpoints: handed soft-deleted
event/block-trigger workflows to the worker services, which would
keep firing executions for them.
- openapi discovery doc: published soft-deleted slugs to external
agents (relied on is_listed=false coupling instead of an explicit
filter, like the sibling x402/catalog routes already do).
- execution-status route: now hides a soft-deleted workflow's
execution detail, matching the execution-history route.
- hub protocol counts: excluded soft-deleted workflows so public
counts stay accurate.
Also extracts softDeleteValues() so the delete handler and the
duplicate-route anonymous move write the same { deletedAt, isListed:
false } shape -- no more divergent half-retired states.
POST /api/agentic-wallet/feedback went straight from calldata to
estimateGas with no check of the caller wallet's ETH balance. The
caller wallet pays mainnet gas natively, so a wallet with zero ETH
cannot complete the giveFeedback() tx -- but instead of a clean
error, that case failed opaquely (observed as a Cloudflare 502 with
no usable body) because estimateGas on a 0-balance account can stall
or error unhelpfully on some RPC providers.
buildAndSignTx now reads the wallet balance up front:
- zero balance short-circuits before estimateGas is ever called
- a non-zero balance is re-checked against the real estimated cost
(gasWithHeadroom * maxFeePerGas) once it is known
Either case throws InsufficientGasError, which the POST handler
surfaces as 402 INSUFFICIENT_GAS with balanceWei (and requiredWei
when known). The feedback row is still marked "failed" with a null
txHash, so it stays a stranded, retryable row -- the caller funds
the wallet and retries, recovering via the existing KEEP-515 path.
Adds integration coverage for both the zero-balance and
balance-too-low branches.
… red Previous defaults left a 10-minute gap between a chain going silent and the dispatcher flipping to fallback (5min BLOCK_ADVANCE_TIMEOUT x 2 SILENT_FAILOVER_THRESHOLD). The Grafana dashboard cell turned red at 120s and the Block Dispatcher Chain Silent alert finished its for=2m debounce at the same point — but the dispatcher itself was still sitting on the broken primary for another 8 minutes. Lowers BLOCK_ADVANCE_TIMEOUT_MS from 5min to 60s. With the unchanged SILENT_FAILOVER_THRESHOLD=2 the flip now happens at 120s, aligned with both the dashboard threshold and the alert firing. 60s is the floor that keeps Ethereum's 12s block time tolerable during testnet variance (5 missed blocks = noisy but not unusual) while making the silent-subscription failure mode detectable on sub-2s chains (Polygon, Base, Avalanche, BSC) within tens of expected blocks instead of hundreds. Also tightens MONITOR_RECREATE_TIMEOUT_MS from 10min to 120s so the reconciler's tear-down-and-recreate backstop runs at the same window. By the time the reconciler hits this gate, the chain has already had its first reconnect attempt and is about to flip; the recreate covers monitors that wedge during the flip itself. Tests: the "stays alive for 10 minutes" reaper test now pins MONITOR_RECREATE_TIMEOUT_MS via vi.stubEnv so the test stays decoupled from the production default. All 80 unit tests pass. Operationally this still has zero false-positive risk: the actual flip only happens after the chain has been silent past 2x the timeout AND the in-process reconnect on the same URL also failed to advance the height — i.e. it's two consecutive 60s windows of nothing arriving.
…failover-thresholds fix(block-dispatcher): tighten failover thresholds to match dashboard red
…flight fix: add ETH-balance gas preflight to agentic-wallet feedback route
…g-soft-delete fix: KEEP-440 soft-delete workflows to close slug-squat-after-delete
…nce and broader edge cases Adds two new test areas across unit, integration, and E2E layers: 1. Node-count invariance -- explicitly verifies the validator does not branch on node-count or index position. The user reported that saves "fail when there are more than 2 nodes." That observation is coincidental (1-2 node workflows usually have no contract action); the validator iterates every node uniformly. The new tests prove it by saving workflows of size 1, 2, 3, 5, 10, 20 with the affected node at varying indices, and asserting: - all sizes succeed when the affected node is valid - invalidFields report the correct nodes[N] path regardless of N - multiple affected nodes can be reported in one call - no aggregate cap exists 2. Broader save-time edge cases unrelated to KEEP-571 -- coverage we were missing on the validator: empty nodes array, trigger-only payloads, missing/blank actionType, RESERVED_CONFIG_KEYS pass- through, numeric values on string-like fields, object values rejected on string-like fields, showWhen gating both ways, per-node isolation of failures, deterministic issue ordering, integer-string on protocol-uint, empty-string treated as missing on required fields. Counts: - unit: 32 -> 60 tests (+28) - integration: 28 -> 35 tests (+7) - e2e: 5 -> 10 tests (+5)
Single formatter-only fix in chain-monitor.ts: line-wrap on the stalenessBaseline / MONITOR_RECREATE_TIMEOUT_MS comparison collapsed onto one line per Biome rules. No logic change. 81/81 scheduler unit tests still pass, typecheck clean. Resolves the lint failure blocking #1272.
…ction key leaks Cross-workspace workflow imports were rejected on save by the new action-config validator when the imported nodes carried two classes of keys the validator did not recognize: 1. useManualAbi -- a UI-only boolean toggle written by the abi-with-auto-fetch field renderer (components/workflow/config/abi-with-auto-fetch-field.tsx). It is persisted on every action that uses that field type so the form remembers the user's manual-vs-fetched ABI choice across reloads. The step runtime never reads it. 2. inputMode / batchSize on web3/query-transactions and web3/query-events -- leftover form state from a sibling action (batch-read-contract declares these as real fields). When a user started authoring as batch-read-contract and switched the action type, the prior keys persisted. The runtimes for query-transactions and query-events hardcode their own batching strategy and ignore these keys. Validator changes: - Add useManualAbi to RESERVED_CONFIG_KEYS (global, since it can appear on any action with abi-with-auto-fetch). - Introduce LEGACY_IGNORED_FIELDS: per-action allowlist of keys that do not map to a canonical field but must not be rejected (legacy / cross-action leftovers). Seed it with query-transactions and query-events accepting inputMode and batchSize. Truly unknown keys are still rejected, and batch-read-contract's own inputMode is still type-checked. Test additions (unit + integration): - useManualAbi accepted on every web3 action with abi-with-auto-fetch (read, write, query-events, query-transactions, batch-read-contract) - inputMode/batchSize accepted as cross-action leaks on query-transactions and query-events - Combined payload (useManualAbi + inputMode + batchSize) accepted on query-transactions - Truly unknown field still rejected when useManualAbi is present - inputMode is still type-validated on batch-read-contract where it is a real field - Integration tests for the same shapes at the PATCH route boundary Final tally: 108 unit + integration tests passing on this branch. Test data hygiene: all artifact names in tests are mocked (reader/doWrite/idBytes32/Prev Loop/targetAddress) -- no customer-specific debug data lands in the repo.
…cept-stringified-args fix(workflow-save): KEEP-571 accept stringified container fields and legacy aliases
…tuck-monitor fix: KEEP-570 reaper now detects monitors stuck across silent reconnects
…rea-focus fix(workflow): KEEP-487 stop remounting manual ABI textarea on every keystroke
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.