Align Trail Status with Server and Refactor List

pull and merge in latest main from the remote - then tell me the semantical diff on this current branch
Merged origin/main cleanly (the auto-merge in cmd/entire/cli/trail_cmd.go resolved fine — the branch's tests still pass post-merge).
Semantic diff vs main
This branch is a single commit (ee8d7d0a6) that improves the empty-state message of entire trail list. The problem it fixes: entire trail list filters to in_progress trails by default, so when a repo has trails but none in progress, the old flat "No trails found." message misleadingly suggested the repo had no trails at all.
Changes in cmd/entire/cli/trail_cmd.go:
- The inline empty-state printing in
runTrailListAllis extracted into a new helper,printTrailListEmpty(w, authorFilter, statusFilters). - The message now names the active status filter, e.g. "No in progress trails found." instead of "No trails found." When the user passed
--status any(no filter), it stays generic. - When a status filter is active, it adds a hint: "Use --status any to see trails in other statuses."
- If an author filter is active, it's appended too: "No in progress trails found for alice."
- The existing "Commands:" block (
trail create/list/update) is unchanged at the end.
Tests added in trail_cmd_test.go (three new parallel unit tests): default status filter names the filter and shows the --status any hint; no filter (--status any) omits the hint and uses the generic message; author filter appears in the message.
Net: +69/−6 lines across the two files — purely a UX/messaging change, no behavior change to which trails are listed.
Make sure that the possible values for a trail's status match the ones existant in the API/data model on the service / database layer
All status validation flows through trail.ValidStatuses(), so create, update, and list --status all automatically reflect the new set.
Done — CLI trail statuses now match the service
The service simplified the status model on June 3rd (migration 20260603120300_simplify_repo_trail_status in entire.io): in_progress and in_review were folded into open, the DB check constraint and the API TrailStatus type are now exactly draft | open | merged | closed. The CLI was still carrying the old six-value set — and this branch's default trail list filter was in_progress, a status the server can no longer return, which would have made the default listing permanently empty.
Changes:
cmd/entire/cli/trail/trail.go— removedStatusInProgressandStatusInReview;ValidStatuses()is nowdraft, open, merged, closed, with a comment tying the set to the server's check constraint.cmd/entire/cli/trail_cmd.go— default--statusfilter fortrail listis nowopen(the status the server migrated the retired values into); the status grouping order is now open → draft → merged → closed; updated the empty-state comment.- Tests updated across
trail_cmd_test.go,trail/trail_test.go, andtrail/store_test.go: replaced retired statuses withopen/draft, and added explicit assertions thatin_progress/in_revieware now rejected by bothStatus.IsValid()and the--statusfilter parser. Also refreshed twotrail_review_cmd_test.gofixtures that used"in_review"(display-only, but stale).
Other enums already matched: priority (urgent/high/medium/low/none) and reviewer status (pending/approved/changes_requested) are identical on both sides. Trails with unknown statuses still land in the "Other" bucket on unfiltered lists, so any future server-side additions degrade gracefully.
Verified: go build ./..., both affected test packages pass, mise run fmt + mise run lint clean.
One thing to note: the CLI's Metadata still has a Type field (bug/feature/...) while the server migration comment mentions a dropped type column — I left that alone since you asked about status, but it may be worth the same treatment in a follow-up.
The full mise run check (unit + integration + e2e canary) is running in the background — I'll commit and push as soon as it passes.
Committed and pushed. The full mise run check passed first (fmt, lint, unit + integration + e2e canary, ~2¼ min).
- Commit
4767f3dc4— "trail: align status values with the server's simplified set" (6 files, +51/−49), pushed toorigin/fix-trail-list-empty-statewith tracking set up. The branch also carries the earlier empty-state commit and the merge of latest main. - I left
.opencode/package-lock.jsonout of the commit — the canary run bumped@opencode-ai/plugin1.4.7 → 1.17.3 in the local environment, unrelated to this change. It's still modified in your working tree if you want to keep or discard it.
GitHub suggests opening the PR at: https://github.com/entireio/cli/pull/new/fix-trail-list-empty-state
PR opened: https://github.com/entireio/cli/pull/1425
It covers both commits on the branch: the empty-state message improvement and the status-set alignment with the server (draft, open, merged, closed, default filter now open). The "1 uncommitted change" warning is just the local .opencode/package-lock.json modification we intentionally left out.
Working tree is clean — I discarded the .opencode/package-lock.json modification that the e2e canary run left behind (it was just a local lockfile re-resolve, not part of your change). The branch is up to date with origin/fix-trail-list-empty-state.
One thing I deliberately left alone: there's a stash from other work — stash@{0}: WIP on feat/trail-api-migration: 0a22289d Update migrate.go. That looks like real WIP from another branch, so I didn't drop it. Say the word if you want it gone (git stash drop) or inspected first (git stash show -p).
Dropped — the stash list is now empty, and local git state is fully clean. (If you ever need it back, the dropped stash commit was bd23bfb84 and stays recoverable via git stash apply bd23bfb84 until gc runs.)
CI is fully green on PR #1425 — all 10 checks pass: lint, binary-size, license check, Cursor Bugbot, and the whole test matrix (core, canary, and all three integration shards). It's ready for review/merge.
It's not this branch — there is no install task in this repo at all. The failure you're seeing is mise erroring with "task not found" and printing the list of available tasks. I checked origin/main and the full git history of mise.toml and mise-tasks/: no install task ever existed or was deleted, so it's equally absent on main. (The only "install" in mise.toml is the go install postinstall hook for the Go toolchain.)
What you're probably after is one of these:
mise run dev:publish— the actual "install" task: builds andgo installsentireandgit-remote-entireinto~/go/binmise run build— just builds the CLI binary
So mise run dev:publish is the equivalent of what mise run install would do. You may be thinking of another repo's task naming.
there's another inconsistency with the trail list output: when the number of trails matching the filters exceeds that limit count set explicitply via limitor implicitly via its default (10), the output just shows "10 trails". this suggests that's the matching number to the filter query, not just the value filtered down. so it should show xx/yyy trails
Include this in the PR as well
additionally: find any other such potential inconsistencies in the trail list command
While that runs, here's what I found and changed. The truncation-count inconsistency existed in three places, all now fixed with a shown/total format that only appears when --limit actually truncated the list:
- The header —
Recent trails · 10now renders asRecent trails · 10/37(and pluralization follows the total, soOpen · 1/3 trails, nottrail). - Per-status group counts in the grouped view —
Open · 8now rendersOpen · 8/20when the page cut that group short. - The "Other" bucket for unknown statuses — same treatment.
Other inconsistencies I found in trail list while auditing:
--jsonflag help said "respects --status filter" but JSON output also respects--authorand--limit. Fixed the description.- Not fixed (judgment call): a status group can vanish entirely — if all of a status's trails fall outside the top-N by update time, its group is silently omitted from the grouped view. The new
10/37header at least signals there's more than shown, but there's no per-status hint. Fixing it would mean renderingMerged · 0/15rows, which felt noisy; flag it if you want that behavior. - Not fixed (by design): explicit
--statuscan't name a server-added status the CLI doesn't know yet —parseTrailStatusFiltervalidates againstValidStatuses(). Unknown statuses are only reachable via--status any(where they land in "Other"). That's an intentional trade-off already documented in the code.
I'll commit and push once mise run check completes.
Done. Commit adfe5a07b is pushed to the PR and the description is updated: https://github.com/entireio/cli/pull/1425
What the commit fixes — the truncation-count inconsistency in all three places it appeared:
- Header:
Recent trails · 10/37(was· 10), with the noun pluralized by the total (Open · 1/3 trails) - Per-status group counts:
Open · 8/20 - "Other" bucket: same
shown/totaltreatment - Plus the stale
--jsonhelp text, which claimed only--statusis respected (it also honors--authorand--limit)
Untruncated lists keep plain counts — the slash form only appears when --limit actually dropped rows. Four new unit tests cover each case, and the full mise run check passed before the commit.
Two findings from the audit I deliberately left as-is: a status group whose trails all fall outside the top-N silently disappears from the grouped view (the 10/37 header now signals it, but rendering Merged · 0/15 rows felt noisy), and explicit --status can't name server-added statuses the CLI doesn't know — that's existing intentional behavior (--status any + "Other" bucket covers it). Happy to address either if you disagree.
there seems to be a bug that the max list of trails returned is always capped at 23. when the limit is lower, I'm seeing "x/23" returned in the CLI - when I set it higher it only says "23 trails" - but looking at the database and backend it's way more trails in that state - what's going on?
Found it — it's a silent server-side pagination cap, and the CLI never pages past it.
What's going on
runTrailListAll calls GET /api/v1/trails/:host/:owner/:repo with no query parameters (trail_cmd.go:187). But the server paginates this endpoint: it defaults to limit=50 (max 200) and returns {trails, total, limit, offset, ...} (trails.ts:628-633 in entire.io). So the CLI only ever receives the first 50 trails, sorted by updated_at descending — then does all its status/author filtering client-side on that 50-row page.
Your "23" is simply how many trails in that filtered status exist among the 50 most recently updated trails. Everything older never left the server:
--limit 5→ 5 shown of 23 matches within the page → "5/23"--limit 100→ all 23 page-local matches shown → "23 trails", even though the DB has far more
Two compounding factors:
- The CLI's
TrailListResponsestruct (api/trail_types.go) doesn't even decode the server'stotal/limit/offsetfields, so it has no way to notice the response was truncated. - My shown/total change is computed from the client-side count, so it inherits the same blind spot — the "total" it shows is really "total within the first server page."
The fix
The server already supports exactly what the CLI does by hand: status (comma-separated, OR'd in SQL), author (login, resolved server-side), limit (1–200), and offset. The CLI should push its filters down as query params and read the returned total for the shown/total display. Design points to settle:
--limitabove 200 would need an offset loop (or just clamp and say so)- The per-status group counts in the
--status anygrouped view would be page-local unless we add a server aggregation — likely fine to keep them page-local since the header shows the real total - Client-side sorting becomes redundant (server already orders by
updated_at desc)
Want me to implement the pushdown in this PR, or keep this PR display-only and do the pagination fix as a follow-up? Given it changes the request shape and has its own edge cases, I'd lean toward a separate PR.
please implement using the service side filtering logic
re the 200 limit: make it clear when we get capped there, but normally listing trails should not need that many results
for status any let's not do any aggregation or breakdown by status, just show the total count matched
Implementation is complete; full mise run check is running and I'll commit, push, and update the PR when it's green. Summary of what changed:
Server-side filtering (trail_cmd.go)
runTrailListAllnow sendsstatus(comma-separated),author(the resolved login, including--author me), andlimitas query params via a newtrailListQueryhelper — the server does the filtering, ordering (updated_at desc), and truncation.TotalMatchednow comes from the server'stotalfield (newly decoded inapi.TrailListResponsealong withlimit/offset), so10/137reflects the real database count, not the first-page count. Older servers withouttotaldegrade to plain counts.- All the client-side filter/sort/limit machinery is deleted (
filterTrailsByAuthor,filterTrailsByStatuses,limitTrails,sort.Slice, …).
200-cap visibility — --limit above 200 is clamped in the request, and when matches actually exceed what was shown, the list is followed by: Note: --limit 500 exceeds the server maximum of 200 trails per request.
--status any display — per your call: no per-status aggregation or grouped breakdown anymore. It's one flat list with the header showing the total match count, and a STATUS column appears whenever more than one status can occur (so unknown server-side statuses also stay visible, replacing the old "Other" bucket).
Same-bug-class finding: findTrail (backing trail show, update, and by-number/by-branch lookups) also scanned the unpaginated first page — so entire trail on a branch whose trail wasn't in the 50 most recently updated would claim no trail exists. I applied a stopgap (request the 200 max) and left a comment; the real fix needs a server-side branch filter param or using the by-number detail endpoint, which I'd suggest as a follow-up.
Pushed and PR updated: https://github.com/entireio/cli/pull/1425
- Commit
9f453fc10— "trail list: push filters, limit, and pagination to the server" (+123/−247; the deleted client-side filter/sort/limit machinery accounts for the negative balance). Fullmise run checkpassed before committing. - The PR body now covers all four changes on the branch, plus a Follow-up section flagging the remaining
findTrailblindness past 200 trails (needs a server-sidebranchfilter or the by-number detail endpoint — a service-repo change).
With this, your "capped at 23" symptom is fixed at the root: the 23 was just the matching slice of the first 50-row server page. Now the server filters and counts, so you'll see the real totals (e.g. 10/137), and anything beyond a 200-row request gets an explicit cap note instead of silently vanishing.