Skip to content

feat(remote): resolve backend URL from page origin instead of hardcod of hardcoded localhost#44

Merged
Gracker merged 1 commit intoGracker:mainfrom
heihei-github:feat/remote-backend-url
May 6, 2026
Merged

feat(remote): resolve backend URL from page origin instead of hardcod of hardcoded localhost#44
Gracker merged 1 commit intoGracker:mainfrom
heihei-github:feat/remote-backend-url

Conversation

@heihei-github
Copy link
Copy Markdown
Contributor

4-layer fix that derives the backend address dynamically from window.location.hostname so the same build works on localhost, LAN IP, or a public server without reconfiguration:

  • CSP: inject current hostname into connect-src whitelist at runtime
  • BackendUploader: add setDefaultBackendUrl() for pre-trace injection
  • AI plugin: module-level IIFE sets backend URL from page origin
  • Settings: auto-derive backendUrl when user hasn't set a custom one
  • CORS: collect all non-loopback IPv4 addresses at startup

Change-Id: I1dc49a37a0966e1da2d444419a61471cc74c8a76

Summary

  • Derive backend URL from window.location.hostname so the same build works on localhost, LAN IP, or a public server without reconfiguration
  • CSP (connect-src) already present in upstream perfetto — this PR completes the remaining 4 layers
  • Includes TS type fix for os.NetworkInterfaceInfo namespace error

Change Type

  • feat (new capability)

Affected Areas

  • backend/src/agentv3/ (config: getNonLoopbackOrigins CORS helper)
  • perfetto/ui/src/plugins/com.smartperfetto.AIAssistant/ (frontend: plugin + session_manager + backend_uploader)

Done Conditions

  • npm run test:scene-trace-regression from backend/ -> all 6 traces passed
  • npx tsc --noEmit from backend/ -> green

Test Plan

  1. cd backend && npm run test:scene-trace-regression — passes (6/6 traces)
  2. cd backend && npx tsc --noEmit — no errors
  3. Manual: load via http://localhost:10000 -> backend connects to localhost:3000
  4. Manual: load via http://:10000 -> backend auto-connects to http://:3000

Risk / Rollback

Low risk. Changes are additive (new helper function, IIFE, settings override) with no existing behavior modified. Rollback: revert the commit.

Notes for Reviewers

