Skip to content

feat(console): route Indexer and search through CONSOLE_DATA_API_URL - #136

Merged
Travis-Gilbert merged 1 commit into
mainfrom
cursor/console-single-door-1-0
Jul 27, 2026
Merged

feat(console): route Indexer and search through CONSOLE_DATA_API_URL#136
Travis-Gilbert merged 1 commit into
mainfrom
cursor/console-single-door-1-0

Conversation

@Travis-Gilbert

@Travis-Gilbert Travis-Gilbert commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Summary

  • Cut Indexer board objects and RustyWeb search over to the consumer GraphQL door (CONSOLE_DATA_API_URL).
  • Keep named MCP exceptions (Plan, Program, presence/runs, preview assets).
  • Record the cutover in docs/records/011-console-single-door.md (HANDOFF-CONSOLE-SINGLE-DOOR-1.0).

Test plan

  • vitest for consumer-graphql + indexer-harness
  • With Theorem commonplace-api deployed: Indexer board loads without CONSOLE_HARNESS_* on that path
  • Live search returns tenant-scoped candidates via rustyWebSearch
  • Grep client bundle: no private bearer for board/search paths

Summary by CodeRabbit

  • New Features

    • Indexer data is now retrieved through the console’s shared GraphQL data service.
    • Web research now uses tenant-scoped GraphQL search with improved timeout, configuration, authentication, and error handling.
    • Added a standardized allowlist for live web-search providers.
  • Bug Fixes

    • Improved endpoint selection and URL normalization for console data requests.
    • Enhanced reporting of search and indexer service failures.
  • Documentation

    • Added documentation describing the console’s single-door data access model and remaining service exceptions.

Cut board and RustyWeb search over to the consumer GraphQL door so private MCP/node tokens stay off those paths (HANDOFF-CONSOLE-SINGLE-DOOR-1.0).

Co-authored-by: Cursor <cursoragent@cursor.com>
Copilot AI review requested due to automatic review settings July 27, 2026 23:35
@ecc-tools

ecc-tools Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Console GraphQL routing now prioritizes the data API door. Indexer object reads and RustyWeb searches use authenticated, timed consumer GraphQL requests, with updated error handling, tests, and single-door documentation.

Changes

Console single-door GraphQL routing

Layer / File(s) Summary
Consumer data-door selection
apps/console/src/lib/server/consumer-graphql.ts, apps/console/src/lib/server/consumer-graphql.test.ts, docs/records/011-console-single-door.md
consumerGraphqlUrl trims and prioritizes CONSOLE_DATA_API_URL, with tests and documentation describing the consumer single-door routing model.
Indexer consumer transport
apps/console/src/lib/server/indexer-harness.ts, apps/console/src/lib/server/indexer-harness.test.ts
Indexer object reads now perform authenticated, timed consumer GraphQL requests and return normalized transport or GraphQL errors; preview asset loading retains dynamic harness GraphQL access.
RustyWeb consumer search
apps/console/src/lib/server/web-research.ts
Web research now queries tenant-scoped rustyWebSearch through consumer GraphQL, sends the live provider allowlist, handles timeouts and GraphQL failures, and parses the GraphQL response envelope.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested reviewers: copilot

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% 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 matches the main change: routing Indexer and search through CONSOLE_DATA_API_URL.
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
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/console-single-door-1-0

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.

@Travis-Gilbert
Travis-Gilbert merged commit 660824d into main Jul 27, 2026
5 of 10 checks passed

Copilot AI left a comment

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.

Pull request overview

This PR routes the Console’s Indexer object reads and RustyWeb live search through the CommonPlace consumer GraphQL door (CONSOLE_DATA_API_URL), while documenting the “single door” cutover and leaving explicit MCP-only exceptions in place.

Changes:

  • Switch Indexer board object loading to use consumer GraphQL over CONSOLE_DATA_API_URL (with upstream credential headers + timeouts).
  • Switch web research (RustyWeb search) to call the consumer GraphQL rustyWebSearch field over CONSOLE_DATA_API_URL.
  • Add/adjust tests and record the cutover in an ADR-style doc.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
