Skip to content

Feat/tier settings rev - #184

Open
agualdron wants to merge 3 commits into
stagingfrom
feat/tier-settings-rev
Open

Feat/tier settings rev#184
agualdron wants to merge 3 commits into
stagingfrom
feat/tier-settings-rev

Conversation

@agualdron

@agualdron agualdron commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds two related billing-tier capabilities:

  • Private-tier access codes with durable user grants, authenticated discovery, localized validation, and a user-scoped limit of five attempts per ten minutes.
  • Administrator-configurable workflow execution-time limits with attempt-scoped policy capture, nested budget propagation, deadline cancellation, and durable failure diagnostics.

Type of Change

  • New feature
  • Bug fix
  • Breaking change
  • Documentation
  • Other

Why

Private tiers need secure, non-enumerating access control without creating a separate subscription path. Workflow executions also need tier-controlled time limits that work consistently across triggers and nested workflows while preserving the existing execution lifecycle.

This change keeps Better Auth, Stripe, workflow execution, logging, and shared rate limiting as the canonical owners.

Affected Areas

  • apps/tradinggoose
  • apps/docs
  • packages/*
  • Workflows / execution
  • Realtime / sockets
  • Market data / charting
  • Dev tooling / CI / infra
  • Documentation only
  • Other: Billing tiers, Stripe renewal handling, localization, and SDK result contracts

Validation

The following validation passed:

bun run test:billing:suite
# 31 files, 157 tests passed

bun run test -- [workflow-focused test files]
# 15 files, 216 tests passed

bun run type-check
# Passed

bunx biome check [changed TS-038 files]
# Passed

git diff --check origin/staging...HEAD
# Clean

A final independent branch review against staging reported no goal-blocking findings.

Reviewer Focus

  • Private access-code authorization, confidentiality, generic error behavior, and rate-limit ordering.
  • Exact five-attempt/ten-minute accounting, user isolation, Retry-After behavior, and storage-failure handling.
  • Workflow policy capture at processing-attempt start and nested remaining-budget propagation.
  • Deadline race behavior, late-result suppression, durable logs, and Workflow Console failure rendering.
  • Tier lifecycle rules, renewal cancellation, and organization seat-management boundaries.
  • English, Spanish, and Chinese message-key and behavior parity.
  • Generated migration contents and deployment ordering.

Risk / Rollout Notes

  • Apply the generated migration before deploying application code that reads private grants or workflow limits.
  • Existing tiers retain null access-code and workflow-limit values; null workflow limits remain unlimited.
  • Deadline cancellation is best-effort for active external operations, but late results cannot overwrite the persisted deadline result.
  • Rate-limit storage failures intentionally fail closed with HTTP 503.
  • Stripe renewal handling now prevents unavailable tiers from renewing at invoice creation.
  • No breaking public API change is intended.

Config / Data Changes

  • Env vars added or changed: None.
  • Database schema or migration impact: One generated migration adds system_billing_tier.access_code, system_billing_tier.workflow_execution_time_limit_seconds, and private_tier_access. No backfill or rate-limit schema change.
  • External services or provider behavior changed: Better Auth registers eligible active public and private plans uniformly; Stripe subscription-cycle renewal is rejected for draft, archived, or missing tiers.

Screenshots / Video

Not attached. Visible changes are contained within existing billing administration and subscription-modal surfaces.

Checklist

  • I kept the change focused and reviewed my own diff
  • I validated the change locally and documented the results above
  • I updated docs, examples, or copy if behavior/user-facing flows changed
  • I called out any env, schema, provider, or rollout impact
  • I did not include secrets, tokens, or private credentials in this PR

Summary by CodeRabbit

  • New Features
    • Added private billing tiers with access codes, enterprise contact details, and localized access flows.
    • Added configurable workflow execution time limits with deadline status, metadata, and SDK support.
    • Added billing tier archiving, improved subscription availability, and yearly-only pricing support.
    • Added Stripe webhook test setup details and stronger subscription upgrade validation.
  • Bug Fixes
    • Improved workflow cancellation, timeout handling, console status reporting, and request cancellation.
    • Added rate-limit boundary handling and fail-closed behavior.
    • Prevented duplicate access codes and invalid billing tier configurations.
  • Localization
    • Added and updated English, Spanish, and Chinese billing and timeout messages.

@greptile-apps

greptile-apps Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR adds durable private-tier access grants and tier-configurable workflow execution deadlines.

  • Adds authenticated access-code validation, user-scoped rate limiting, private-tier discovery, and billing administration controls.
  • Captures execution-time policy per attempt and propagates remaining budgets through nested workflows.
  • Extends execution diagnostics, localized UI behavior, billing lifecycle handling, and SDK result contracts.

Confidence Score: 5/5

The PR appears safe to merge because the previously reported dependency-failure guidance defect is fixed and no blocking failure remains.

The private-tier request helper retains the 503 status and server message in a typed error, and the subscription UI now presents that temporary-unavailability message instead of invalid-code guidance.

Important Files Changed

Filename Overview
apps/tradinggoose/hooks/queries/private-tier-access.ts The previous error-mapping defect is fixed by preserving server guidance for rate-limit and dependency-failure responses while retaining generic invalid-code copy for validation failures.
apps/tradinggoose/app/api/billing/private-tier-access/route.ts Adds an authenticated private-tier discovery and grant endpoint with rate limiting, no-store responses, and explicit temporary-unavailability handling.
apps/tradinggoose/lib/execution/workflow-execution-time-policy.ts Introduces tier-derived workflow execution-time policy capture for the execution pipeline.
apps/tradinggoose/background/workflow-execution.ts Integrates attempt-scoped execution deadlines and durable timeout handling into background workflow processing.
apps/tradinggoose/executor/index.ts Propagates and enforces execution budgets while suppressing results completed after the deadline.

Sequence Diagram

sequenceDiagram
  participant User
  participant UI as Subscription UI
  participant API as Private-tier API
  participant Limiter as Rate limiter
  participant Billing as Billing helpers
  User->>UI: Submit access code
  UI->>API: POST access code
  API->>Limiter: Check user attempt budget
  alt Limiter unavailable
    Limiter-->>API: Dependency failure
    API-->>UI: 503 temporary unavailable
    UI-->>User: Server unavailability message
  else Attempt allowed
    API->>Billing: Validate code and persist grant
    Billing-->>API: Granted or invalid
    API-->>UI: Updated tiers or generic invalid response
  end
Loading

Reviews (2): Last reviewed commit: "fix: surface private access service erro..." | Re-trigger Greptile

Comment thread apps/tradinggoose/hooks/queries/private-tier-access.ts
@agualdron

Copy link
Copy Markdown
Collaborator Author

@greptile

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This change adds private billing-tier access, tier archiving, subscription policy handling, workflow execution time budgets, deadline propagation, cancellation signals, and related persistence, UI, API, localization, test, and SDK updates.

Changes

Billing and private-tier access

Layer / File(s) Summary
Private-tier persistence and access flow
packages/db/schema/*, packages/db/migrations/*, apps/tradinggoose/lib/billing/*, apps/tradinggoose/lib/api/rate-limit.ts, apps/tradinggoose/app/api/billing/private-tier-access/*
Billing tiers support private access codes and workflow execution limits. User-to-tier access is persisted. The access-code endpoint authenticates requests, applies a five-attempt ten-minute rate limit, grants valid access, and returns localized errors.
Billing administration and subscription display
apps/tradinggoose/app/admin/billing/*, apps/tradinggoose/hooks/queries/*, apps/tradinggoose/global-navbar/settings-modal/components/subscription/*, apps/tradinggoose/lib/billing/webhooks/*
Admin mutations use shared hooks. Tier deletion becomes archiving. Subscription displays compose public, private, archived, and current-only tiers. Renewal eligibility and invoice handling use tier status.
Billing contracts and localization
apps/tradinggoose/i18n/messages/*, apps/tradinggoose/lib/admin/billing/*, apps/tradinggoose/lib/billing/*
Billing schemas, snapshots, availability policies, catalog queries, subscription types, tests, and English, Spanish, and Chinese messages cover private access, archiving, Enterprise details, and recurring price validation.

Workflow execution time budgets

Layer / File(s) Summary
Time-policy and budget contracts
apps/tradinggoose/lib/execution/workflow-execution-time-policy.ts, apps/tradinggoose/lib/execution/workflow-execution-time-budget.ts, apps/tradinggoose/executor/types.ts
Workflow execution policies support bounded and unlimited limits, inherited remaining time, absolute deadlines, activity accounting, child-budget merging, timeout metadata, and stable failure codes.
Budget-aware execution orchestration
apps/tradinggoose/background/workflow-execution.ts, apps/tradinggoose/lib/workflows/execution-runner.ts, apps/tradinggoose/executor/index.ts, apps/tradinggoose/executor/handlers/workflow/workflow-handler.ts
Root executions create time policies. Nested executions validate inherited policies. The runner accounts for startup and child time, stops executors at deadlines, snapshots unfinished logs, and propagates remaining budgets.
Execution persistence and result propagation
apps/tradinggoose/lib/logs/execution/*, apps/tradinggoose/lib/execution/workflow-execution-events.ts, apps/tradinggoose/lib/workflows/execution-result.ts, apps/tradinggoose/lib/logs/execution/trace-spans/*
Execution results are stored and reconstructed with timeout codes and deadline metadata. Public results omit remaining time. Internal results retain it. Trace spans preserve failure codes.
Execution entry points and queueing
apps/tradinggoose/app/api/workflows/[id]/queue/*, apps/tradinggoose/lib/execution/pending-execution.*, apps/tradinggoose/background/*-execution.ts, apps/tradinggoose/tools/index.ts, apps/tradinggoose/lib/auth/internal.ts
Queued child payloads materialize inherited policies at enqueue time. Background entry points use executeWorkflowJob. Internal execution contexts carry validated policy metadata. Pending execution draining has unlimited duration.

Cancellation and supporting behavior

Layer / File(s) Summary
Abort-signal propagation
apps/tradinggoose/executor/handlers/*, apps/tradinggoose/providers/ai/*, apps/tradinggoose/tools/index.ts
Execution abort signals reach tool calls, MCP requests, provider requests, evaluator requests, and browser requests while preserving request-level timeouts.
Execution and console status handling
apps/tradinggoose/stores/console/*, apps/tradinggoose/widgets/widgets/workflow_console/*
Terminal events finalize matching console entries with status, error, cancellation, timestamps, and durations. Terminal status displays localized failure text for errored entries.
Independent endpoint and UI updates
apps/tradinggoose/app/api/auth/*, apps/tradinggoose/app/api/webhooks/test/*, apps/tradinggoose/components/ui/dropdown-menu.*, apps/tradinggoose/i18n/request-locale.*, apps/tradinggoose/services/queue/ExecutionLimiter.*
Subscription upgrade requests are guarded and normalized. Stripe webhook setup details are exposed through an authenticated route. Dropdown content always uses a portal. Locale and rate-limit boundary handling are centralized and tested.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant executeWorkflowJob
  participant AttemptTimeBudget
  participant Executor
  participant WorkflowRunner
  participant ExecutionLog

  Client->>executeWorkflowJob: submit workflow execution
  executeWorkflowJob->>AttemptTimeBudget: create execution policy and budget
  executeWorkflowJob->>WorkflowRunner: run with time policy and start timestamp
  WorkflowRunner->>Executor: execute blocks with abort signal
  AttemptTimeBudget-->>WorkflowRunner: deadline expiration
  WorkflowRunner->>Executor: stopForDeadline()
  Executor-->>WorkflowRunner: snapshot timed-out block logs
  WorkflowRunner->>ExecutionLog: persist timeout result and deadline metadata
  ExecutionLog-->>Client: return failed execution result
Loading

Suggested reviewers: bwj2310, bruzwj

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 95.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title references tier settings, but “rev” is vague and does not clearly summarize the private access and workflow time-limit changes. Replace it with a specific summary, such as “Add private tier access codes and workflow execution time limits.”
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
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.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/tier-settings-rev

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

@TradingGoose-Dev

Copy link
Copy Markdown
Contributor

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@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: 17

Caution

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

⚠️ Outside diff range comments (2)
apps/tradinggoose/lib/logs/execution/logger.ts (1)

283-290: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

The whole ExecutionResult is persisted into workflowExecutionLogs.executionData. The root cause is the merge at the logger, which writes the complete result next to traceSpans and finalOutput. The result repeats output and adds every BlockLog with its input and output, so the row stores the same payloads twice and widens the sensitive surface of the durable log.

  • apps/tradinggoose/lib/logs/execution/logger.ts#L283-L290: narrow the persisted value to the deadline diagnostics (code, deadline, error) instead of spreading the full result, and type the parameter as that narrowed shape rather than object.
  • apps/tradinggoose/lib/logs/execution/logging-session.ts#L44-L59: change result?: ExecutionResult on SessionCompleteParams and SessionErrorCompleteParams to the same narrowed type.
  • apps/tradinggoose/lib/workflows/execution-runner.ts#L528-L555: project the result before passing it to completeWithError and complete.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/tradinggoose/lib/logs/execution/logger.ts` around lines 283 - 290, Stop
persisting the full ExecutionResult in logger.ts#L283-L290: define and use a
narrowed type containing only deadline diagnostics (code, deadline, and error),
and persist only those fields alongside traceSpans and finalOutput. Update
SessionCompleteParams and SessionErrorCompleteParams in
apps/tradinggoose/lib/logs/execution/logging-session.ts#L44-L59 to use the same
narrowed result type instead of ExecutionResult, and project those fields before
passing the result to completeWithError and complete in
apps/tradinggoose/lib/workflows/execution-runner.ts#L528-L555.
apps/tradinggoose/tools/index.ts (1)

52-73: 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Propagate the captured workflow time policy through nested tool calls.

resolveExecutionScope only captures the policy from executionContext. Every provider site passes undefined for that argument. When a limited workflow invokes a provider tool, workflowExecutionTimePolicy is therefore absent. The abort signal cancels the current request, but a nested internal workflow cannot receive the original tier policy or deadline.

MCP execution has an execution context, but it creates a generic internal token. Use the scoped token path there so that MCP child execution also receives the captured policy.

  • apps/tradinggoose/tools/index.ts#L52-L73: support a captured policy supplied by provider-driven tool execution.
  • apps/tradinggoose/providers/ai/anthropic/core.ts#L554-L556: pass the captured policy or an equivalent execution context.
  • apps/tradinggoose/providers/ai/anthropic/core.ts#L972-L974: pass the captured policy or an equivalent execution context.
  • apps/tradinggoose/providers/ai/anthropic/index.ts#L466-L468: pass the captured policy or an equivalent execution context.
  • apps/tradinggoose/providers/ai/anthropic/index.ts#L818-L820: pass the captured policy or an equivalent execution context.
  • apps/tradinggoose/providers/ai/azure-openai/index.ts#L391-L393: pass the captured policy or an equivalent execution context.
  • apps/tradinggoose/providers/ai/bedrock/index.ts#L504-L506: pass the captured policy or an equivalent execution context.
  • apps/tradinggoose/providers/ai/cerebras/index.ts#L295-L297: pass the captured policy or an equivalent execution context.
  • apps/tradinggoose/providers/ai/deepseek/index.ts#L297-L299: pass the captured policy or an equivalent execution context.
  • apps/tradinggoose/providers/ai/fireworks/index.ts#L303-L305: pass the captured policy or an equivalent execution context.
  • apps/tradinggoose/providers/ai/mistral/index.ts#L333-L335: pass the captured policy or an equivalent execution context.
  • apps/tradinggoose/providers/ai/ollama/index.ts#L399-L401: pass the captured policy or an equivalent execution context.
  • apps/tradinggoose/providers/ai/openai/index.ts#L340-L342: pass the captured policy or an equivalent execution context.
  • apps/tradinggoose/tools/index.ts#L1103-L1104: resolve the scope before authentication and use the scoped internal token generator.
  • apps/tradinggoose/tools/index.ts#L1188-L1188: retain abort propagation after adding scoped policy propagation.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/tradinggoose/tools/index.ts` around lines 52 - 73, Propagate the
captured workflow execution-time policy through provider tool calls so nested
internal workflows retain the original tier policy and deadline. Update
resolveExecutionScope in apps/tradinggoose/tools/index.ts and every listed
provider site to accept and pass the captured policy or equivalent execution
context; in apps/tradinggoose/tools/index.ts lines 1103-1104 resolve the scope
before authentication and use the scoped internal-token generator, while
preserving abort propagation at lines 1188-1188. Apply the corresponding changes
at all listed provider file ranges.
🧹 Nitpick comments (21)
apps/tradinggoose/lib/billing/webhooks/subscription.ts (1)

142-142: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Log the skipped overage calculation.

When subscription.tier is null, the final overage becomes 0 and no invoice is created. Real unbilled usage is then dropped without any signal. The existing log at line 235 only reports "No overage to bill". Add a warning that distinguishes a missing tier from a genuine zero overage.

♻️ Proposed change
-    // Calculate overage for the final billing period
-    const totalOverage = subscription.tier ? await calculateSubscriptionOverage(subscription) : 0
+    // Calculate overage for the final billing period
+    if (!subscription.tier) {
+      logger.warn('Skipping final overage calculation for a subscription without a tier', {
+        subscriptionId: subscription.id,
+        stripeSubscriptionId,
+      })
+    }
+    const totalOverage = subscription.tier ? await calculateSubscriptionOverage(subscription) : 0
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/tradinggoose/lib/billing/webhooks/subscription.ts` at line 142, Add a
warning in the subscription overage flow around the `totalOverage` assignment
when `subscription.tier` is missing, explicitly recording that overage
calculation was skipped; keep the zero fallback, and ensure the existing “No
overage to bill” log remains reserved for genuine zero-overage cases.
apps/tradinggoose/lib/billing/webhooks/subscription.test.ts (1)

344-346: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Restore coverage for the settlement-failure path.

handleStripeSubscriptionDeleted still implements the settlement-failure branch. It records settlementError, skips final settlement, restores stripeSubscriptionId on the replacement subscription, and rethrows. The removed tests were the only coverage for that branch. Add a test that forces syncSubscriptionBillingTierFromStripeSubscription to reject, then assert the Stripe ID restore and the rethrow.

Also applies to: 410-410

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/tradinggoose/lib/billing/webhooks/subscription.test.ts` around lines 344
- 346, Restore a test for the settlement-failure branch of
handleStripeSubscriptionDeleted by mocking
syncSubscriptionBillingTierFromStripeSubscription to reject. Assert that
settlement is skipped, the replacement subscription restores
stripeSubscriptionId, and the original error is rethrown.
apps/tradinggoose/lib/billing/webhooks/invoices.ts (1)

74-77: 🗄️ Data Integrity & Integration | 🔵 Trivial | 💤 Low value

Remove the idempotencyKey from stripe.invoices.del. Stripe Node accepts and forwards the key, but Stripe ignores Idempotency-Key on /v1 DELETE requests because DELETE is idempotent by definition. The key provides no replay protection here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/tradinggoose/lib/billing/webhooks/invoices.ts` around lines 74 - 77,
Remove the idempotencyKey option from the stripe.invoices.del call in the
invoice webhook handling flow, leaving the invoice ID and existing control flow
unchanged.
apps/tradinggoose/app/api/admin/billing/tiers/route.test.ts (1)

5-11: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Replace source-text assertions with behavior tests.

These tests only verify that identifiers occur in source text. They do not verify normalization, persistence, uniqueness handling, or tier-query behavior.

  • apps/tradinggoose/app/api/admin/billing/tiers/route.test.ts#L5-L11: invoke the create route with mocked persistence and assert normalized access-code storage plus duplicate-code handling.
  • apps/tradinggoose/lib/billing/tiers.test.ts#L5-L12: invoke the exported tier helpers with mocked persistence and assert the Stripe-backed and private-access query results.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/tradinggoose/app/api/admin/billing/tiers/route.test.ts` around lines 5 -
11, Replace source-text assertions in
apps/tradinggoose/app/api/admin/billing/tiers/route.test.ts:5-11 with behavior
tests that invoke the create route using mocked persistence, asserting
access-code normalization, persistence, and duplicate-code handling through the
route’s uniqueness backstop. Update
apps/tradinggoose/lib/billing/tiers.test.ts:5-12 to invoke the exported tier
helpers with mocked persistence and assert both Stripe-backed and private-access
query results.
apps/tradinggoose/lib/workflows/workflow-execution-time-budget.test.ts (1)

1-3: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider co-locating this test with its subject.

This file tests AttemptTimeBudget from @/lib/execution/workflow-execution-time-budget, but it lives under lib/workflows/. The sibling test added in this PR, apps/tradinggoose/lib/execution/workflow-execution-events.test.ts, sits next to its subject. Moving this file to apps/tradinggoose/lib/execution/workflow-execution-time-budget.test.ts keeps discovery consistent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/tradinggoose/lib/workflows/workflow-execution-time-budget.test.ts`
around lines 1 - 3, Move the test file containing the AttemptTimeBudget tests
from the workflows test location to the execution directory beside
workflow-execution-time-budget, matching the co-located placement used by
workflow-execution-events.test.ts; preserve the test contents unchanged.
apps/tradinggoose/lib/execution/workflow-execution-time-budget.ts (2)

103-105: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Mark the budget disposed so a late call cannot re-arm a timer.

dispose clears the timer but keeps this.timer set and leaves the instance usable. A late closeActivity or mergeChildRemaining calls arm() and creates a new timer that nothing clears. The runner disposes at the end of an attempt, so this is defensive hardening rather than a live leak.

♻️ Proposed hardening
   private arm() {
     if (this.timer) clearTimeout(this.timer)
     this.timer = undefined
+    if (this.disposed) return
     const remaining = this.currentRemaining()
+  private disposed = false
+
   dispose() {
+    this.disposed = true
     if (this.timer) clearTimeout(this.timer)
+    this.timer = undefined
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/tradinggoose/lib/execution/workflow-execution-time-budget.ts` around
lines 103 - 105, Update dispose() in the workflow execution time budget to mark
the instance disposed after clearing its timer, and ensure arm() rejects or
no-ops once disposed so late closeActivity or mergeChildRemaining calls cannot
create another timer. Preserve normal timer behavior before disposal.

68-71: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider surfacing an unknown slot id in markQueuedChildWait.

markQueuedChildWait ignores a slot id that is not registered. If a caller ever marks before it registers, the budget keeps charging during the queued child wait and no signal is produced. A debug log or an assertion makes that caller error visible.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/tradinggoose/lib/execution/workflow-execution-time-budget.ts` around
lines 68 - 71, Update markQueuedChildWait to detect when slotId is absent from
this.activities and surface that caller error through the existing
project-appropriate debug log or assertion mechanism; retain the
queued-child-wait state update and syncPause behavior for registered slots.
apps/tradinggoose/lib/execution/workflow-execution-time-policy.ts (1)

117-161: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Consider validating processingStartedAt at construction.

createWorkflowExecutionTimePolicy validates limitSeconds thoroughly but accepts processingStartedAt unchecked. An unparsable value passes through into a remaining policy and only fails later in isWorkflowExecutionTimePolicy. In the absolute branch at Line 156, new Date(NaN).toISOString() throws a RangeError. That branch is currently unreachable because NESTED_WORKFLOW_QUEUE_WAIT_COUNTS_TOWARD_DEADLINE is false. A single guard makes the failure local and consistent with the rest of the file.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/tradinggoose/lib/execution/workflow-execution-time-policy.ts` around
lines 117 - 161, Validate processingStartedAt at the start of
createWorkflowExecutionTimePolicy by confirming it parses to a finite timestamp,
and throw a clear error when invalid. Perform this before the tier and
accounting branches so both unlimited and bounded policies reject invalid input
consistently.
apps/tradinggoose/components/ui/dropdown-menu.test.tsx (1)

31-44: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the portal boundary.

Line 43 passes when the menu renders inline because container is inside document.body. Assert that container does not contain Option, then assert that document.body does contain it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/tradinggoose/components/ui/dropdown-menu.test.tsx` around lines 31 - 44,
Update the open-menu test around the DropdownMenu render to first assert that
the local container does not contain “Option,” then assert that document.body
contains it, confirming the menu renders through the required Base UI portal.
apps/tradinggoose/background/workflow-execution.test.ts (1)

107-131: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Test the inherited-budget path.

The policy at Line 124 exceeds its own 10-second limit. isWorkflowExecutionTimePolicy rejects it before any parent allowance comparison.

Rename this test to describe malformed policy validation, or add a nested execution test that propagates a real parent remaining budget and verifies that the child cannot increase it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/tradinggoose/background/workflow-execution.test.ts` around lines 107 -
131, The test named “rejects a nested policy that expands the inherited
allowance” currently exercises malformed policy validation because
remainingMilliseconds exceeds limitSeconds, so it never reaches inherited-budget
comparison. Rename the test to describe malformed policy rejection, or update it
to provide a valid bounded policy and a real parent remaining budget, then
verify the nested child cannot increase that allowance while preserving the
existing no-execution assertions.
apps/tradinggoose/lib/admin/billing/snapshot.test.ts (1)

5-11: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the snapshot output instead of the source text.

This test reads snapshot.ts as a string and checks for substrings. It passes when a symbol appears in a comment or unreachable code, and it fails after a harmless rename. It verifies no behavior of the snapshot builder.

Replace it with a test that calls the snapshot function with a stubbed database and asserts the returned object contains entitledSubscriptionCount, archiveAction, and accessCode. That gives real coverage of the contract this test intends to protect.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/tradinggoose/lib/admin/billing/snapshot.test.ts` around lines 5 - 11,
Replace the source-text assertions in the test with an invocation of the
snapshot function using a stubbed database. Assert the returned snapshot object
contains the expected entitledSubscriptionCount, archiveAction, and accessCode
values, and remove checks for symbol names such as
BILLING_ENTITLED_SUBSCRIPTION_STATUSES.
apps/tradinggoose/lib/workflows/execution-runner.ts (1)

476-493: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

The deadline handler duplicates deadlineResultIfExpired, and the losing attempt keeps mutating shared state.

Two points on this block:

  1. Lines 480-485 repeat the body of deadlineResultIfExpired (lines 386-391). After the handler sets attemptClosed = true, deadlineResultIfExpired() returns exactly the same value. Reuse it so the terminal-result shape stays defined in one place.

  2. When the deadline wins the race, the attempt promise continues to run. Its remaining startup steps are not abortable. It can still assign the outer encryptedEnvVars at line 417 after line 542 has already read that variable for loggingSession.complete. The variables recorded on the terminal log then depend on timing. The deadlineResultIfExpired guards do prevent dispatch, so no execution occurs; only the logged variables are nondeterministic.

♻️ Proposed dedup for point 1
     if (executionPolicy.kind === 'bounded') {
       const deadline = timeBudget.expired.then(() => {
         attemptClosed = true
         executor?.stopForDeadline()
-        const terminatedAt = new Date().toISOString()
-        return createWorkflowExecutionDeadlineResult(
-          executionPolicy,
-          terminatedAt,
-          executor?.snapshotBlockLogsForDeadline(terminatedAt) ?? []
-        )
+        return deadlineResultIfExpired()!
       })

For point 2, capture encryptedEnvVars into a local constant once the race settles, so the logged variables reflect the state at termination time.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/tradinggoose/lib/workflows/execution-runner.ts` around lines 476 - 493,
In the bounded execution branch around deadlineResultIfExpired and the
Promise.race, replace the duplicated deadline-result construction with the
existing deadlineResultIfExpired() helper after setting attemptClosed. Once the
race settles, capture encryptedEnvVars into a local constant before completing
logging, and use that snapshot for the terminal log’s variables so the losing
attempt cannot change them.
apps/tradinggoose/lib/admin/billing/access-code.ts (1)

22-30: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

The violation check inspects only one cause level.

isAccessCodeUniqueViolation reads error.cause once. Drizzle wraps driver errors in DrizzleQueryError, and the depth of the wrapping can change between driver or ORM versions. If the postgres-js error is nested deeper, the helper returns false and the route returns HTTP 500 instead of 409. Consider walking the cause chain.

♻️ Optional: walk the cause chain
 export function isAccessCodeUniqueViolation(error: unknown): boolean {
-  const cause = (error as { cause?: unknown })?.cause as {
-    code?: unknown
-    constraint_name?: unknown
-  }
-  return (
-    cause?.code === '23505' && cause?.constraint_name === 'system_billing_tier_access_code_unique'
-  )
+  let current: unknown = error
+  for (let depth = 0; depth < 5 && current; depth++) {
+    const candidate = current as { code?: unknown; constraint_name?: unknown; cause?: unknown }
+    if (
+      candidate.code === '23505' &&
+      candidate.constraint_name === 'system_billing_tier_access_code_unique'
+    ) {
+      return true
+    }
+    current = candidate.cause
+  }
+  return false
 }

Note: the current unit test asserts that an unwrapped error returns false. Update that case if you accept this change.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/tradinggoose/lib/admin/billing/access-code.ts` around lines 22 - 30,
Update isAccessCodeUniqueViolation to traverse the full error.cause chain,
checking each wrapped error for code 23505 and constraint_name
system_billing_tier_access_code_unique, while safely handling unknown or cyclic
causes. Preserve false for errors without a matching cause and update the
related unwrapped-error test only if its expected behavior changes.</code>
apps/tradinggoose/executor/handlers/function/function-handler.ts (1)

69-70: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use the optional fifth parameter of executeTool directly.

Pass context.abortSignal ? { signal: context.abortSignal } : undefined to keep the call arity stable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/tradinggoose/executor/handlers/function/function-handler.ts` around
lines 69 - 70, Update the executeTool call in the function handler to pass the
optional fifth parameter directly as context.abortSignal ? { signal:
context.abortSignal } : undefined, preserving stable call arity instead of
conditionally spreading an array argument.
apps/tradinggoose/providers/ai/xai/index.ts (1)

334-336: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Tool calls honor the abort signal; the xAI completion calls do not.

executeTool now receives request.abortSignal, but xai.chat.completions.create(...) in this file is called without the OpenAI request-options argument, so model calls ignore cancellation. See the consolidated comment for the shared fix.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/tradinggoose/providers/ai/xai/index.ts` around lines 334 - 336, Update
the xAI completion calls in the surrounding request flow to pass
request.abortSignal through the OpenAI request-options argument of
xai.chat.completions.create(...), matching the existing executeTool cancellation
behavior. Apply this to every completion call in the file while preserving the
current completion parameters.
apps/tradinggoose/providers/ai/openrouter/index.ts (1)

258-260: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Tool calls honor the abort signal; the OpenRouter completion calls do not.

executeTool now receives request.abortSignal, but client.chat.completions.create(...) in this file is called without the OpenAI request-options argument, so model calls ignore cancellation. See the consolidated comment for the shared fix.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/tradinggoose/providers/ai/openrouter/index.ts` around lines 258 - 260,
Update the OpenRouter completion calls in the relevant request flow to pass
request options containing request.abortSignal as the OpenAI client’s final
argument to client.chat.completions.create(...). Apply this consistently to
every completion call in the file while preserving the existing request
payloads.
apps/tradinggoose/executor/handlers/workflow/workflow-handler.ts (1)

96-181: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Create the child-execution promise lazily, or attach a no-op rejection handler.

The IIFE at Line 102 starts the child workflow immediately and stores the promise. If any caller receives the deferred value but never calls wait(), the rejection stays unobserved and Node reports an unhandled rejection. Executor.executeLayer currently always awaits deferred results, so this is a latent risk rather than a present failure. A one-line guard removes the risk without changing the eager-start semantics.

♻️ Proposed guard
     })()
+    wait.catch(() => {})
 
     return { kind: 'deferred', wait: () => wait }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/tradinggoose/executor/handlers/workflow/workflow-handler.ts` around
lines 96 - 181, Add a no-op rejection handler immediately after creating the
eager child-execution promise in the IIFE assigned to wait, while keeping the
existing wait() accessor and eager-start behavior unchanged. Ensure the handled
promise does not alter the original rejection observed when wait() is called.
apps/tradinggoose/providers/ai/groq/index.ts (1)

264-266: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Tool calls honor the abort signal; the Groq completion calls do not.

executeTool now receives request.abortSignal. The groq.chat.completions.create(...) calls in this file are issued without a request-options object, so they ignore cancellation. The groq-sdk accepts a second request-options argument with signal. See the consolidated comment for the shared fix.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/tradinggoose/providers/ai/groq/index.ts` around lines 264 - 266, Update
every groq.chat.completions.create call in this file to pass a second
request-options argument containing request.abortSignal, matching the signal
already supplied to executeTool. Ensure all Groq completion calls honor
cancellation without changing their existing request payloads.
apps/tradinggoose/providers/ai/google/index.ts (2)

528-530: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Tool calls now honor the abort signal, but the Gemini HTTP calls in this provider still do not.

executeTool receives request.abortSignal, so tool work stops at the deadline. The fetch calls to generativelanguage.googleapis.com in this same executeRequest do not pass signal, so a long model call keeps running after the workflow deadline fires. The vLLM provider passes request.abortSignal to every completion call. Consider aligning this provider so deadline cancellation covers model requests too.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/tradinggoose/providers/ai/google/index.ts` around lines 528 - 530,
Update the Gemini HTTP requests within executeRequest to pass
request.abortSignal through their fetch options, matching the cancellation
behavior already used by executeTool and the vLLM completion calls. Ensure every
generativelanguage.googleapis.com request in this provider honors the workflow
deadline.

1-1: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Cancellation reaches executeTool in four providers but not their model API calls. Each provider now forwards request.abortSignal to executeTool, so tool work stops at the workflow deadline. The model requests in the same executeRequest functions still run without a signal, so a slow completion continues after stopForDeadline aborts the execution. apps/tradinggoose/providers/ai/vllm/index.ts already passes request.abortSignal ? { signal: request.abortSignal } : undefined to every chat.completions.create call; apply that same pattern.

  • apps/tradinggoose/providers/ai/google/index.ts#L528-530: add signal: request.abortSignal to the fetch options for the initial, check, streaming, and follow-up calls to generativelanguage.googleapis.com.
  • apps/tradinggoose/providers/ai/groq/index.ts#L264-266: pass a request-options second argument containing signal: request.abortSignal to every groq.chat.completions.create(...) call.
  • apps/tradinggoose/providers/ai/openrouter/index.ts#L258-260: pass a request-options second argument containing signal: request.abortSignal to every client.chat.completions.create(...) call.
  • apps/tradinggoose/providers/ai/xai/index.ts#L334-336: pass a request-options second argument containing signal: request.abortSignal to every xai.chat.completions.create(...) call.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/tradinggoose/providers/ai/google/index.ts` at line 1, Propagate
request.abortSignal to all model API calls in the executeRequest flows for
Google, Groq, OpenRouter, and xAI. Add signal: request.abortSignal to Google
fetch options for initial, check, streaming, and follow-up requests, and pass
the corresponding request-options object to every chat.completions.create call
in Groq, OpenRouter, and xAI, matching the existing vLLM pattern.
apps/tradinggoose/lib/auth/internal.ts (1)

40-45: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Validate timePolicyCapturedAt with the same strictness as the policy timestamps.

isWorkflowExecutionTimePolicy requires an exact ISO round-trip for processingStartedAt and expiresAt. This guard only requires Date.parse to return a finite value, so values such as "2026" or "Jan 1 2026" pass. The producer always emits new Date().toISOString(), so aligning the check costs nothing and keeps the claim format stable for downstream elapsed-time math.

♻️ Proposed change
-    typeof (value as Record<string, unknown>).timePolicyCapturedAt === 'string' &&
-    Number.isFinite(
-      Date.parse((value as Record<string, unknown>).timePolicyCapturedAt as string)
-    ) &&
+    typeof (value as Record<string, unknown>).timePolicyCapturedAt === 'string' &&
+    new Date(
+      Date.parse((value as Record<string, unknown>).timePolicyCapturedAt as string)
+    ).toISOString() === (value as Record<string, unknown>).timePolicyCapturedAt &&
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/tradinggoose/lib/auth/internal.ts` around lines 40 - 45, Update the
timePolicyCapturedAt validation in the surrounding auth claim guard to require
the same exact ISO round-trip format as processingStartedAt and expiresAt,
rather than only checking that Date.parse returns a finite value. Reuse the
existing timestamp-validation approach from isWorkflowExecutionTimePolicy while
preserving the surrounding type and policy checks.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/tradinggoose/app/admin/billing/billing-admin.tsx`:
- Around line 486-489: Make the dynamic feedback messages accessible to screen
readers by adding polite live-region semantics around the save-success Notice
rendered by the billing admin component; likewise add a polite live region for
the access-code success and validation feedback in subscription.tsx at lines
636-639. Preserve the existing Notice content and feedback behavior at both
sites.

In `@apps/tradinggoose/app/admin/billing/tier-editor.tsx`:
- Around line 1446-1463: Update the Input for workflowExecutionTimeLimitSeconds
in the tier editor to reject zero by requiring values greater than 0, aligning
client-side validation with the server and database constraints while preserving
the existing numeric input behavior.

In `@apps/tradinggoose/app/api/auth/`[...all]/route.ts:
- Line 86: Normalize pathname by removing a trailing slash before the guard
comparison in the route handler, so both `/api/auth/subscription/upgrade` and
its slash-suffixed form enter the session, reference authorization, and tier
availability checks. Preserve the existing POST-method requirement and exact
subscription upgrade path matching after normalization.

In `@apps/tradinggoose/executor/index.ts`:
- Around line 662-665: Update the shouldCancelExecution callback in the
execution options to abort this.abortController when either this.isCancelled or
the external contextExtensions.shouldCancelExecution callback returns true. Keep
deadlineExceeded handling separate and unchanged, and continue returning the
cancellation result.

In `@apps/tradinggoose/i18n/messages/en.json`:
- Around line 1463-1468: Implement the non-test renderer for
workspace.logs.details.deadline, mapping limitSeconds to the limit message’s
seconds placeholder and appliedTierName to the tier message’s tierName
placeholder. Ensure the deadline title, reason, limit, and tier translations are
consumed when rendering this log detail.

In `@apps/tradinggoose/i18n/messages/es.json`:
- Line 22160: Update the activeSubscriptionsWarning translation to replace
“suscripciones con derecho” with clear Spanish wording such as “suscripciones
con acceso vigente,” while preserving the message’s existing meaning about
archiving, the paid period, and renewal cancellation.

In `@apps/tradinggoose/i18n/messages/zh.json`:
- Line 22147: Update the activeSubscriptionsWarning translation to clearly state
that the tier has active subscriptions and that archiving preserves the current
paid period while canceling subsequent renewals.

In `@apps/tradinggoose/lib/auth/internal.test.ts`:
- Line 7: Replace the process.env assignments with deletion so the variables are
truly unset: use delete for INTERNAL_API_SECRET in
apps/tradinggoose/lib/auth/internal.test.ts:7-7 and for NEXT_PHASE in
apps/tradinggoose/lib/billing/plans.test.ts:29-29, including its assignments
inside the runtime-phase tests.

In `@apps/tradinggoose/lib/auth/internal.ts`:
- Around line 23-24: Update the child-workflow token validation and queue flow
around timePolicy and timePolicyCapturedAt to support a compatibility window for
pre-deploy tokens that verify as valid but lack the new fields. Delay
enforcement of the workflow execution policy until those legacy tokens can
expire, while ensuring missing policy data is never treated as a safe fallback.

In `@apps/tradinggoose/lib/billing/webhooks/invoices.ts`:
- Around line 46-54: Update the missing-subscription branch in the renewal
handler around getSubscriptionByStripeSubscriptionId to log the absence and
return immediately. Ensure the subsequent eligibility check and Stripe
cancellation path run only when a local subscription record exists, while
preserving cancellation for confirmed non-renewable local subscriptions.
- Around line 409-415: Update the cancellation/default-restoration flow around
handleStripeSubscriptionDeleted and ensureDefaultUserSubscription to clear
billingBlocked for both userStats and organizationBillingLedger before the early
return, ensuring canceled subscriptions settled through this path do not retain
the blocked state.

In `@apps/tradinggoose/lib/execution/workflow-execution-events.ts`:
- Around line 234-240: Update the isExecutionResult(storedResult) branch to
merge executionData.traceSpans into the returned stored-result object before
constructing result, preserving any existing stored trace spans while retaining
the current status, metadata, and failureReason behavior.

In `@apps/tradinggoose/lib/logs/execution/logger.ts`:
- Line 227: Replace the broad result?: object persisted by the execution logger
with a narrowed diagnostic-only type containing only the failure fields needed
for durable diagnostics, excluding output and BlockLog input/output payloads.
Apply the same type to SessionCompleteParams and SessionErrorCompleteParams in
logging-session.ts, then project results to that shape at the
execution-runner.ts call sites before persistence; preserve the existing
mergedExecutionData fields.

In `@apps/tradinggoose/providers/ai/gemini/core.ts`:
- Around line 126-128: Update executeToolCallsBatch to rethrow the caught error
when request.abortSignal.aborted is true, instead of converting an aborted
execution into a normal tool failure; preserve existing handling for non-abort
errors. Add a test that aborts every tool call and verifies executeGeminiRequest
rejects.

In `@apps/tradinggoose/services/queue/ExecutionLimiter.test.ts`:
- Around line 296-415: Ensure the tests using fake timers in the added
rate-limiter cases always restore real timers when assertions or setup fail.
Prefer adding an afterEach cleanup for this test suite that calls
vi.useRealTimers(), rather than relying only on each test’s final statement;
remove redundant per-test restoration only if appropriate.

In
`@apps/tradinggoose/widgets/widgets/workflow_console/components/terminal/components/status-display.test.tsx`:
- Around line 1-31: Set globalThis.IS_REACT_ACT_ENVIRONMENT to true at the start
of the StatusDisplay test setup, before either act call executes, so React
recognizes the Vitest jsdom environment and avoids the act-environment warning.

In `@packages/db/migrations/0040_wet_psylocke.sql`:
- Around line 13-16: Update the migration around
system_billing_tier_access_code_unique to create the unique index concurrently
through a separate non-transactional migration step or custom runner, avoiding
Drizzle’s transactional execution for that statement. Add the three CHECK
constraints with NOT VALID, then validate each constraint in a separate step
while preserving their existing conditions.

---

Outside diff comments:
In `@apps/tradinggoose/lib/logs/execution/logger.ts`:
- Around line 283-290: Stop persisting the full ExecutionResult in
logger.ts#L283-L290: define and use a narrowed type containing only deadline
diagnostics (code, deadline, and error), and persist only those fields alongside
traceSpans and finalOutput. Update SessionCompleteParams and
SessionErrorCompleteParams in
apps/tradinggoose/lib/logs/execution/logging-session.ts#L44-L59 to use the same
narrowed result type instead of ExecutionResult, and project those fields before
passing the result to completeWithError and complete in
apps/tradinggoose/lib/workflows/execution-runner.ts#L528-L555.

In `@apps/tradinggoose/tools/index.ts`:
- Around line 52-73: Propagate the captured workflow execution-time policy
through provider tool calls so nested internal workflows retain the original
tier policy and deadline. Update resolveExecutionScope in
apps/tradinggoose/tools/index.ts and every listed provider site to accept and
pass the captured policy or equivalent execution context; in
apps/tradinggoose/tools/index.ts lines 1103-1104 resolve the scope before
authentication and use the scoped internal-token generator, while preserving
abort propagation at lines 1188-1188. Apply the corresponding changes at all
listed provider file ranges.

---

Nitpick comments:
In `@apps/tradinggoose/app/api/admin/billing/tiers/route.test.ts`:
- Around line 5-11: Replace source-text assertions in
apps/tradinggoose/app/api/admin/billing/tiers/route.test.ts:5-11 with behavior
tests that invoke the create route using mocked persistence, asserting
access-code normalization, persistence, and duplicate-code handling through the
route’s uniqueness backstop. Update
apps/tradinggoose/lib/billing/tiers.test.ts:5-12 to invoke the exported tier
helpers with mocked persistence and assert both Stripe-backed and private-access
query results.

In `@apps/tradinggoose/background/workflow-execution.test.ts`:
- Around line 107-131: The test named “rejects a nested policy that expands the
inherited allowance” currently exercises malformed policy validation because
remainingMilliseconds exceeds limitSeconds, so it never reaches inherited-budget
comparison. Rename the test to describe malformed policy rejection, or update it
to provide a valid bounded policy and a real parent remaining budget, then
verify the nested child cannot increase that allowance while preserving the
existing no-execution assertions.

In `@apps/tradinggoose/components/ui/dropdown-menu.test.tsx`:
- Around line 31-44: Update the open-menu test around the DropdownMenu render to
first assert that the local container does not contain “Option,” then assert
that document.body contains it, confirming the menu renders through the required
Base UI portal.

In `@apps/tradinggoose/executor/handlers/function/function-handler.ts`:
- Around line 69-70: Update the executeTool call in the function handler to pass
the optional fifth parameter directly as context.abortSignal ? { signal:
context.abortSignal } : undefined, preserving stable call arity instead of
conditionally spreading an array argument.

In `@apps/tradinggoose/executor/handlers/workflow/workflow-handler.ts`:
- Around line 96-181: Add a no-op rejection handler immediately after creating
the eager child-execution promise in the IIFE assigned to wait, while keeping
the existing wait() accessor and eager-start behavior unchanged. Ensure the
handled promise does not alter the original rejection observed when wait() is
called.

In `@apps/tradinggoose/lib/admin/billing/access-code.ts`:
- Around line 22-30: Update isAccessCodeUniqueViolation to traverse the full
error.cause chain, checking each wrapped error for code 23505 and
constraint_name system_billing_tier_access_code_unique, while safely handling
unknown or cyclic causes. Preserve false for errors without a matching cause and
update the related unwrapped-error test only if its expected behavior
changes.</code>

In `@apps/tradinggoose/lib/admin/billing/snapshot.test.ts`:
- Around line 5-11: Replace the source-text assertions in the test with an
invocation of the snapshot function using a stubbed database. Assert the
returned snapshot object contains the expected entitledSubscriptionCount,
archiveAction, and accessCode values, and remove checks for symbol names such as
BILLING_ENTITLED_SUBSCRIPTION_STATUSES.

In `@apps/tradinggoose/lib/auth/internal.ts`:
- Around line 40-45: Update the timePolicyCapturedAt validation in the
surrounding auth claim guard to require the same exact ISO round-trip format as
processingStartedAt and expiresAt, rather than only checking that Date.parse
returns a finite value. Reuse the existing timestamp-validation approach from
isWorkflowExecutionTimePolicy while preserving the surrounding type and policy
checks.

In `@apps/tradinggoose/lib/billing/webhooks/invoices.ts`:
- Around line 74-77: Remove the idempotencyKey option from the
stripe.invoices.del call in the invoice webhook handling flow, leaving the
invoice ID and existing control flow unchanged.

In `@apps/tradinggoose/lib/billing/webhooks/subscription.test.ts`:
- Around line 344-346: Restore a test for the settlement-failure branch of
handleStripeSubscriptionDeleted by mocking
syncSubscriptionBillingTierFromStripeSubscription to reject. Assert that
settlement is skipped, the replacement subscription restores
stripeSubscriptionId, and the original error is rethrown.

In `@apps/tradinggoose/lib/billing/webhooks/subscription.ts`:
- Line 142: Add a warning in the subscription overage flow around the
`totalOverage` assignment when `subscription.tier` is missing, explicitly
recording that overage calculation was skipped; keep the zero fallback, and
ensure the existing “No overage to bill” log remains reserved for genuine
zero-overage cases.

In `@apps/tradinggoose/lib/execution/workflow-execution-time-budget.ts`:
- Around line 103-105: Update dispose() in the workflow execution time budget to
mark the instance disposed after clearing its timer, and ensure arm() rejects or
no-ops once disposed so late closeActivity or mergeChildRemaining calls cannot
create another timer. Preserve normal timer behavior before disposal.
- Around line 68-71: Update markQueuedChildWait to detect when slotId is absent
from this.activities and surface that caller error through the existing
project-appropriate debug log or assertion mechanism; retain the
queued-child-wait state update and syncPause behavior for registered slots.

In `@apps/tradinggoose/lib/execution/workflow-execution-time-policy.ts`:
- Around line 117-161: Validate processingStartedAt at the start of
createWorkflowExecutionTimePolicy by confirming it parses to a finite timestamp,
and throw a clear error when invalid. Perform this before the tier and
accounting branches so both unlimited and bounded policies reject invalid input
consistently.

In `@apps/tradinggoose/lib/workflows/execution-runner.ts`:
- Around line 476-493: In the bounded execution branch around
deadlineResultIfExpired and the Promise.race, replace the duplicated
deadline-result construction with the existing deadlineResultIfExpired() helper
after setting attemptClosed. Once the race settles, capture encryptedEnvVars
into a local constant before completing logging, and use that snapshot for the
terminal log’s variables so the losing attempt cannot change them.

In `@apps/tradinggoose/lib/workflows/workflow-execution-time-budget.test.ts`:
- Around line 1-3: Move the test file containing the AttemptTimeBudget tests
from the workflows test location to the execution directory beside
workflow-execution-time-budget, matching the co-located placement used by
workflow-execution-events.test.ts; preserve the test contents unchanged.

In `@apps/tradinggoose/providers/ai/google/index.ts`:
- Around line 528-530: Update the Gemini HTTP requests within executeRequest to
pass request.abortSignal through their fetch options, matching the cancellation
behavior already used by executeTool and the vLLM completion calls. Ensure every
generativelanguage.googleapis.com request in this provider honors the workflow
deadline.
- Line 1: Propagate request.abortSignal to all model API calls in the
executeRequest flows for Google, Groq, OpenRouter, and xAI. Add signal:
request.abortSignal to Google fetch options for initial, check, streaming, and
follow-up requests, and pass the corresponding request-options object to every
chat.completions.create call in Groq, OpenRouter, and xAI, matching the existing
vLLM pattern.

In `@apps/tradinggoose/providers/ai/groq/index.ts`:
- Around line 264-266: Update every groq.chat.completions.create call in this
file to pass a second request-options argument containing request.abortSignal,
matching the signal already supplied to executeTool. Ensure all Groq completion
calls honor cancellation without changing their existing request payloads.

In `@apps/tradinggoose/providers/ai/openrouter/index.ts`:
- Around line 258-260: Update the OpenRouter completion calls in the relevant
request flow to pass request options containing request.abortSignal as the
OpenAI client’s final argument to client.chat.completions.create(...). Apply
this consistently to every completion call in the file while preserving the
existing request payloads.

In `@apps/tradinggoose/providers/ai/xai/index.ts`:
- Around line 334-336: Update the xAI completion calls in the surrounding
request flow to pass request.abortSignal through the OpenAI request-options
argument of xai.chat.completions.create(...), matching the existing executeTool
cancellation behavior. Apply this to every completion call in the file while
preserving the current completion parameters.
🪄 Autofix

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 Plus

Run ID: 991217e0-f4ea-45b3-8733-09cb782e1bb6

📥 Commits

Reviewing files that changed from the base of the PR and between 6d860e0 and f3ebe4a.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (146)
  • apps/tradinggoose/app/(landing)/components/monitor-preview/fetch-listings.test.ts
  • apps/tradinggoose/app/(landing)/components/monitor-preview/fetch-listings.ts
  • apps/tradinggoose/app/admin/billing/billing-admin.test.tsx
  • apps/tradinggoose/app/admin/billing/billing-admin.tsx
  • apps/tradinggoose/app/admin/billing/tier-detail.test.tsx
  • apps/tradinggoose/app/admin/billing/tier-detail.tsx
  • apps/tradinggoose/app/admin/billing/tier-editor.test.tsx
  • apps/tradinggoose/app/admin/billing/tier-editor.tsx
  • apps/tradinggoose/app/api/admin/billing/tiers/[id]/route.test.ts
  • apps/tradinggoose/app/api/admin/billing/tiers/[id]/route.ts
  • apps/tradinggoose/app/api/admin/billing/tiers/route.test.ts
  • apps/tradinggoose/app/api/admin/billing/tiers/route.ts
  • apps/tradinggoose/app/api/auth/[...all]/route.test.ts
  • apps/tradinggoose/app/api/auth/[...all]/route.ts
  • apps/tradinggoose/app/api/billing/payg/activate/route.ts
  • apps/tradinggoose/app/api/billing/private-tier-access/route.test.ts
  • apps/tradinggoose/app/api/billing/private-tier-access/route.ts
  • apps/tradinggoose/app/api/billing/public-catalog/route.test.ts
  • apps/tradinggoose/app/api/logs/log-utils.test.ts
  • apps/tradinggoose/app/api/organizations/[id]/seats/route.test.ts
  • apps/tradinggoose/app/api/webhooks/test/route.test.ts
  • apps/tradinggoose/app/api/webhooks/test/route.ts
  • apps/tradinggoose/app/api/workflows/[id]/queue/route.test.ts
  • apps/tradinggoose/app/api/workflows/[id]/queue/route.ts
  • apps/tradinggoose/background/pending-execution-drain.test.ts
  • apps/tradinggoose/background/pending-execution-drain.ts
  • apps/tradinggoose/background/portfolio-monitor-execution.ts
  • apps/tradinggoose/background/schedule-execution.ts
  • apps/tradinggoose/background/webhook-execution.ts
  • apps/tradinggoose/background/workflow-execution.test.ts
  • apps/tradinggoose/background/workflow-execution.ts
  • apps/tradinggoose/components/ui/dropdown-menu.test.tsx
  • apps/tradinggoose/components/ui/dropdown-menu.tsx
  • apps/tradinggoose/executor/handlers/agent/agent-handler.ts
  • apps/tradinggoose/executor/handlers/api/api-handler.ts
  • apps/tradinggoose/executor/handlers/evaluator/evaluator-handler.ts
  • apps/tradinggoose/executor/handlers/function/function-handler.ts
  • apps/tradinggoose/executor/handlers/generic/generic-handler.ts
  • apps/tradinggoose/executor/handlers/router/router-handler.ts
  • apps/tradinggoose/executor/handlers/workflow/workflow-handler.test.ts
  • apps/tradinggoose/executor/handlers/workflow/workflow-handler.ts
  • apps/tradinggoose/executor/index.test.ts
  • apps/tradinggoose/executor/index.ts
  • apps/tradinggoose/executor/types.ts
  • apps/tradinggoose/global-navbar/settings-modal/components/subscription/subscription-permissions.test.ts
  • apps/tradinggoose/global-navbar/settings-modal/components/subscription/subscription-permissions.ts
  • apps/tradinggoose/global-navbar/settings-modal/components/subscription/subscription.test.tsx
  • apps/tradinggoose/global-navbar/settings-modal/components/subscription/subscription.tsx
  • apps/tradinggoose/hooks/queries/admin-billing.test.tsx
  • apps/tradinggoose/hooks/queries/admin-billing.ts
  • apps/tradinggoose/hooks/queries/private-tier-access.test.tsx
  • apps/tradinggoose/hooks/queries/private-tier-access.ts
  • apps/tradinggoose/i18n/messages/en.json
  • apps/tradinggoose/i18n/messages/es.json
  • apps/tradinggoose/i18n/messages/zh.json
  • apps/tradinggoose/i18n/request-locale.test.ts
  • apps/tradinggoose/i18n/request-locale.ts
  • apps/tradinggoose/lib/admin/billing/access-code.test.ts
  • apps/tradinggoose/lib/admin/billing/access-code.ts
  • apps/tradinggoose/lib/admin/billing/snapshot.test.ts
  • apps/tradinggoose/lib/admin/billing/snapshot.ts
  • apps/tradinggoose/lib/admin/billing/tier-mutations.test.ts
  • apps/tradinggoose/lib/admin/billing/tier-mutations.ts
  • apps/tradinggoose/lib/admin/billing/types.ts
  • apps/tradinggoose/lib/api/rate-limit.test.ts
  • apps/tradinggoose/lib/api/rate-limit.ts
  • apps/tradinggoose/lib/auth.ts
  • apps/tradinggoose/lib/auth/internal.test.ts
  • apps/tradinggoose/lib/auth/internal.ts
  • apps/tradinggoose/lib/billing/authorization.ts
  • apps/tradinggoose/lib/billing/catalog.test.ts
  • apps/tradinggoose/lib/billing/catalog.ts
  • apps/tradinggoose/lib/billing/core/subscription.test.ts
  • apps/tradinggoose/lib/billing/core/subscription.ts
  • apps/tradinggoose/lib/billing/plans.test.ts
  • apps/tradinggoose/lib/billing/plans.ts
  • apps/tradinggoose/lib/billing/private-tier-access.ts
  • apps/tradinggoose/lib/billing/public-catalog.ts
  • apps/tradinggoose/lib/billing/subscription-tier-display.test.ts
  • apps/tradinggoose/lib/billing/subscription-tier-display.ts
  • apps/tradinggoose/lib/billing/tier-availability-policy.test.ts
  • apps/tradinggoose/lib/billing/tier-availability-policy.ts
  • apps/tradinggoose/lib/billing/tier-summary.ts
  • apps/tradinggoose/lib/billing/tiers.test.ts
  • apps/tradinggoose/lib/billing/tiers.ts
  • apps/tradinggoose/lib/billing/types/index.ts
  • apps/tradinggoose/lib/billing/webhooks/invoices.test.ts
  • apps/tradinggoose/lib/billing/webhooks/invoices.ts
  • apps/tradinggoose/lib/billing/webhooks/subscription.test.ts
  • apps/tradinggoose/lib/billing/webhooks/subscription.ts
  • apps/tradinggoose/lib/execution/pending-execution.test.ts
  • apps/tradinggoose/lib/execution/pending-execution.ts
  • apps/tradinggoose/lib/execution/workflow-execution-events.test.ts
  • apps/tradinggoose/lib/execution/workflow-execution-events.ts
  • apps/tradinggoose/lib/execution/workflow-execution-time-budget.ts
  • apps/tradinggoose/lib/execution/workflow-execution-time-policy.test.ts
  • apps/tradinggoose/lib/execution/workflow-execution-time-policy.ts
  • apps/tradinggoose/lib/logs/execution/logger.ts
  • apps/tradinggoose/lib/logs/execution/logging-session.ts
  • apps/tradinggoose/lib/logs/execution/trace-spans/trace-spans.test.ts
  • apps/tradinggoose/lib/logs/execution/trace-spans/trace-spans.ts
  • apps/tradinggoose/lib/logs/types.ts
  • apps/tradinggoose/lib/subscription/upgrade.ts
  • apps/tradinggoose/lib/workflows/execution-result.test.ts
  • apps/tradinggoose/lib/workflows/execution-result.ts
  • apps/tradinggoose/lib/workflows/execution-runner.test.ts
  • apps/tradinggoose/lib/workflows/execution-runner.ts
  • apps/tradinggoose/lib/workflows/workflow-execution-time-budget.test.ts
  • apps/tradinggoose/package.json
  • apps/tradinggoose/providers/ai/anthropic/core.ts
  • apps/tradinggoose/providers/ai/anthropic/index.ts
  • apps/tradinggoose/providers/ai/azure-openai/index.ts
  • apps/tradinggoose/providers/ai/bedrock/index.ts
  • apps/tradinggoose/providers/ai/cerebras/index.ts
  • apps/tradinggoose/providers/ai/deepseek/index.ts
  • apps/tradinggoose/providers/ai/fireworks/index.ts
  • apps/tradinggoose/providers/ai/gemini/core.ts
  • apps/tradinggoose/providers/ai/google/index.ts
  • apps/tradinggoose/providers/ai/groq/index.ts
  • apps/tradinggoose/providers/ai/mistral/index.ts
  • apps/tradinggoose/providers/ai/ollama/index.ts
  • apps/tradinggoose/providers/ai/openai/index.ts
  • apps/tradinggoose/providers/ai/openrouter/index.ts
  • apps/tradinggoose/providers/ai/vllm/index.ts
  • apps/tradinggoose/providers/ai/xai/index.ts
  • apps/tradinggoose/proxy.ts
  • apps/tradinggoose/scripts/test-billing-suite.ts
  • apps/tradinggoose/services/queue/ExecutionLimiter.test.ts
  • apps/tradinggoose/services/queue/ExecutionLimiter.ts
  • apps/tradinggoose/stores/console/store.test.ts
  • apps/tradinggoose/stores/console/store.ts
  • apps/tradinggoose/stores/organization/store.ts
  • apps/tradinggoose/stores/organization/types.ts
  • apps/tradinggoose/tools/index.test.ts
  • apps/tradinggoose/tools/index.ts
  • apps/tradinggoose/widgets/widgets/editor_workflow/components/workflow-block/components/sub-block/components/dropdown.tsx
  • apps/tradinggoose/widgets/widgets/workflow_console/components/terminal/components/status-display.test.tsx
  • apps/tradinggoose/widgets/widgets/workflow_console/components/terminal/components/status-display.tsx
  • apps/tradinggoose/widgets/widgets/workflow_console/components/terminal/terminal.tsx
  • packages/db/migrations/0040_wet_psylocke.sql
  • packages/db/migrations/meta/0040_snapshot.json
  • packages/db/migrations/meta/_journal.json
  • packages/db/schema/billing.ts
  • packages/db/schema/system.ts
  • packages/python-sdk/tradinggoose/__init__.py
  • packages/ts-sdk/src/index.ts
💤 Files with no reviewable changes (3)
  • apps/tradinggoose/widgets/widgets/editor_workflow/components/workflow-block/components/sub-block/components/dropdown.tsx
  • apps/tradinggoose/stores/organization/types.ts
  • apps/tradinggoose/stores/organization/store.ts

Comment thread apps/tradinggoose/app/admin/billing/billing-admin.tsx
Comment thread apps/tradinggoose/app/admin/billing/tier-editor.tsx
Comment thread apps/tradinggoose/app/api/auth/[...all]/route.ts
Comment thread apps/tradinggoose/executor/index.ts
Comment thread apps/tradinggoose/i18n/messages/en.json
Comment thread apps/tradinggoose/lib/logs/execution/logger.ts
Comment thread apps/tradinggoose/providers/ai/gemini/core.ts
Comment thread apps/tradinggoose/services/queue/ExecutionLimiter.test.ts
Comment thread packages/db/migrations/0040_wet_psylocke.sql
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