Perfetto submodule points to commit f8ff26c8a (branch feat/remote-backend-url). This commit needs to exist on Gracker/perfetto before the submodule pointer resolves. CSP layer (http://${location.hostname}:3000 in connect-src) was
already merged upstream — see ui/src/frontend/index.ts line 177.

Copy link
Copy Markdown
Owner

@Gracker Gracker left a comment

Choose a reason for hiding this comment

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

Requesting changes. The SmartPerfetto wrapper does not yet make the remote/public-host setup work reliably without configuration. Please update the CORS strategy before landing.

Comment thread backend/src/config/index.ts Outdated
for (const iface of Object.values(os.networkInterfaces())) {
for (const info of (iface ?? [])) {
if (info.family === 'IPv4' && !info.internal) {
origins.push(`http://${info.address}:10000`);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This only whitelists origins built from local non-loopback IPv4 addresses. It does not cover access through a hostname, public DNS name, or NAT/public IP, while the Perfetto-side change derives the backend URL from window.location.hostname. In those cases the browser origin can be http://my-host:10000 but serverConfig.corsOrigins will only include values like http://192.168.x.x:10000, so browser requests to http://my-host:3000 can still fail CORS. Please support the same hostname/public-host deployment path here, or document and require explicit CORS_ORIGINS instead of claiming it works without reconfiguration.

huang8604 pushed a commit to huang8604/SmartPerfetto that referenced this pull request May 6, 2026
Replace the monolithic "any code change → trace regression" rule with
an explicit four-tier policy that distinguishes work that genuinely
exercises agent behavior from contract / type-only and CRUD-only
changes that don't:

- Contract / type-only (`backend/src/types/sparkContracts.ts` etc.)
  → `npx tsc --noEmit` + the sparkContracts.test.ts case for that
  contract.
- CRUD-only service (file IO, no agent path touched)
  → that service's own `__tests__/<name>.test.ts`.
- Touches mcp / memory / report / agent runtime
  → `npm run test:scene-trace-regression` (the existing 6-trace gate).
- PR landing
  → `npm run verify:pr` (strict full gate, unchanged).

The new policy is inlined consistently in all 7 rule documents — keeping
fresh clones self-contained — and the wording is identical across files
so future drift is easy to spot.

Files touched: CLAUDE.md, AGENTS.md, docs/development/testing.md,
README.md, README.zh-CN.md, CONTRIBUTING.md,
docs/getting-started/quick-start.md.

Motivation: subsequent Spark contract scaffold commits (Gracker#41 / Gracker#44 / Gracker#50
/ Gracker#54 / Gracker#55) only add types to sparkContracts.ts and add unit tests.
Running the full 6-trace regression on each adds minutes per commit
without exercising any code path the contract touches. The tiered
policy keeps the strict gate where it earns its keep (anything wired
into the agent runtime, plus PR landing) while letting type-only work
finish in seconds. The trace regression command itself is unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
huang8604 pushed a commit to huang8604/SmartPerfetto that referenced this pull request May 6, 2026
Land Plan 44 (Spark Gracker#94, Gracker#95) — project / world memory plus the
feedback → case → skill draft pipeline.

Critical invariant: this contract does NOT modify the existing
session-scope `analysisPatternMemory.ts`. Plan 44 introduces an
independent project + world store at runtime
(`backend/src/agentv3/projectMemory.ts`, landed in D-phase). The
existing 200-entry session store, weighted Jaccard matching, and
supersede integration stay untouched.

Types added to `backend/src/types/sparkContracts.ts`:

- `ProjectMemoryStatus` — 5-state status machine inlined to keep
  `backend/src/types/` independent of `backend/src/agentv3/`. Mirrors
  agentv3's PatternStatus including `disputed_late`. Doc note flags
  that the two unions must stay in sync; if agentv3 changes, mirror
  the change here.
- `ProjectMemoryEntry` — one entry. Carries optional `promotionPolicy`;
  the Plan 44 service layer (`projectMemory.saveProjectMemoryEntry`)
  enforces that a `'world'`-scope entry MUST have a policy. Schema
  itself keeps it optional so older snapshots remain readable.
- `FeedbackPipelineEntry` — feedback pipeline state. Uses the shared
  `CaseRef` from C0 base types so this contract does NOT depend on
  Plan 54's CaseNode shape, breaking the Gracker#44Gracker#54 schema cycle that
  Codex flagged in round 1.
- `MemoryRagSelfImprovementContract` — service surface bundling
  entries + pipeline + recent RAG retrievals.

Storage location for project + world entries:
`backend/logs/analysis_project_memory.json` with shape
`{entries: ProjectMemoryEntry[], promotionAudit: ...}`. Audit log
schema is finalized in §4.3 of the design doc.

Five new test cases in `__tests__/sparkContracts.test.ts` cover:

- ProjectMemoryStatus matches the 5-state machine, no `auto_inferred`
- project entry can omit promotionPolicy
- world entry carries promotionPolicy with reviewer for audit
- FeedbackPipelineEntry uses CaseRef shape, not CaseNode
- contract bundles entries + pipeline + recent retrievals

Test count: 55 (was 50).

Test tier: contract / type-only. `npx tsc --noEmit` clean,
sparkContracts.test.ts passes 55/55. Trace regression intentionally
not run per the tiered policy in commit d8529e1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@heihei-github heihei-github force-pushed the feat/remote-backend-url branch 5 times, most recently from c828e29 to 67479f6 Compare May 6, 2026 07:52
- Backend: replace static whitelist with port 10000 check in CORS middleware
- Perfetto: update submodule to feat/remote-backend-url (URL derivation)
- Fixes remote/public-host deployment where hostname != local IP

Change-Id: I9fba5e72236046df30ee2fe44b8c2179194da0cc
@heihei-github heihei-github force-pushed the feat/remote-backend-url branch from 67479f6 to 2889dbd Compare May 6, 2026 07:57
@heihei-github
Copy link
Copy Markdown
Contributor Author

@Gracker 已按反馈重新实现:

cors({ origin: corsOrigins }) 改成了 origin 校验函数,
不再依赖启动时枚举的局域网 IP 白名单——任意 origin 只要
URL(origin).port === '10000' 就放行,无 Origin 头(curl/
服务端)也放行,其他一律拒绝。

这样 localhost / LAN IP / hostname / 公网 DNS 都能覆盖,
你之前提到的 http://my-host:10000 场景已通过。

Copy link
Copy Markdown
Owner

@Gracker Gracker left a comment

Choose a reason for hiding this comment

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

Verified the updated CORS strategy and the submodule pointer. SmartPerfetto root verify:pr passed on the PR head with the updated perfetto submodule.

@Gracker Gracker merged commit 2fa0583 into Gracker:main May 6, 2026
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