docs/records/011-console-single-door.md Adds a record describing the single-door rule, cutover evidence, and remaining MCP exceptions.
apps/console/src/lib/server/web-research.ts Replaces the Node /v1/rustyweb/search call with a consumer GraphQL rustyWebSearch call.
apps/console/src/lib/server/indexer-harness.ts Replaces MCP GraphQL transport for topicIndexerObjects with consumer GraphQL transport; keeps preview assets on MCP.
apps/console/src/lib/server/indexer-harness.test.ts Updates Indexer transport tests for the new fetch-based consumer GraphQL path.
apps/console/src/lib/server/consumer-graphql.ts Updates endpoint selection to prefer CONSOLE_DATA_API_URL.
apps/console/src/lib/server/consumer-graphql.test.ts Adds coverage for preferring CONSOLE_DATA_API_URL when both env vars exist.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +14 to 19
const configured =
environment.CONSOLE_DATA_API_URL?.trim()
|| environment.THEOREM_GRAPHQL_URL?.trim();
if (!configured) return null;

const base = configured.replace(/\/+$/, '');
Comment on lines +93 to +100
if (!upstream.ok || payload?.errors || !payload?.data) {
const detail = payload?.errors?.[0]?.message;
return {
ok: false,
status: upstream.ok ? 502 : upstream.status,
error: typeof detail === 'string' ? detail : indexerTransportError(upstream.status, timeout.didTimeout()),
};
}
Comment on lines +113 to +117
function indexerTransportError(status: number, timedOut: boolean): string {
if (timedOut) return 'indexer_graphql_timeout';
if (status === 404) return 'indexer_graphql_unconfigured';
return 'indexer_graphql_failed';
}
Comment on lines +142 to 145
// Preview assets remain on the agent GraphQL surface until commonplace-api
// mounts topicPreviewAsset; Indexer object reads already use the data door.
const { callHarnessGraphql } = await import('@/lib/server/harness-graphql');
const result = await callHarnessGraphql(
Comment on lines +91 to 96
it('maps transport failures to the Indexer vocabulary', async () => {
fetchMock.mockResolvedValue({
ok: false,
status: 504,
error: 'harness_graphql_timeout',
json: async () => ({ errors: [{ message: 'timeout' }] }),
});

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 70e4108b50

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +14 to +16
const configured =
environment.CONSOLE_DATA_API_URL?.trim()
|| environment.THEOREM_GRAPHQL_URL?.trim();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve credentials for existing consumer GraphQL callers

When CONSOLE_DATA_API_URL is configured, this redirects every consumerGraphqlUrl() caller to commonplace-api, but proactivity-harness.ts and filing-harness.ts still authenticate exclusively with THEOREM_API_KEY rather than CONSOLE_DATA_API_KEY. In the documented Railway configuration where the data API has its own key, both existing surfaces will receive 403 responses; either scope the new endpoint selection to Indexer/search or migrate those callers' credentials simultaneously.

AGENTS.md reference: apps/console/AGENTS.md:L33-L36

Useful? React with 👍 / 👎.

readonly includeCaptures?: boolean;
}): Promise<IndexerRead> {
const result = await callHarnessGraphql(INDEXER_OBJECTS_QUERY, {
const result = await executeConsumerGraphql(INDEXER_OBJECTS_QUERY, {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Add the Indexer field before switching GraphQL schemas

This switches Indexer reads to the consumer schema, but a repo-wide search of this commit's apps/commonplace-api implementation finds no topicIndexerObjects field; the Query implementation beginning at apps/commonplace-api/src/schema/mod.rs:1808 does not declare it. Consequently commonplace-api returns a GraphQL unknown-field error for every Indexer object read, whereas the previous MCP schema owned this field.

AGENTS.md reference: AGENTS.md:L27-L27

Useful? React with 👍 / 👎.

Comment on lines +45 to +47
query ConsoleRustyWebSearch($query: String!, $limit: Int, $providers: [String!]) {
rustyWebSearch(query: $query, limit: $limit, providers: $providers)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Add the RustyWeb field before routing search to commonplace-api

The new request queries rustyWebSearch, but a repo-wide search of this commit's apps/commonplace-api schema and source finds no such field or resolver. Thus both Composer web research and Indexer live search receive an unknown-field GraphQL error from the configured data API and return 502 instead of results; the consumer field needs to land with this transport cutover.

Useful? React with 👍 / 👎.

Comment on lines +113 to +117
} finally {
timeout.clear();
}

if (!upstream.ok) {
const envelope = await upstream.json().catch(() => null) as {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep the timeout active while reading the response body

When the data API sends response headers but delays or stalls its JSON body, fetch() resolves and this finally clears the abort timer before upstream.json() starts on line 117. That leaves both Composer and Indexer search requests able to hang indefinitely despite the configured timeout; parse the body inside the timed try and clear the timer only after parsing completes.

Useful? React with 👍 / 👎.

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

🧹 Nitpick comments (2)
apps/console/src/lib/server/indexer-harness.test.ts (1)

91-102: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Test doesn't actually exercise indexerTransportError's vocabulary mapping.

This test's asserted error: 'timeout' comes from the raw GraphQL errors[0].message passthrough, not from indexerTransportError. None of that function's three branches (timeout / 404-unconfigured / generic-failed) are covered by a case without a string errors[0].message. Consider adding a case with a non-string/absent error detail to confirm the normalized vocabulary is actually returned.

🤖 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/console/src/lib/server/indexer-harness.test.ts` around lines 91 - 102,
The test for readIndexerObjects currently validates raw GraphQL error-message
passthrough rather than indexerTransportError's vocabulary mapping. Update or
add cases that omit errors[0].message or provide a non-string detail, covering
the timeout, 404-unconfigured, and generic-failed branches, and assert each
normalized vocabulary value.
apps/console/src/lib/server/indexer-harness.ts (1)

53-111: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consumer-GraphQL transport logic duplicated across two files. executeConsumerGraphql and loadWebResearch independently implement the same endpoint-check, credential-resolution, timed-fetch-with-headers, and envelope-parsing sequence; the shared root cause is the lack of a common helper in consumer-graphql.ts for this transport shape.

  • apps/console/src/lib/server/indexer-harness.ts#L53-L111: extract the endpoint/credential/timeout/fetch/envelope logic into a shared helper (e.g. in consumer-graphql.ts) and have executeConsumerGraphql delegate to it, keeping only the Indexer-specific principal resolution and result shape here.
  • apps/console/src/lib/server/web-research.ts#L51-L116: adopt the same shared helper for the fetch/timeout/envelope portion, keeping only the RustyWeb-specific query/variables and source extraction 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/console/src/lib/server/indexer-harness.ts` around lines 53 - 111, The
Consumer-GraphQL transport sequence is duplicated and should be centralized. In
apps/console/src/lib/server/indexer-harness.ts#L53-L111, extract endpoint
validation, credential resolution, timeout-managed fetch, and envelope parsing
from executeConsumerGraphql into a shared helper in consumer-graphql.ts, leaving
principal resolution and the Indexer-specific result shape local. In
apps/console/src/lib/server/web-research.ts#L51-L116, replace the duplicated
transport logic in loadWebResearch with that helper while retaining its RustyWeb
query/variables and source extraction.
🤖 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/console/src/lib/server/indexer-harness.ts`:
- Around line 93-99: Stop returning raw upstream GraphQL messages from
executeConsumerGraphql and loadWebResearch. In
apps/console/src/lib/server/indexer-harness.ts lines 93-99, log the extracted
detail server-side and always return the fixed indexerTransportError(...)
result; in apps/console/src/lib/server/web-research.ts lines 122-134, log the
upstream detail and return the existing generic refusal message instead.

---

Nitpick comments:
In `@apps/console/src/lib/server/indexer-harness.test.ts`:
- Around line 91-102: The test for readIndexerObjects currently validates raw
GraphQL error-message passthrough rather than indexerTransportError's vocabulary
mapping. Update or add cases that omit errors[0].message or provide a non-string
detail, covering the timeout, 404-unconfigured, and generic-failed branches, and
assert each normalized vocabulary value.

In `@apps/console/src/lib/server/indexer-harness.ts`:
- Around line 53-111: The Consumer-GraphQL transport sequence is duplicated and
should be centralized. In
apps/console/src/lib/server/indexer-harness.ts#L53-L111, extract endpoint
validation, credential resolution, timeout-managed fetch, and envelope parsing
from executeConsumerGraphql into a shared helper in consumer-graphql.ts, leaving
principal resolution and the Indexer-specific result shape local. In
apps/console/src/lib/server/web-research.ts#L51-L116, replace the duplicated
transport logic in loadWebResearch with that helper while retaining its RustyWeb
query/variables and source extraction.
🪄 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 Plus

Run ID: cb7a7761-9315-4658-bd6d-ddf3249f035e

📥 Commits

Reviewing files that changed from the base of the PR and between 6bc0869 and 70e4108.

📒 Files selected for processing (6)
  • apps/console/src/lib/server/consumer-graphql.test.ts
  • apps/console/src/lib/server/consumer-graphql.ts
  • apps/console/src/lib/server/indexer-harness.test.ts
  • apps/console/src/lib/server/indexer-harness.ts
  • apps/console/src/lib/server/web-research.ts
  • docs/records/011-console-single-door.md

Comment on lines +93 to +99
if (!upstream.ok || payload?.errors || !payload?.data) {
const detail = payload?.errors?.[0]?.message;
return {
ok: false,
status: upstream.ok ? 502 : upstream.status,
error: typeof detail === 'string' ? detail : indexerTransportError(upstream.status, timeout.didTimeout()),
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Files:"
git ls-files | rg 'apps/console/src/lib/server/(indexer-harness|web-research)\.ts$' || true

echo
echo "indexer-harness outline:"
ast-grep outline apps/console/src/lib/server/indexer-harness.ts --view expanded || true

echo
echo "web-research outline:"
ast-grep outline apps/console/src/lib/server/web-research.ts --view expanded || true

echo
echo "Relevant slices:"
wc -l apps/console/src/lib//.
sed -n '1,140p' apps/console/src/lib/server/indexer-harness.ts
echo '--- web-research 1-170 ---'
sed -n '1,170p' apps/console/src/lib/server/web-research.ts

Repository: Travis-Gilbert/CommonPlace

Length of output: 1511


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- indexer-harness 93-130, 174-210 ---'
sed -n '93,130p' apps/console/src/lib/server/indexer-harness.ts
sed -n '174,210p' apps/console/src/lib/server/indexer-harness.ts

echo
echo '--- web-research 120-145 ---'
sed -n '120,145p' apps/console/src/lib/server/web-research.ts

echo
echo '--- GraphQL error message fields in consumer-graphql helpers ---'
rg -n "errors\\?\\.\\[0\\]\\.message|envelope\\?.*errors|GRAPHQL|THEOREM|CONSOLE_HARNESS|graphql_query" apps/console/src/lib/server apps/console/src -g '*.ts' -g '*.tsx' | head -200

Repository: Travis-Gilbert/CommonPlace

Length of output: 19733


Do not expose raw upstream GraphQL error messages. Both executeConsumerGraphql and loadWebResearch return errors[0].message directly to clients when it is a string; log that detail server-side and return fixed local error text/codes (indexerTransportError(...) for the indexer path and the existing generic refusal message for web research) instead.

📍 Affects 2 files
  • apps/console/src/lib/server/indexer-harness.ts#L93-L99 (this comment)
  • apps/console/src/lib/server/web-research.ts#L122-L134
🤖 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/console/src/lib/server/indexer-harness.ts` around lines 93 - 99, Stop
returning raw upstream GraphQL messages from executeConsumerGraphql and
loadWebResearch. In apps/console/src/lib/server/indexer-harness.ts lines 93-99,
log the extracted detail server-side and always return the fixed
indexerTransportError(...) result; in
apps/console/src/lib/server/web-research.ts lines 122-134, log the upstream
detail and return the existing generic refusal message instead.

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