Clarify cross-deployment account-hint environments - #373
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
🤝 Merged Conflicted files:
Please review the merge commit before relying on it. |
…environment-labels (AI-resolved conflicts) Conflicted paths: remix/CHANGELOG.md Resolved by the resolve-pr-conflicts workflow: https://github.com/lopugit/thingtime/actions/runs/32713758114 Co-Authored-By: Claude <noreply@anthropic.com>
Lopu repository reviewLopu reviewed this PR against codex/thingtime-mcp-desktop-connectors as Thingtime's principal PR and repository manager. Using Claude Opus 5. Lopu made justified improvements and pushed ef15578 to codex/account-hint-environment-labels. Lopu review — PR #373 · Clarify cross-deployment account-hint environmentsCompared: The failing check — diagnosed, and it is not this PR
I reproduced it locally in the PR worktree, then re-ran the identical test with
Byte-identical failure, identical count. This PR adds zero I then bisected it to the exact commit, by running the same guard test against
So the regression entered through the base branch's own For the record, I dumped the actual plan by driving I deliberately did not "fix" this here. Choosing which of #68's indexes to Findings on the PR's own contentThe substance is a careful, security-positive change: a public
Non-blocking observations
Change made
col('deploymentPeers').createIndex({ federationId: 1, lastSeenAt: -1, origin: 1 }),That changes the key shape of the index it replaces createIndexReplacing(
col('deploymentPeers'),
{ federationId: 1, lastSeenAt: -1, origin: 1 },
{ name: 'deployment_peers_federation_recent' },
['lastSeenAt_-1_origin_1']
),Naming the index also makes it referenceable from a future retirement list Validation run
CodeQL16 open alerts on this head — every one of them pre-existing on 5 left open on purpose — I will not dismiss a real finding to green a
|
|
🤝 Merged Conflicted files:
Please review the merge commit before relying on it. |
…environment-labels (AI-resolved conflicts) Conflicted paths: remix/CHANGELOG.md, remix/app/api/utils/peers/peerDiscovery.ts, remix/package.json Resolved by the resolve-pr-conflicts workflow: https://github.com/lopugit/thingtime/actions/runs/32735798678 Co-Authored-By: Claude <noreply@anthropic.com>
✅ Develop S3 preview ready
The alias passed the develop bucket CORS preflight and a final live PR/SHA fence. Generic Vercel Preview deployments use the shared development runtime; this controller adds the stable exact-SHA alias and marker-scoped cleanup. |
|
🤖 Lopu — the failing check is diagnosed and repaired; and your "Known baseline" note is now stale
|
|
🤝 Merged Conflicted files:
Please review the merge commit before relying on it. |
…environment-labels (AI-resolved conflicts) Conflicted paths: remix/CHANGELOG.md, remix/app/docs/apiDocs.ts, remix/package.json Resolved by the resolve-pr-conflicts workflow: https://github.com/lopugit/thingtime/actions/runs/32986626169 Co-Authored-By: Lopu <github-actions[bot]@users.noreply.github.com>
Structural `graphify update` followed by LLM semantic `graphify extract` (graphify 0.9.4, claude-cli backend); unchanged content served from the tracked semantic cache. Refreshed by the resolve-pr-conflicts workflow: https://github.com/lopugit/thingtime/actions/runs/32986626169
|
These examples are warning-only. They do not fail the build/API contexts or block this PR.
Sanitized tailnode:internal/modules/run_main:123
triggerUncaughtException(
^
AssertionError [ERR_ASSERTION]: all-branch.yml must stay retired; Lopu PR manager owns its former public triggers
true !== false
at file:///home/runner/work/thingtime/thingtime/remix/scripts/workflow-caller-contract.mjs:39:10
at ModuleJob.run (node:internal/modules/esm/module_job:343:25)
at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:681:26)
at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:117:5) {
generatedMessage: false,
code: 'ERR_ASSERTION',
actual: true,
expected: false,
operator: 'strictEqual',
diff: 'simple'
}
Node.js v22.23.2
|
|
🤖 Lopu — correcting my 09:13 note: this job is red again, and I found a real (small) defect in the Two updates on this head ( 1.
|
| Commit | Result |
|---|---|
b615534 — this branch at 09:16 |
passes |
f42abb9 — the base, after 126dc2d merged develop in at 12:31 |
62/64 — fail |
9ca92cb — this head, after that base landed here at 20:47 |
62/64 — fail |
I also ran the identical test with your collections.ts swapped for the base's: byte-identical failure, identical count. This PR adds zero things indexes — your only collections.ts change is on deploymentPeers, and un-retiring things_passkey_link_key_unique can only relax the second assertion, never the count.
I have posted the full breakdown on #68 (60 distinct things indexes + _id_ + the home-only TTL = 62; develop produces 49) since that is where the fix belongs. Nothing to do here — this clears when #68 clears. I did not attempt a fix on this branch: choosing which indexes to consolidate is #68's design decision, and landing it on a stacked child would conflict the moment #68 moves.
2. One real defect, fixed in this worktree
The new peers index is created with a bare createIndex:
col('deploymentPeers').createIndex({ federationId: 1, lastSeenAt: -1, origin: 1 }),That changes the key shape of the index it replaces ({ lastSeenAt: -1, origin: 1 }), and MongoDB does not drop the old one — a plain createIndex with a new shape just builds a second index under a second auto-generated name. Fresh databases are fine; every already-deployed one keeps the superseded index forever, and nothing in the repo remembers it exists to retire it later.
This file already has the convention for exactly this — createIndexReplacing(collection, keys, { name }, legacyNames), used a dozen times above, with dropIndexRetrying treating an absent index as a no-op. Switched to it:
createIndexReplacing(
col('deploymentPeers'),
{ federationId: 1, lastSeenAt: -1, origin: 1 },
{ name: 'deployment_peers_federation_recent' },
['lastSeenAt_-1_origin_1']
),Naming it also makes it referenceable from a future retirement list instead of depending on an auto-generated name a second time. (I normalized the indentation back to the file's spaces while I was there — the new line had arrived with a stray tab.)
Given the 62/64 situation above, an orphaned index is worth more than usual right now — though note this one is on deploymentPeers, not things, so it does not move the failing count.
On the change itself — still no objections
I re-verified the federation work I praised this morning and it holds up. One thing I did not flag then and should have: announcePeer's filter admits { federationId: { $exists: false } }, so during the upgrade window the first v2 deployment to announce a given origin adopts that legacy row into its federation. Bounded by the pinned origin and the signingPublicKey match, so I do not think it is exploitable — but it is the one place the federation fence is deliberately open, and it deserves a comment saying it is a one-time migration allowance rather than a standing rule.
Also worth a remix/CHANGELOG.md line: PEER_DISCOVERY_PROTOCOL_VERSION 1 → 2 is a hard cutover, so v1 and v2 peers will 401 each other during a rolling deploy. Leases are 10 minutes so the mesh self-heals, but an operator seeing mutual 401s should be able to look that up rather than debug it.
— Lopu 🤖
Summary
*.vercel.applogins through the configured first-party development authorityTHINGTIME_DATA_ENV=production|development|custom:<id>, with a safe authority/federation identity in root data and/api/v1/capabilities(api.capabilities1.1.0)Validation
test:account-hints— 9/9test:root-data— 4/4test:peers— 6/6test:api-capabilities— 4/4build:client,build:server, and rootbuild:vercel— passapi.capabilities=1.1.0,dataEnvironment=development,federationId=development, withauthorityOrigin=https://dev.thingtime.com; account-hints headers verified asCache-Control: private, no-storeandVary: CookieKnown baseline
test:collectionscurrently fails an existing contradictory assertion: the current source intentionally createsthings_passkey_link_key_uniquewhile the historical retired-index list still asserts it must be absent. This change only replaces the deployment-peer sort index with a federation-prefixed equivalent and does not touch that Things index.