Repository navigation
Delivery board reads the package repository: an instance shows another repository numbers and says nothing #1250
Description
Owner: Dev4
(Proposed by Chief on 2026-10-26 from the owner's correction: "固定写在包里肯定不行". Triage: confirm or move.)
Goal (one observable behavior)
The delivery board reads the repository this instance actually works in, and says which one it read and where that name came from. Today it cannot: core/src/host/delivery-board.js:745-748
const repo = (() => { try { return rt.repoSlug?.() ?? repoSlug() } catch { return repoSlug() } })()repoSlug() (core/src/host/update.js:163) parses the shipped package's repository.url, and nothing in the tree provides rt.repoSlug (grep: no rt.repoSlug = anywhere). So every instance shows ThinkFlowLab/FlyBot no matter what it is connected to — an instance set up on someone's own fork shows our numbers, and a fresh instance with no token shows our numbers too.
Resolution order (this is the whole design)
First one that answers wins, and the view must carry which one answered:
- Instance setting —
delivery.repo: "owner/name"in the instance config (the same place other instance settings live). Explicit beats inferred. - The workspace's git remote —
originof the folder the work happens in (git remote get-url origin, acceptinghttps://github.com/o/r(.git)andgit@github.com:o/r.git). This is what "the repo this instance works in" means in practice. - Package
repository.url— last resort only, and only so an untouched instance still shows something. It must be labelled as a default, not presented as fact.
If none answers: the view fails with no repository — set delivery.repo. It must not request /repos/null.
Acceptance criteria
- With
delivery.repo = "acme/widget", board and probe both readacme/widget, and the header showsacme/widgetwith sourceconfig. - With no setting and a workspace whose
originishttps://github.com/acme/widget.git, both readacme/widget, sourceremote. A table-driven test covers thegit@github.com:acme/widget.gitand scp-lesshttps://github.com/acme/widgetforms. - With neither, the resolved name is the package one and the header says source
package(a warn line records that it is a default). No silent fallback in the logs. - With neither and a package whose
repositoryis absent, the view fails with the message above and the probe exits non-zero — assert that no request was made at all. - Changing the setting re-resolves: the cache is keyed by repo, so the previous repo's snapshot is never served for the new name (assert the second read is
loading, not the oldreadywith old columns). - A repo the saved
GITHUB_TOKENcannot read fails with a message naming the repo and the endpoint (the#1211/#1232failure shape already carriesendpoint/status— reuse it, do not invent a second shape). npm run verifygreen.
The knife: delete the config branch → (1) goes red; delete the remote branch → (2) goes red. Keep both in the same test file so one cannot rot silently.
Where it sits (file:line pointers)
core/src/host/delivery-board.js:745-748—install()'s repo resolution (the bug).core/src/host/update.js:163—repoSlug(); keep it for what it is good at (where this package's releases live), do not repurpose it.core/scripts/delivery-probe.mjs:18— same order, so the CLI and the button agree;--repostays as the explicit override.core/src/client/delivery-view.js:276—DeliveryHeader, which already receivesrepo; add the source label here.docs/subsystems/core-host.md— the arch-docs owner page forcore/src/host/; add the setting and the order.
Out of scope / do not touch
- Release checks (
core/src/host/update.js,dsh-update.js) keep using the package URL: "where releases of the installed package live" is genuinely a package fact, not an instance choice. Do not unify the two. - No settings UI beyond showing the resolved name and source; editing
delivery.repostays a config/secret action in this issue. - No change to which endpoints the board reads, to the cache TTL, or to the columns.
- Do not add a second way to name the repo (no env var and config and CLI all matching different things: config, then remote, then package, and CLI
--repooverrides).
Why it bites
An instance this team does not own was showing this repository's numbers, and nothing on the page said whose repository it was. The owner's words: 固定写在包里肯定不行. A default is acceptable only while it is visible as a default.
Activity
Birfy commentedon Oct 26, 2026
Triage — every pointer resolves at
7be5658a;Owner: Dev4confirmed. Five forks decided so this can be implemented without a round tripChecked:
delivery-board.js:744-748(install()+ thert.repoSlug?.() ?? repoSlug()IIFE),update.js:162-163(repoSlug()offPKG.repository),delivery-probe.mjs:18,delivery-view.js:276(DeliveryHeader({ view, snapshot, repo = null, … })). No duplicate: nothing open covers this;#1211was the failure-shape issue and is closed.rt.config. Do not invent a settings store.parts.js:140destructures{ ctx, config, state }fromrtand readsconfig.checkRatioat:213, and this host's own profile sets it today:/data/dsh/profiles/web/cordis.patch.ymlhas- id: bot, name: ds-bot, config: { checkRatio: 0.45 }. Sodelivery.repois one more key on that same plugin entry (config.deliveryRepo), read viart.config— no new tool, no new UI, no new file. The wrong alternative is a secret:rt.secretValue(secrets.js:607) holds scoped key values and the list renders them as keys, which a repo name is not.repocannot stay a constant. It is baked intobaseonce (delivery-board.js:258) and reused by every endpoint, every error message andprobe()(:741). Soinstall()must resolve{ repo, source }perrt.deliveryBoard()call and keepMap<repo, board>— a different resolved repo gets that repo's own board instance. That makes criterion 5 structural ("the new repo's first read isloading", not a cache flush bug). Do not push a function intocreateDeliveryBoard({ repo });baseis built once from it..git/config, it does not spawngit. There is no subprocess anywhere incore/src/host(grepexecFile: 0 hits) and the host may run wheregitis not onPATH. Parse the[remote "origin"]url =value out of<folder>/.git/config(followgitdir:when.gitis a file), synchronously and testably. The folder is the instance's team workspace —teamFolder()(folders.js:25,ctx.workspaceRegistry.get(state.workspaceId)?.path), not a Bot'sworkDir(workDirOf,folders.js:24): the board is host-level, one host shows one repo, and using a Bot's folder would make the answer depend on which Bot happened to be named. Do not union disagreeing remotes; the header's source label is what makes the choice honest.delivery-probe.mjsis a standalone script with nortand nostate. Restate its order as--repo→--workspace <dir>(new flag, default cwd) → package, and put the resolver in one module both call sites import (e.g.core/src/host/delivery-repo.js,resolveRepo({ setting, workspace, packageSlug })), so the board and the CLI cannot drift — and the knife (delete config branch / delete remote branch) can be one table-driven test against the resolver, not two copies./repos/nullguard must sit before the board is built.baseis interpolated atdelivery-board.js:258andprobeGitHub:211, so a null repo becomes/repos/nullunless resolution refuses first. Criterion 4's "assert no request" has to count everyfetchon the whole path, including the firstrt.deliveryBoard()read, and must see zero.Criterion 6 is nearly free:
hintFor(error, { repo })already receives the repo (delivery-view.js:299) and the#1211/#1232error shape already carriesendpoint/status. What is missing is only that the 404 for an unreadable repo names the repo rather than the endpoint alone.Labels:
enhancement,area:ui,agent-ready(the visible surface is the header's repo + source line). Out-of-scope section is right:update.js/dsh-update.jskeep the package URL — that is a package fact, not an instance choice.Birfy commentedon Oct 26, 2026
Written-by: Dev4
Claimed #1250 — branch
dev/feat/1250-delivery-repo— first step: the resolver both the host and the probe import (core/src/host/delivery-repo.js):delivery.repo→ the team workspace gitorigin→ the package as a labelled default.feat(delivery): resolve which repository this instance reads (ThinkFl…
feat(delivery): read more than one repository on the delivery board (T…