Skip to content

[fountain-workbench] A standing proposal is visible without opening the item #7

Description

@jhgaylor

Carried over from the archived managoat/fountain-workbench#32 when the demo
suite was consolidated into this repository. The original repo has been deleted,
so this is the surviving copy.

  • Originally opened by @jhgaylor on 2026-08-24 (PR https://github.com/managoat/fountain-workbench/pull/32)
  • Now lives at: apps/fountain-workbench
  • Status: unmerged feature work. The diff was 1,248 lines — too large for an
    issue body — so it is preserved in the repository at
    salvage/fountain-workbench-pr-32.diff.
git apply --directory=apps/fountain-workbench salvage/fountain-workbench-pr-32.diff

Splits the surfacing half out of item f17d065ff15f. The mechanism landed in #19; this is where it shows.

A proposal is the one state in the app that does nothing until a person answers it, and it rendered in exactly two places — the item rows on the project page and the WorkItem header, both reached by already knowing to go there. So a verdict sat unanswered until somebody happened to look at the item it was on.

The sidebar

An open item carrying a verdict gets a tiny needs you next to its title — the words the board's own column (src/lib/board.ts) already uses for exactly these items, so it is one name across four screens.

The item asked to decide the wording before committing, and the short form deliberately does not say the verdict: a pill reading "won't do" on an item that is still open is the exact confusion wont was separated from done to avoid. The sentence — "Coder says: won't do. Nothing has been retired — the item is still open." — moves into the title.

On whether it fits: I can't screenshot in this sandbox (no headless browser), but the sizing question has a concrete answer without one. The tree already carries a pill in that slot at that size — the one a closed item gets, won't do, eight characters in .pill.tiny. "needs you" is nine. And the two never appear together: the tiny proposal pill is only for an open item, which is the one case the status pill is absent. That reasoning is pinned as a test rather than left in the PR.

The count

Not a fourth number in 12 open · 3 done · 1 won't do. Those three partition the items and a proposal does not — an item waiting on you is still counted in open, which is the whole point of the field being separate from the status — so a fourth number in that line would read as a fourth state. The item itself flagged this ("adds a number to a row that already carries three").

Instead it rides the survey, beside the other things that are happening rather than filed. ItemCounts, ProjectDto and Db.itemCounts are untouched, and a test pins that proposing moves none of the three.

  • Activity gains proposals — the projects list renders it as a pill next to "N working".
  • ActivityDto gains proposals: ProposalEntry[] and proposalsDropped.

The bell

Since there is a lot of notification infrastructure now, and a proposal is the same shape of fact as "N agents are blocked waiting on you", it goes in the panel too — between the two things already there. The order is how long each will wait: a blocked agent is on a five-minute clock, a verdict waits forever but is a question somebody asked you, a finished conversation is news and news keeps.

A verdict row links to the work item, not a thread — the same argument the blocked rows made and won, and it lands harder here: Confirm is what retires the item's computers, and the notes saying why won't do are on the item. The top bar is outside every project so it holds no team and says "A teammate says: won't do"; the item page, which has the team, names them.

Two properties worth calling out:

  • It answers without Fountain. A proposal is a column on the work item, so that half of the survey is a database read — a refused key or a Fountain timeout is a hole in the conversation sweep, and a question standing on an item is not something the browser should stop being told about because of it. Tested.
  • The per-project number is counted before the list is capped, so it cannot say 50 while 55 are waiting.
  • Confirm and Dismiss both drop the row immediately (proposalAnswered, the same early-application feedRead already does), rather than leaving the bell saying "1 verdict waiting on you" for the rest of the minute.

Tests

New cases in server/app.test.ts: the entry's shape and that a member of a shared project is told; a proposal moves none of open/done/wont, and confirming it does; dismissing clears the row and leaves the item open; oldest-first ordering with the cap keeping the oldest while the per-project number stays exact; a proposal left on a closed item is waiting on nobody; and the survey answering with the owner's key refused. Plus src/lib/feed.test.ts and both component tests.

Gate

$ bun run typecheck && bun test && bun run build
 387 pass
 0 fail
 1449 expect() calls
Ran 387 tests across 33 files. [5.16s]
✓ built in 1.55s

One caveat, reported rather than hidden: the cost suite's one conversation Fountain will not answer for is a hole it names test is flaky in a full run — roughly 1 in 8. It reproduces on origin/main unchanged and touches nothing here. Already filed as cf756055744a.

🤖 Generated with Claude Code

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions