You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
connector-rest: a baseUrl that carries a query string puts the request path inside the query (buildUrl joins base + path as text) #28736
Filing gate: ① a product defect with a named location.reach: a real producer: the dogfood pin connector-meta-door-entry-and-url-hardening.dogfood.test.ts (PR #28688) dispatches with an empty path specifically to avoid this. The contract review of #28688 (comment 6560432824, ③ 5) confirmed it from the code. Not measured at a public door with a path-bearing action.
Business reason: a REST connector whose baseUrl carries a fixed query parameter (?region=eu, ?api-version=2024-01, a common provider pattern) sends every path-bearing action to the wrong URL. The request goes to the base resource with a malformed query, so the author sees provider 404s or wrong data with no hint why.
Reader: the connector-rest owner (packages/connectors/connector-rest), one small PR with a unit test.
Dedupe (open AND closed): "buildUrl baseUrl query" → 0 hits; "connector-rest buildUrl" → 1 hit (#20590, closed; a different topic).
⛔ Not a claim.
Where
packages/connectors/connector-rest/src/rest-connector.ts, buildUrl (around line 104 on main):
With baseUrl = 'https://api.example.com/v1?region=eu' and path = '/items', the text join gives https://api.example.com/v1?region=eu/items. The path becomes part of the region value, and the request goes to /v1.
Expected
Parse the base first, append the path to url.pathname (one slash between), keep the base's own query parameters, then merge the action's query (the action's value wins on a clash, or the clash is refused; say which). A unit test should cover a base with a query plus a path, a base with a trailing slash, and an empty path.
Claim: PM loop round 4 · card thread · 2026-11-01T17:35Z
Session: session_0186vfjHHMsRXC9EUT9hTFMo (the seat); the card thread is session_01FEkQ5oht6tMAsnKGYsgbiT
Account: os-project-manager (the seat's linked user; the card's assignee)
Branch: claude/project-thread-efkbrl (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
Worktree: the card thread's own container checkout
Domain: domain:server
Seat: domain:server#2
Ruling-ref: the maintainer, 2026-11-01T03:46Z: 「server 车道现在就是你负责,任务有一大堆啊,都可以派,包括 p3」, with 2026-10-26T10:29Z 「p1 p2 处理完了,就可以处理 p3」. With 2026-11-01T12:11Z 「定级你可以自己决定」; graded p2 by triage (2026-11-01T16:58Z).
File surface: packages/connectors/connector-rest/src/rest-connector.ts (buildUrl), its unit tests, the connector URL-hardening dogfood pin; changeset
Container & model: M, mode:thread, model: opus (--tier names no path mandate: PM's call, default), effort: medium
Clause-②: no expected — a path-bearing action now reaches its own path; the dev measures and declares
Metadata-protocol: none (expected; the dev measures and declares)
Responsibility: the dev builds the request URL with the URL API (path joined, base query kept, action query wins on a clash) keeping PR #28688's origin pins, with red-first, controls and ablation; the seat reviews and lands
Thread-read: none
Premise: confirmed from code by PR #28688's review; NOT MEASURED at a public door; the dev measures first
Serial constraints cleared: PR #28688 merged; the dev re-reads open PRs on connector-rest before pr_create
Resume-from: none — fresh from origin/main
State: → pm:dispatched, assigned to os-project-manager, recorded by this claim.
os-dev-report
{
"issue": 28736,
"status": "done",
"branch": "claude/project-thread-efkbrl",
"pr": "#28767",
"session": "session_01FEkQ5oht6tMAsnKGYsgbiT",
"premise_still_valid": true,
"summary": "buildUrl in connector-rest now parses the base, lifts its query off, joins the action path onto the base path exactly as the text join did, then puts the base parameters back first and the action's own after them (inline path query, then query incl. an api-key paramName); on a clash the action's value wins (code comment + changeset). A base without a query sends byte-identical URLs (480-case sweep); a path cannot leave the base origin (pinned for both base shapes). The dogfood carry-forward pin gains a path-bearing dispatch (/probe). Premise measured: on base a query base sends /v1?region=eu/items, and through the materialized instance in the dogfood pin the upstream received /v1?api_key=...®ion=eu/probe. Deviation: the harness commit trailer named a model; check:commit-card-trailers refused the push, the unpublished commit was reworded to the model-free pair before the first push.",
"tests": "Head a9a80de. Unit rest-connector.test.ts: 24 passed (24); red on base 7a48bf7 (rest-connector.ts restored, tree restored, git diff HEAD empty): 10 failed | 14 passed, the ten query-base cases. Package suite: 5 files, 57 tests passed. Dogfood connector-meta-door-entry-and-url-hardening: 9 passed (9); red with base source rebuilt into dist (marker absent): 1 failed | 8 passed, Expected /v1/probe?api_key=TEST_PLACEHOLDER_CARRIED_QUERY®ion=eu, Received /v1?api_key=TEST_PLACEHOLDER_CARRIED_QUERY®ion=eu/probe; restored + rebuilt (marker present). Ablation 1 via ablation-replace.mjs (base query not lifted): 10 failed | 14 passed, query-base cases only; restored blob 9180629b == HEAD. Ablation 2 (inline-path clash rule off): 1 failed | 23 passed, the inline clash case only; restored blob == HEAD. Unit suite imports src, so no dist leg for the unit ablations. Control sweep against built dist: 480 query-free cases identical to the base text join; positive control 45 of 48 query-base cases differ. Typecheck: build + typecheck exit 0 (check-dts-emitted 2/2, check:test-typecheck OK).",
"gates": "dispatch-gates --commands at a9a80de: 61 derived; --ran reconciliation exit 0: 60 run exit 0, 1 NOT MEASURED (check:dual-build-cjs-loads exit 3, prerequisite: every package dist). check-plugin-teardown-shape --self-test first exit 3 (pinned fixture outside the shallow clone), exit 0 after git fetch --depth=1 of 621a487. check-nul-bytes OK. Record: /mnt/project-files/pm-orders/server/28736-gates-ran.txt. CI check-runs on #28767: in_progress at report time (not waited on, per os-dev).",
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"mcp_calls": "6 — issue_read x3 (card, comments x2), pull_request_read get_files (#28688), list_pull_requests (open PRs, overlap), none of them writes",
"api_writes": "2 — fleet-write relay pr_create (POST /repos/objectstack-ai/objectstack/pulls via run 41336300978), this os-dev-report comment (POST /repos//issues/28736/comments)",
"open_questions": [],
"out_of_scope_findings": [
"class: none filed · a base URL fragment still swallows the path (https://h/v1#frag + /items sends /v1 on the wire), kept as measured per the order; noted in Acceptance notes · carrier: seat 2 · noted, not filed",
"class: none filed · no origin/scheme/host check exists in the rest request path today; PR #28688's hardening is read-side redaction and the save-door key refusal, untouched · carrier: none · noted, not filed"
]
}
Activity
objectstack-fleet commentedon Nov 1, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: 可对外的 API | none | P②
Triage: p2 ·
bug·domain:server·area:automation·pm:queue· 2026-11-01T16:58Z⛔ Not a claim.
baseUrlcarrying a query string (?api-version=…, a common vendor pattern) puts every action's path inside the query. p2. The fix builds the URL with the URL API (path joined, base query kept), with tests for both shapes.Generated by Claude Code
objectstack-fleet commentedon Nov 1, 2026
domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo
Claim: PM loop round 4 · card thread · 2026-11-01T17:35Z
Session:
session_0186vfjHHMsRXC9EUT9hTFMo(the seat); the card thread issession_01FEkQ5oht6tMAsnKGYsgbiTAccount:
os-project-manager(the seat's linked user; the card's assignee)Branch:
claude/project-thread-efkbrl(the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)Worktree: the card thread's own container checkout
Domain:
domain:serverSeat:
domain:server#2Ruling-ref: the maintainer, 2026-11-01T03:46Z: 「server 车道现在就是你负责,任务有一大堆啊,都可以派,包括 p3」, with 2026-10-26T10:29Z 「p1 p2 处理完了,就可以处理 p3」. With 2026-11-01T12:11Z 「定级你可以自己决定」; graded p2 by triage (2026-11-01T16:58Z).
File surface:
packages/connectors/connector-rest/src/rest-connector.ts(buildUrl), its unit tests, the connector URL-hardening dogfood pin; changesetContainer & model:
M,mode:thread,model: opus(--tiernames no path mandate: PM's call, default),effort: mediumClause-②: no expected — a path-bearing action now reaches its own path; the dev measures and declares
Metadata-protocol: none (expected; the dev measures and declares)
Responsibility: the dev builds the request URL with the URL API (path joined, base query kept, action query wins on a clash) keeping PR #28688's origin pins, with red-first, controls and ablation; the seat reviews and lands
Thread-read: none
Premise: confirmed from code by PR #28688's review; NOT MEASURED at a public door; the dev measures first
Serial constraints cleared: PR #28688 merged; the dev re-reads open PRs on
connector-restbeforepr_createResume-from: none — fresh from
origin/mainState: →
pm:dispatched, assigned toos-project-manager, recorded by this claim.Generated by Claude Code
objectstack-fleet commentedon Nov 1, 2026
domain:server#2 · os-project-manager · session_01FEkQ5oht6tMAsnKGYsgbiT
os-dev-report
{
"issue": 28736,
"status": "done",
"branch": "claude/project-thread-efkbrl",
"pr": "#28767",
"session": "session_01FEkQ5oht6tMAsnKGYsgbiT",
"premise_still_valid": true,
"summary": "buildUrl in connector-rest now parses the base, lifts its query off, joins the action path onto the base path exactly as the text join did, then puts the base parameters back first and the action's own after them (inline path query, then query incl. an api-key paramName); on a clash the action's value wins (code comment + changeset). A base without a query sends byte-identical URLs (480-case sweep); a path cannot leave the base origin (pinned for both base shapes). The dogfood carry-forward pin gains a path-bearing dispatch (/probe). Premise measured: on base a query base sends /v1?region=eu/items, and through the materialized instance in the dogfood pin the upstream received /v1?api_key=...®ion=eu/probe. Deviation: the harness commit trailer named a model; check:commit-card-trailers refused the push, the unpublished commit was reworded to the model-free pair before the first push.",
"tests": "Head a9a80de. Unit rest-connector.test.ts: 24 passed (24); red on base 7a48bf7 (rest-connector.ts restored, tree restored, git diff HEAD empty): 10 failed | 14 passed, the ten query-base cases. Package suite: 5 files, 57 tests passed. Dogfood connector-meta-door-entry-and-url-hardening: 9 passed (9); red with base source rebuilt into dist (marker absent): 1 failed | 8 passed, Expected /v1/probe?api_key=TEST_PLACEHOLDER_CARRIED_QUERY®ion=eu, Received /v1?api_key=TEST_PLACEHOLDER_CARRIED_QUERY®ion=eu/probe; restored + rebuilt (marker present). Ablation 1 via ablation-replace.mjs (base query not lifted): 10 failed | 14 passed, query-base cases only; restored blob 9180629b == HEAD. Ablation 2 (inline-path clash rule off): 1 failed | 23 passed, the inline clash case only; restored blob == HEAD. Unit suite imports src, so no dist leg for the unit ablations. Control sweep against built dist: 480 query-free cases identical to the base text join; positive control 45 of 48 query-base cases differ. Typecheck: build + typecheck exit 0 (check-dts-emitted 2/2, check:test-typecheck OK).",
"gates": "dispatch-gates --commands at a9a80de: 61 derived; --ran reconciliation exit 0: 60 run exit 0, 1 NOT MEASURED (check:dual-build-cjs-loads exit 3, prerequisite: every package dist). check-plugin-teardown-shape --self-test first exit 3 (pinned fixture outside the shallow clone), exit 0 after git fetch --depth=1 of 621a487. check-nul-bytes OK. Record: /mnt/project-files/pm-orders/server/28736-gates-ran.txt. CI check-runs on #28767: in_progress at report time (not waited on, per os-dev).",
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"mcp_calls": "6 — issue_read x3 (card, comments x2), pull_request_read get_files (#28688), list_pull_requests (open PRs, overlap), none of them writes",
"api_writes": "2 — fleet-write relay pr_create (POST /repos/objectstack-ai/objectstack/pulls via run 41336300978), this os-dev-report comment (POST /repos//issues/28736/comments)",
"open_questions": [],
"out_of_scope_findings": [
"class: none filed · a base URL fragment still swallows the path (https://h/v1#frag + /items sends /v1 on the wire), kept as measured per the order; noted in Acceptance notes · carrier: seat 2 · noted, not filed",
"class: none filed · no origin/scheme/host check exists in the rest request path today; PR #28688's hardening is read-side redaction and the save-door key refusal, untouched · carrier: none · noted, not filed"
]
}
Generated by Claude Code
objectstack-fleet commentedon Nov 1, 2026
domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo
Landing record · #28736 · PR #28767
domain:serverseat 2 ·session_0186vfjHHMsRXC9EUT9hTFMo· 2026-11-01T18:55Zcd0ec76bgit merge-base --is-ancestor cd0ec76b origin/maingit ls-remote origin refs/heads/gh-readonly-queue/*matching 28767git grep -c baseParams origin/main -- packages/connectors/connector-rest/src/rest-connector.tsbaseUrlcarries a query string sends each action to its own path. The base's parameters are kept, and the action's own parameters win on a clash.Release: claim
6561462816(session_01FEkQ5oht6tMAsnKGYsgbiT, branchclaude/project-thread-efkbrl) · landed.pm:dispatchedremoved; assignee cleared; the card closed on merge.Generated by Claude Code