Skip to content

feat: hide configured repositories from interactive UI - #862

Open
wesm wants to merge 14 commits into
mainfrom
feat/repository-ui-visibility
Open

feat: hide configured repositories from interactive UI#862
wesm wants to merge 14 commits into
mainfrom
feat/repository-ui-visibility

Conversation

@wesm

@wesm wesm commented Aug 8, 2026

Copy link
Copy Markdown
Member

Archive-only repositories need to remain configured for history, reports, and direct maintenance, but that should not force them into active-work selectors.

  • Add an explicit per-repository UI visibility action in the repository gear menu without changing sync or archive behavior.
  • Apply the setting consistently to desktop, mobile, and workspace repository pickers, including exact/glob overlap and provider-host identity.
  • Preserve hidden repositories in Settings and provider-aware direct routes so visibility can be restored at any time.

@roborev-ci

roborev-ci Bot commented Aug 8, 2026

Copy link
Copy Markdown

roborev: Combined Review (84b723f)

Changes need fixes: three medium-severity issues remain.

Medium

  • internal/server/helpers.go:129 — Renamed repositories retain only one configured-path provenance. If a visible current-path entry precedes a hidden old-path entry, deduplication discards the hidden provenance, making “hidden wins” depend on configuration order. Retain all configured paths per stable repository identity and test both orderings.

  • packages/ui/src/views/mobileActivityRepoOptions.ts:26 — An existing hidden repository selection is not cleared when mobile options exclude it. The global normalizer preserves unknown provider-qualified values, leaving activity filtered to a repository absent from the selector. Strictly validate the mobile selection against interactive options and clear unavailable selections.

  • internal/server/e2etest/settings_test.go:767 — Coverage verifies persistence only; no full-stack browser test confirms that the Settings toggle updates repository selectors and workspace creation. Add Playwright coverage using the real API and seeded database to hide and restore a repository and clear an active selection.


Reviewers: 2 done | Synthesis: codex, 6s | Total: 5m57s

@wesm

wesm commented Aug 8, 2026

Copy link
Copy Markdown
Member Author

settings-globs-pr.png

@wesm

wesm commented Aug 8, 2026

Copy link
Copy Markdown
Member Author

Repository visibility action in the repository gear menu:

repository-visibility-gear-menu.png

@roborev-ci

roborev-ci Bot commented Aug 8, 2026

Copy link
Copy Markdown

roborev: Combined Review (67f58aa)

Changes need one medium-severity fix before approval.

Medium

  • packages/ui/src/views/mobileActivityRepoOptions.ts:26 — Hidden repositories are excluded from the mobile selector, but App.svelte::getNormalizedGlobalRepo still validates persisted selections against all configured repositories. A hidden repository can therefore remain selected on mobile, continue filtering activity, pull requests, and issues, and appear as a dropdown value without a matching option.

    Suggested fix: Normalize mobile selections against the visible repository set, or clear selectedRepo when it is absent from repoOptions. Add coverage for loading mobile views with a hidden repository persisted as the global selection.


Reviewers: 2 done | Synthesis: codex, 10s | Total: 5m58s

@roborev-ci

roborev-ci Bot commented Aug 8, 2026

Copy link
Copy Markdown

roborev: Combined Review (6c90556)

Overall verdict: One medium-severity correctness issue requires attention; no material security vulnerabilities were found.

Medium

  • frontend/src/App.svelte:632 — Valid repository selections can be incorrectly cleared. Global selection validation treats visible exact configuration rows as the complete interactive catalog. Repositories discovered through visible globs, or repositories whose provider route changed after configuration, exist only in /repos; valid selections are therefore removed and cleared from local storage after settings load.
    • Fix: Validate against the merged /repos catalog plus visible exact entries, and wait until that catalog has loaded before pruning. Add coverage for persisted and newly selected glob-backed or renamed repositories.

Reviewers: 2 done | Synthesis: codex, 12s | Total: 10m16s

@roborev-ci

roborev-ci Bot commented Aug 8, 2026

Copy link
Copy Markdown

roborev: Combined Review (422d7a8)

The PR has two medium-severity issues involving renamed repository visibility and missing full-stack coverage.

Medium

  • Stale configured paths can override hidden-entry visibility
    Location: packages/ui/src/utils/repo-visibility.ts:50, frontend/src/App.svelte:663, frontend/src/lib/components/RepoTypeahead.svelte:149
    Effective visibility is inferred only from configured owner/name values. If an exact repository is renamed by its provider into a path matched by a hidden glob, the server removes the current identity from /repos, but the frontend re-adds the stale configured path as a valid selection. This violates the hidden-entry-wins rule.
    Fix: Base effective visibility on resolved catalog identities and configuration provenance, or treat the filtered catalog as authoritative while adding only demonstrably unresolved exact entries. Add coverage for a renamed exact repository overlapping a hidden glob.

  • Visibility settings lack full-stack browser coverage
    Location: frontend/src/lib/components/settings/RepoSettings.svelte:269
    Existing server e2e coverage verifies only PUT persistence, while mocked and component tests do not establish that the gear action updates the real catalog, clears selectors, and survives reload.
    Fix: Add a Playwright full-stack test that hides and shows an exact repository and a glob through the gear menu, verifies /repos plus selector/workspace visibility, and confirms persistence after reload.


Reviewers: 2 done | Synthesis: codex, 13s | Total: 10m4s

@roborev-ci

roborev-ci Bot commented Aug 8, 2026

Copy link
Copy Markdown

roborev: Combined Review (554d1ec)

The repository visibility controls have two medium-severity consistency issues involving renamed repositories and overlapping hidden globs.

Medium

  • Incorrect unresolved-repository detectionpackages/ui/src/utils/repo-visibility.ts:74, internal/server/settings_handlers.go:137

    matched_repo_count === 0 is treated as proof that an exact configuration row is unresolved, but matchedRepoCount ignores ConfiguredRepoPath. After a provider rename, this can restore a stale configured route and potentially resurrect a repository hidden by a glob.

    Fix: Make exact-match counting provenance-aware (for example, using repoMatchesConfig) or expose explicit configuration-to-catalog resolution state. Add coverage through the real settings and catalog APIs for a provider rename combined with an overlapping hidden glob.

  • Mobile options use stale configuration identitiespackages/ui/src/views/mobileActivityRepoOptions.ts:25

    Mobile repository options are derived from configuration identities rather than the authoritative filtered /repos catalog. Following a rename, a hidden glob can remove the current route from /repos while mobile still shows the stale configured route.

    Fix: Build mobile options from the filtered /repos catalog, applying any intentional unresolved-exact fallback consistently with the desktop selector. Add phone-profile coverage for renamed repositories hidden by overlapping configuration.


Reviewers: 2 done | Synthesis: codex, 12s | Total: 9m5s

@wesm
wesm force-pushed the feat/repository-ui-visibility branch from 554d1ec to efafb71 Compare August 8, 2026 17:07
@roborev-ci

roborev-ci Bot commented Aug 8, 2026

Copy link
Copy Markdown

roborev: Combined Review (efafb71)

Repository visibility has two medium-severity correctness issues involving renamed repositories and stale configured paths.

Medium

  • Renamed repositories can have stale paths incorrectly restoredpackages/ui/src/utils/repo-visibility.ts:74
    matched_repo_count === 0 is treated as proof that an exact row is unresolved, but matchedRepoCount in internal/server/settings_handlers.go:137 ignores ConfiguredRepoPath provenance. A provider-renamed repository can therefore report zero matches, restoring its stale configured path and potentially displaying a repository hidden under its current route. Make exact-repository counts use provenance-aware repoMatchesConfig (or expose an explicit resolution field), and test against a real post-rename settings response.

  • Mobile activity can show renamed repositories hidden by a globpackages/ui/src/views/mobileActivityRepoOptions.ts:26
    Mobile activity reconstructs visibility from configuration rows instead of the authoritative repository catalog. Since the client-side matcher lacks rename provenance, a renamed repository hidden by a glob matching its current route can reappear under its stale configured path. Build mobile options from the filtered /repos catalog, add only genuinely unresolved exact configuration rows, and cover a renamed repository hidden by an overlapping glob.


Reviewers: 2 done | Synthesis: codex, 20s | Total: 6m54s

@roborev-ci

roborev-ci Bot commented Aug 8, 2026

Copy link
Copy Markdown

roborev: Combined Review (539ef9c)

Code review found two medium-severity correctness issues; no security vulnerabilities were identified.

Medium

  • frontend/src/App.svelte:659 — Catalog normalization clears a repository pinned through ui.repo when hideRepoSelector is enabled and the repository is hidden from the interactive catalog. The fixed-scope view then incorrectly falls back to “All repos.” Preserve the host-pinned repository in this mode by bypassing interactive-catalog normalization.

  • frontend/src/lib/components/settings/RepoSettings.svelte:168 — Concurrent visibility changes replace the entire repository settings array with the last response received, allowing an older response to overwrite a newer row’s confirmed state. Serialize these mutations or reconcile responses by mutation generation, applying only the field and row owned by each request.


Reviewers: 2 done | Synthesis: codex, 11s | Total: 5m52s

@roborev-ci

roborev-ci Bot commented Aug 8, 2026

Copy link
Copy Markdown

roborev: Combined Review (f431631)

The PR needs changes to prevent repository selections from disappearing or being cleared unexpectedly.

Medium

  • packages/ui/src/utils/repo-visibility.ts:74matched_repo_count > 0 does not guarantee the authoritative /repos catalog contains the repository. Direct exact-repository additions and fresh-startup resolution can populate the syncer before a database row is persisted, causing the configured fallback to be suppressed and the repository to disappear from selectors and workspace creation until reload.

    • Fix: Persist resolved repository identities before publishing settings/tracked state, treat identityless fallback refs as unmatched, and add a full-stack regression test for selection immediately after an exact repository is added.
  • frontend/src/lib/components/RepoTypeahead.svelte:95 — A structured /repos error ends loading without recording that catalog loading failed. The validation effect then treats an empty catalog as authoritative and calls onchange(undefined), permanently clearing the persisted repository filter after a transient API failure.

    • Fix: Track successful catalog loading separately, prune selections only after a successful response, and preserve the prior catalog and selection when loading fails.

Reviewers: 2 done | Synthesis: codex, 14s | Total: 8m1s

@roborev-ci

roborev-ci Bot commented Aug 8, 2026

Copy link
Copy Markdown

roborev: Combined Review (3def5af)

Changes need revision: two medium-severity consistency issues can leave repository settings persisted or displayed incorrectly.

Medium

  • internal/server/settings_handlers.go:812 — The config file is saved before persistResolvedRepos runs. If database persistence fails, only the in-memory append is rolled back, so the API returns an error while the repository remains on disk and reappears after reload. Persist the resolved identity before saving the modified config, or durably restore the prior config on failure. Add a failure-path test covering both memory and the saved file.

  • frontend/src/lib/components/settings/RepoSettings.svelte:159 — Only visibility requests use the mutation queue, while worktree edits, refreshes, removals, and additions can concurrently apply complete settings.repos snapshots. Out-of-order responses may overwrite newer state, resurrect removed rows, or show stale visibility/path values. Use one shared queue or generation-aware reconciliation for all repository-setting mutations, or disable competing mutations while a request is pending.


Reviewers: 2 done | Synthesis: codex, 10s | Total: 11m56s

@roborev-ci

roborev-ci Bot commented Aug 9, 2026

Copy link
Copy Markdown

roborev: Combined Review (2428c26)

No issues found.


Reviewers: 2 done | Synthesis: codex | Total: 16m56s

@roborev-ci

roborev-ci Bot commented Aug 9, 2026

Copy link
Copy Markdown

roborev: Combined Review (795dd57)

One medium-severity issue could cause hidden-state leakage across repository identities.

Medium

  • Stable repository identity violationinternal/server/helpers.go:129

    A hidden exact entry can match both its renamed repository through ConfiguredRepoPath and an unrelated repository that later reuses the old route. If a visible glob tracks both, the route successor is incorrectly removed from selectors.

    Fix: When an exact entry has a provenance match, apply its visibility only to that repository. Fall back to route matching only when no provenance-bound repository exists, and add route-reuse coverage.


Reviewers: 2 done | Synthesis: codex, 10s | Total: 15m51s

@roborev-ci

roborev-ci Bot commented Aug 9, 2026

Copy link
Copy Markdown

roborev: Combined Review (1dc53b4)

Repository visibility controls have two medium-severity persistence and identity issues that can surface after renames or restarts.

Medium

  • internal/server/settings_handlers.go:812 — Pre-response persistence uses DB.UpsertRepo, which does not update the route of an existing provider ID. Re-adding a previously cataloged repository after a rename reports a match, but /repos retains the old route, causing selectors and workspace creation to omit it until a later sync.

    • Fix: Persist provider-resolved results through timestamp-fenced ReconcileRepositoryObservation, and test adding a known provider ID under its renamed route.
  • internal/server/helpers.go:125 — Stable visibility binding relies on ConfiguredRepoPath, which exists only in the in-memory tracked reference. After a reload or restart, the exact path is rebound to its current occupant; following a rename and route reuse, the successor may become hidden while the originally hidden repository reappears through an overlapping glob.

    • Fix: Persist the exact config entry’s stable provider-ID association and restore it during resolution. Add coverage for rename plus route reuse across reload and restart.

Reviewers: 2 done | Synthesis: codex, 14s | Total: 11m55s

@roborev-ci

roborev-ci Bot commented Aug 9, 2026

Copy link
Copy Markdown

roborev: Combined Review (f6ae3ea)

High-severity stable-binding flaw remains, with two medium-severity consistency issues.

High

  • internal/github/configured_repo_bindings.go:64 — When a bound route resolves to a different provider ID, the fallback remains syncable at that conflicting route. A later sync can replace it with the route successor while preserving ConfiguredRepoPath, transferring visibility and other exact-entry settings to the wrong repository.
    • Fix: Fail closed on identity mismatch. Resolve the repository by stable ID/current route, or leave it untracked until revalidated. Add full-stack coverage for rename-plus-reuse before the catalog observes the rename.

Medium

  • internal/github/configured_repo_bindings.go:121 — The accepted result from ReconcileRepositoryObservation is ignored. A delayed provider response rejected as stale can still update the exact-path binding, after which callers publish stale route and metadata.

    • Fix: Treat accepted == false as non-authoritative. Prevent binding or publishing that ref, and return either an authoritative catalog ref or a retryable error.
  • internal/server/config_reload.go:423 — Bindings are pruned before SetReposWithContext succeeds. If repository lifecycle application fails, the old in-memory configuration remains active while its bindings may already be deleted, losing stable identity across the next reload or restart.

    • Fix: Commit binding replacement only after a successful reload, or snapshot and restore bindings on every subsequent failure.

Reviewers: 2 done | Synthesis: codex, 11s | Total: 18m55s

@roborev-ci

roborev-ci Bot commented Aug 9, 2026

Copy link
Copy Markdown

roborev: Combined Review (2e8681b)

Code review found four medium-severity correctness and resilience issues; no security vulnerabilities were identified.

Medium

  • Non-atomic repository binding persistenceinternal/server/settings_handlers.go:799, internal/server/repo_import_handlers.go:582
    Repository bindings are persisted before the config file is saved, but save failures restore only s.cfg.Repos. Bulk persistence can also retain earlier bindings when a later item fails, leaving stale bindings that subsequent reloads may treat as authoritative.
    Fix: Make binding updates atomic across the entire mutation and restore the previous binding set whenever binding persistence or config publication fails.

  • Binding mismatches incorrectly treated as safely unresolvedpackages/ui/src/utils/repo-visibility.ts:73
    The frontend interprets matched_repo_count === 0 as proof that an exact entry is safely unresolved. Stable-binding identity mismatches also produce zero matches, causing the stale configured route to be reintroduced after the authoritative catalog excluded it.
    Fix: Expose an explicit resolution or binding-mismatch status and allow fallbacks only for genuinely unbound or offline entries.

  • Hidden repository filtering can fall back to an unsafe route matchinternal/server/helpers.go:125
    A hidden exact entry is matched by stable provenance only while its bound repository remains tracked. If identity verification removes that reference, filtering falls back to the configured route and may hide a different repository occupying that route through an overlapping glob.
    Fix: Resolve hidden exact entries using their persisted binding ID and never fall back to route matching when a stable binding exists.

  • Transient catalog failures permanently remove repository optionsfrontend/src/lib/components/RepoTypeahead.svelte:96
    An initial catalog failure leaves fetchedRepos empty while matched configured repositories are excluded as fallbacks, causing normal desktop and mobile options to disappear for the component’s lifetime.
    Fix: Preserve a usable option snapshot during catalog failures and retry requests with bounded backoff.


Reviewers: 2 done | Synthesis: codex, 16s | Total: 12m26s

@roborev-ci

roborev-ci Bot commented Aug 9, 2026

Copy link
Copy Markdown

roborev: Combined Review (a5a99e9)

The PR needs changes for three medium-severity correctness and resilience issues.

Medium

  • internal/server/settings_handlers.go:1200 — Removing an exact repository does not remove its stable-identity binding. Re-adding the same route from config can resolve against the deleted entry’s old identity, causing incorrect rejection or tracking. Prune the binding within the deletion transaction, and restore both configuration and bindings if persistence fails.

  • internal/github/configured_repo_bindings.go:145 — Provider resolutions without a stable external ID are persisted as route-only rows and reported as successful. This allows callers to publish configuration without a verified identity, undermining route-reuse protection. Reject resolved repositories that lack a stable external ID before saving configuration or updating the tracked set.

  • frontend/src/App.svelte:513 — The app-level catalog request used to validate persisted selections has no retry behavior. On mobile, where the independently retrying typeahead is absent, a transient failure can leave a hidden or removed repository selected indefinitely. Add bounded retries or share the typeahead’s retried catalog state.


Reviewers: 2 done | Synthesis: codex, 14s | Total: 18m55s

@roborev-ci

roborev-ci Bot commented Aug 9, 2026

Copy link
Copy Markdown

roborev: Combined Review (dc3b83f)

Verdict: Changes need follow-up for one high-severity test gap and one medium-severity mobile fallback bug.

High

  • internal/github/configured_repo_bindings.go:34 — The stable-identity route-reuse fix lacks an end-to-end test covering binding persistence, provider rename and route reuse, daemon restart/reload, and resulting tracked/API repository identity. Add a real HTTP API + SQLite test that verifies the original repository remains tracked and the successor does not inherit its configuration provenance.

Medium

  • packages/ui/src/views/mobileActivityRepoOptions.ts:47 — If the initial /repos request exhausts its retries, the mobile selector receives an empty catalog and hides normal configured repositories with matched_repo_count > 0, unlike the desktop fallback. Pass catalog load status into the option builder and, when loading fails, include visible, non-mismatched exact configuration rows.

Reviewers: 2 done | Synthesis: codex, 10s | Total: 18m44s

@mariusvniekerk mariusvniekerk self-assigned this Aug 9, 2026
wesm and others added 10 commits August 9, 2026 13:22
The repository visibility work needed temporary design artifacts during implementation, while the published pull request requires durable decisions to live in the ADR and routed context. Preserve that development boundary alongside the completed operator-facing visibility feature.

- test: restore testify helper guard compliance
- feat: hide configured repositories from interactive UI
- docs: keep repository visibility in the gear menu
- docs: clarify repository visibility menu behavior
- fix: move repository visibility into the gear menu
- docs: retire the repository visibility implementation plan
- fix: clear hidden repository selections
- fix: preserve catalog-backed repository selections
- fix: honor hidden visibility after repository renames

Generated with Codex
Co-authored-by: Codex <noreply@openai.com>
Provider renames left exact configuration rows looking unresolved because settings counted only their stale routes. Mobile activity then rebuilt options from those rows and could expose a repository whose current catalog identity was hidden.

Treat configuration provenance as resolution and make the filtered repository catalog authoritative, retaining exact configuration fallbacks only when they truly have no tracked match.

Generated with Codex
Co-authored-by: Codex <noreply@openai.com>
Host-pinned views intentionally retain their repository even when it is hidden from interactive selectors; catalog pruning must not replace that fixed scope with All repos.

Repository visibility responses contain the entire settings snapshot, so overlapping writes could replay stale state. Serialize those mutations to preserve server-confirmed ordering, and record the shared-worktree configuration safeguard exposed during this review.

Generated with Codex
Co-authored-by: Codex <noreply@openai.com>
Repository settings could report an exact match before its verified identity reached the catalog, briefly removing a newly added repository from selectors and workspace creation. A transient catalog failure could also be mistaken for an authoritative empty response and erase a persisted selection.

Require verified catalog identity before reporting matches, preserve stable identity in offline catalog fallbacks, persist direct additions before publishing success, and retain selector state until a catalog request succeeds.

Generated with Codex
Co-authored-by: Codex <noreply@openai.com>
Repository additions could reach TOML before their resolved catalog identity was durable, so a failed catalog write returned an error while the repository reappeared after reload. Hot reload could likewise advertise a matched repository that the authoritative catalog could not serve.

Repository settings controls also applied independent full-response snapshots, allowing overlapping visibility, clone, refresh, add, or remove operations to replay stale state. Persist identities before publishing configuration state and serialize those mutations so selectors and settings observe one confirmed order.

Generated with Codex
Co-authored-by: Codex <noreply@openai.com>
Maintainers need to preserve archived repository history without carrying inactive projects through active selectors and workspace creation. Publish the one-click settings workflow, TOML equivalent, and glob precedence alongside repository configuration so the durable ADR decision is discoverable in the user guide.

Generated with Codex
Co-authored-by: Codex <noreply@openai.com>
The repository visibility decision is now represented in the published configuration workflow and the implementation itself. Keeping the completed design artifact would duplicate the durable guidance and leave a second documentation surface to drift.

Generated with Codex
Co-authored-by: Codex <noreply@openai.com>
A provider rename can leave the configured path available for a different repository. Treating both provenance and current route as equivalent visibility matches hid that route successor whenever the original exact entry was hidden. Once an exact entry has tracked provenance, restrict its presentation setting to that provenance-bound repository so route reuse remains identity-safe.

Generated with Codex
Co-authored-by: Codex <noreply@openai.com>
A provider rename followed by route reuse could rebind an exact hidden setting to the new route occupant after reload or restart, because the stable association existed only in memory. Persist that association as derived catalog state and reconcile provider-observed routes through the timestamp fence so configuration-owned visibility continues to follow the original repository identity.

Generated with Codex
Co-authored-by: Codex <noreply@openai.com>
A configured path can point at a route successor before the catalog observes the original repository's rename. Publishing that fallback, or accepting an older provider observation, can transfer exact-entry settings across stable identities. Leave mismatched routes untracked, reject stale observations, and restore the prior derived bindings whenever hot reload cannot publish its repository set.

The race lane also demonstrated that fixture startup can exceed 30 seconds under parallel race-detector load, so retain the same bounded wait with enough headroom for that execution shape.

Generated with Codex
Co-authored-by: Codex <noreply@openai.com>
wesm and others added 3 commits August 9, 2026 13:22
Stable repository bindings are derived state, but they must remain consistent with the operator config across partial persistence and save failures. Restore the complete prior binding set when publication fails and keep visibility attached to provider-owned identity instead of a reused route.

Clients also need to distinguish an offline exact entry from a stable-identity conflict. Expose that mismatch explicitly and retain safe configured options while bounded catalog retries recover from transient failures.

Generated with Codex (GPT-5)

Co-authored-by: Codex <noreply@openai.com>
Stable bindings must follow the configuration lifecycle instead of surviving removal or accepting identityless provider responses. Prune bindings as part of deletion and restore derived state when config publication fails so route reuse cannot inherit stale settings.

Mobile selection validation also needs bounded catalog retries because the independently retrying selector is absent on phone routes. A transient failure must not leave a hidden or removed repository filter active indefinitely.

Generated with Codex (GPT-5)

Co-authored-by: Codex <noreply@openai.com>
Mobile selectors must not treat an exhausted catalog request as an authoritative empty result. Keep visible exact configuration rows available while stable-binding mismatches and hidden entries continue to fail closed.\n\nThe stable route-reuse contract also needs a regression at the user-visible boundary. Exercise provider rename, old-route reuse, persisted bindings, server restart, and the repository API against one SQLite catalog so a successor can never inherit exact-entry provenance.

