Public: anyone can read this; the crew can change it.

A question gets an answer: one level of replies, and an unanswered question says so #38

stopped no changes pushed: You've hit your weekly limit · resets Sep 20, 2am (UTC) (api_error) opened this
opened this

The thread is flat. A question is addressed to the proposal's author, and there is no way to answer it under it and nothing that tells a reader whether it was ever answered — so asynchronous deliberation loses the one thing it is for. Give a remark one level of replies, and let the reply be the answer.

What done looks like

  • [ ] A migration appended to migrations in src/db.ts adds reply_to INTEGER REFERENCES remark (id) ON DELETE CASCADE to remark, nullable with no default, and an index on it. Never edit a migration that has run.
  • [ ] addRemark takes an optional replyTo, validated in the action: it must name a remark on the same proposal (invalid, “A reply belongs to a remark on this proposal.”), that remark must not itself be a reply (invalid, “A reply cannot be replied to.” — one level, always), and a reply is a comment (invalid for a reply that claims question or counter). Anon is still signin_required.
  • [ ] listRemarks returns the thread in reading order — each top-level remark followed by its replies, oldest first — from one query, not one per remark.
  • [ ] src/pages/proposal.ts renders replies indented under their parent; every remark gets a stable anchor (id="r<id>") and a permalink to it, so a remark can be linked.
  • [ ] A Reply control under every top-level remark composes a reply with the parent already set. No new JavaScript: a form per remark, or a link to the composer that carries the parent, is enough.
  • [ ] A question with no reply is marked “unanswered” where it sits, and the line above the thread says how many are (“2 questions unanswered”). Answering clears the mark — there is no second column and no state to keep in sync; the reply is the answer.
  • [ ] Deleting a parent takes its replies with it (the foreign key does it) and the live region shows the thread without them.
  • [ ] Every door: POST /api/proposals/:id/remarks takes replyTo, MCP's add_remark takes it with the one-level rule in its sentence, and the terminal shows replies indented under their parent.
  • [ ] Tests that fail without each rule: a reply naming a remark on another proposal; a reply to a reply; a reply with kind counter; reading order with two parents and interleaved replies; the unanswered count before and after an answer; the cascade on delete; and an existing database with remarks in it migrating forward with its rows intact (src/db.test.ts).

Files I expect to change: src/db.ts, src/db.test.ts, src/actions.ts, src/actions.test.ts, src/pages/proposal.ts, src/routes.ts, src/mcp.ts, src/tty.ts, src/server.test.ts, static/app.css.

Risks: The thread is the live region and it grows at the bottom — read the comment at the top of src/pages/proposal.ts and keep whatever someone is typing outside anything that gets swapped, including a per-remark reply form that is open when an event arrives. A new column on a table that already holds rows is exactly the shape of failure #29 is about: run the app against a database that already has proposals and remarks before writing the page. Reading order must come from SQL (ORDER BY coalesce(reply_to, id), id) rather than from sorting an unbounded list twice in TypeScript. A counter that is accepted (#6) still names an option; a reply must not be able to smuggle option_label past that rule.

Fit: Ledger — the argument as a record, every line traceable to the line it answers. A person assigns; I do not.

commented

You've hit your weekly limit · resets Sep 20, 2am (UTC)

commented

Interrupted, not the work (outage; strike cleared 2026-10-02) — was: Parked by the crew: the run ended without a pull: no changes pushed: You've hit your weekly limit · resets Sep 20, 2am (UTC) (api_error)

commented

You've hit your weekly limit · resets Sep 20, 2am (UTC)

commented

Interrupted, not the work (outage; strike cleared 2026-10-02) — was: Parked by the crew: the run ended without a pull: no changes pushed: You've hit your weekly limit · resets Sep 20, 2am (UTC) (api_error)

commented

Amendment from the planner — this issue is split; build the first half only.

Keep: the reply_to migration and its index, the validation in addRemark (same proposal, one level only, a reply is a comment), listRemarks returning reading order from one query (ORDER BY coalesce(reply_to, id), id), replies rendered indented under their parent on /p/:id with a stable id="r<id>" anchor and a permalink, a Reply control that composes with the parent set, the cascade on delete, and the migration test against a database that already holds remarks.

Moved to #46, which waits on this one: the "unanswered" mark and its count, the author's list of questions still owed an answer, and replyTo through the API, MCP and the terminal. Three doors and a derived count on top of a migration was two runs in one issue.

The parks on this issue were a weekly limit and a DNS failure, not anything wrong with the work — nothing here has been attempted yet.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs