Follow-up to #390 / #396. Not a claim that the newest-first pick is wrong — it is deliberate, and #396 pinned it on purpose. The gap is that the rule reproduces the exact symptom #390 set out to eliminate when the newest row is withdrawn.
ownedSubmission (internal/cmd/apps.go:234) takes the first slug-matching row and appViewOwnedAdvice prints its Status / DeployState verbatim. The comment there states the hazard being avoided:
an older row's state reads as plain fact about the newest submission: an author whose newest version is pending over an older approved/live one would be told the wrong deploy state of their own app, with nothing on screen to mark it wrong
A withdrawn newest row produces the same class of wrong answer, in the opposite direction.
What I saw
Immediately after a moderator approved sensei@0.1.1, with the deploy already building:
$ civitai app status sensei
Block ID: sensei
Version: 0.1.1
Publish request: pubreq_01KZZ8H20KJ1M753MR4S20SDDV
Status: withdrawn
Deploy state: -
Submitted: 2026-08-13 23:29 CDT
Not live yet — sensei.civit.ai only serves after the app is approved and deployed (deployState 'live').
That reads as "your submission was withdrawn and nothing is happening." The truth, from app status --json at the same moment:
| id |
submittedAt |
status |
deployState |
pubreq_01KZZ8H2… |
04:29:48.436Z |
withdrawn |
null |
pubreq_01KZZ78V… |
04:07:50.846Z |
approved |
building |
It reached live ~2 minutes later. The row the CLI showed was never wrong about itself — it was simply the least informative row available.
Why the withdrawn row was there at all
It was not authored deliberately. Approving one request appears to auto-withdraw the other pending request for the same app: reviewedAt on the approved row is 04:29:49.684Z and updatedAt on the withdrawn row is 04:29:49.689Z — 5 ms apart. So the platform created the row that then outranked everything by submittedAt.
That is the part worth weighing: the tie-break surfaced a row representing no user intent, and hid the one that did.
Suggested direction
Not "pick the oldest" — that reintroduces #390. Some options, roughly in order of how little they disturb the pinned behaviour:
- Keep printing the newest, but never let a terminal-inactive row stand alone. When the newest row is
withdrawn/rejected and a non-terminal or approved row exists, print both: newest: 0.1.1 withdrawn · in flight: 0.1.1 approved, building.
- Prefer the newest non-
withdrawn row for the headline, mentioning the withdrawn one as a footnote.
- At minimum, suppress the "Not live yet" line when another row for the same app is
approved/live — that sentence is the part that converts a confusing status into a wrong conclusion.
Option 1 keeps #396's invariant intact (the newest row is still what's named) while removing the failure mode, and would also cover the ordinary submit → withdraw → resubmit sequence, not just the auto-withdraw case.
Note on the ordering dependency
apps.go flags that server-side newest-first ordering is "an unverified dependency on the route's contract … every row carries SubmittedAt". In this sample the API did return newest-first, and sorting client-side on SubmittedAt would have produced the same (misleading) pick — so that dependency is not what caused this, and closing it would not fix this.
Observed with a build of main at e49ddc6 (after v0.1.94), i.e. with #396 present.
Follow-up to #390 / #396. Not a claim that the newest-first pick is wrong — it is deliberate, and #396 pinned it on purpose. The gap is that the rule reproduces the exact symptom #390 set out to eliminate when the newest row is
withdrawn.ownedSubmission(internal/cmd/apps.go:234) takes the first slug-matching row andappViewOwnedAdviceprints itsStatus/DeployStateverbatim. The comment there states the hazard being avoided:A
withdrawnnewest row produces the same class of wrong answer, in the opposite direction.What I saw
Immediately after a moderator approved
sensei@0.1.1, with the deploy alreadybuilding:That reads as "your submission was withdrawn and nothing is happening." The truth, from
app status --jsonat the same moment:pubreq_01KZZ8H2…withdrawnnullpubreq_01KZZ78V…approvedbuildingIt reached
live~2 minutes later. The row the CLI showed was never wrong about itself — it was simply the least informative row available.Why the withdrawn row was there at all
It was not authored deliberately. Approving one request appears to auto-withdraw the other pending request for the same app:
reviewedAton the approved row is04:29:49.684ZandupdatedAton the withdrawn row is04:29:49.689Z— 5 ms apart. So the platform created the row that then outranked everything bysubmittedAt.That is the part worth weighing: the tie-break surfaced a row representing no user intent, and hid the one that did.
Suggested direction
Not "pick the oldest" — that reintroduces #390. Some options, roughly in order of how little they disturb the pinned behaviour:
withdrawn/rejectedand a non-terminal orapprovedrow exists, print both:newest: 0.1.1 withdrawn · in flight: 0.1.1 approved, building.withdrawnrow for the headline, mentioning the withdrawn one as a footnote.approved/live— that sentence is the part that converts a confusing status into a wrong conclusion.Option 1 keeps #396's invariant intact (the newest row is still what's named) while removing the failure mode, and would also cover the ordinary submit → withdraw → resubmit sequence, not just the auto-withdraw case.
Note on the ordering dependency
apps.goflags that server-side newest-first ordering is "an unverified dependency on the route's contract … every row carriesSubmittedAt". In this sample the API did return newest-first, and sorting client-side onSubmittedAtwould have produced the same (misleading) pick — so that dependency is not what caused this, and closing it would not fix this.Observed with a build of
mainate49ddc6(after v0.1.94), i.e. with #396 present.