Generated with Codex (GPT-5)
Co-authored-by: Codex <noreply@openai.com>
@mariusvniekerk
mariusvniekerk force-pushed the feat/repository-ui-visibility branch from e7dd346 to 7592e9b Compare August 9, 2026 17:26
@roborev-ci

roborev-ci Bot commented Aug 9, 2026

Copy link
Copy Markdown

roborev: Combined Review (7592e9b)

The changes need fixes for two medium-severity consistency and crash-safety issues.

Medium

  • frontend/src/lib/components/settings/RepoSettings.svelte:102 — Repository mutations bypass SettingsWorkflow transport-uncertainty reconciliation. If a committed request loses its response, the UI reports failure and remains stale; removal also misreports a failed post-DELETE refresh as a deletion failure. Route these commands, including visibility updates, through SettingsWorkflow, or preserve its ordered reconciliation semantics and distinguish refresh failures after acknowledgement.

  • internal/server/settings_handlers.go:1211 — Deletion prunes the stable-identity binding before atomically saving the updated TOML. A process termination between those operations leaves the old configuration without its binding, potentially allowing the path to bind to a route successor after restart. Persist the configuration removal first, then prune the binding, with rollback handling pruning failures while retaining crash-safe ordering.


Reviewers: 2 done | Synthesis: codex, 11s | Total: 16m50s

A committed visibility change can lose its response, and an acknowledged removal must not be reported as failed only because a later refresh fails. Route every repository setting command through the ordered workflow so uncertain writes reconcile against confirmed settings.

Repository removal must also survive interruption without exposing an exact route after its stable binding is gone. Save the config removal first, then prune the derived binding, and restore bindings before config during rollback.

Generated with Codex (GPT-5)
Co-authored-by: Codex <noreply@openai.com>
@roborev-ci

roborev-ci Bot commented Aug 9, 2026

Copy link
Copy Markdown

roborev: Combined Review (a87bcd3)

Changes need fixes: five medium-severity correctness and concurrency issues remain.

Medium

  • Bulk imports can lose stable repository identityinternal/server/repo_import_handlers.go:510
    Bulk imports save the provider-resolved route in Config, while Ref.ConfiguredRepoPath retains the requested route. After a repository rename or redirect, the binding may be stored under a path absent from the saved config and later pruned. Set Ref.ConfiguredRepoPath from the finalized config path before persisting the binding, and add coverage for renamed-route bulk imports.

  • Concurrent glob-refresh rollback can erase valid bindingsinternal/server/settings_handlers.go:960, internal/github/configured_repo_bindings.go:112
    Glob refreshes are not serialized with config reloads, and failed persistence restores the entire binding snapshot. A concurrent refresh rollback can therefore erase exact bindings created by a successful reload. Hold configReloadMu across refresh verification, persistence, and tracked-set replacement, or transactionally isolate binding snapshot, mutation, and rollback.

  • Shared bulk-import timestamps can incorrectly reject later lookups as staleinternal/server/repo_import_handlers.go:650
    A single observation timestamp is captured before all sequential lookups. Later repositories may be rejected as stale if a sync observation occurs before their lookup, even when their provider response is newer. Capture and persist an observation timestamp immediately before each repository lookup.

  • Catalog failures can expose stale renamed repository routesfrontend/src/lib/components/RepoTypeahead.svelte:171, frontend/src/lib/views/mobileActivityRepoOptions.ts:48
    During catalog failure, every non-mismatched exact config path is treated as safe. A bound repository renamed into a hidden glob can reappear under its stale configured route, potentially selecting a route successor. Require authoritative resolved identity before exposing matched exact paths, or include the resolved route and effective visibility in the settings response.

  • Transient catalog states remove valid mobile glob optionsfrontend/src/lib/views/mobileActivityRepoOptions.ts:51
    The mobile selector ignores the retained catalog whenever a refresh starts or fails, so all glob-backed options disappear despite the last successful catalog being preserved. Track whether a catalog has loaded successfully and keep using the retained catalog during refreshes and transient failures.


Reviewers: 2 done | Synthesis: codex, 16s | Total: 18m39s

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants