Public: anyone can read this; the crew can change it.
Removing a member changes what the group is waiting for, and the app says so before it happens #51
Amendment from the planner: this issue covers adding a member too, not only removing one.
Adding is the symmetric case and it is the one that will be met first: a majority of four needs three, and the moment a fifth person joins it needs three still — but a majority of five needs three where a majority of six needs four, so an addition can move an open proposal away from its threshold, and under all an addition means the group is waiting on somebody who was not there a moment ago. None of that may touch anything already decided.
Added criteria, in the same shape as the removal ones: addMember re-tallies every open proposal in the transaction that adds the person; an addition can decide a proposal (under named: it cannot, and under majority it can only where the new denominator lowers nothing — work out which and test it, do not assume); the confirm step on /group says how many open proposals an addition will re-tally and how many it will decide; and re-adding somebody who was removed does not resurrect their old ballots as counting ones unless they are still on the proposal, which they are, so say what happens in the README and test it.
This is still one run: it is one re-tally helper called from two actions, and the tests are the same table with the roster moving the other way. It waits on #57 now rather than #5, because a re-tally that can decide needs the decision path to exist first.
Once ballots exist (#5), the roster is the denominator of every open tally — so
removeMemberis not a list edit, it is a change to what every open proposal needs. Today it would silently move thresholds: a proposal needing three of five could become decided the moment the roster drops to four, or a removed person's ballot could keep counting toward a group they are no longer in. Neither is written down anywhere, and both are the kind of thing a group discovers in an argument.What done looks like
README.mdin a short paragraph before the code is written: a removed person's ballots stop counting toward any open proposal, and nothing alreadydecidedis ever re-tallied — a decision is a fact about the moment it was made.removeMemberre-tallies every open proposal in the same transaction as the removal, and any proposal whose rule is now met is decided right there, emittingdecision.madeper proposal exactly as a vote would — the same code path as #5, not a second one.tallyalready ignores a voter outside the electorate, so this is a matter of passing the new roster, not of new logic insrc/quorum.ts./group(#28) warns first, in words and with numbers: how many open proposals it will re-tally and how many it will decide immediately, computed before the write and shown on a confirm step. No modal, no JavaScript — a second page or a confirm form is enough.DELETE /api/members/:personIdand from MCP, so an agent is told what its removal did rather than getting a bareok.named:rule is untouched by roster changes and the warning says so when one is affected — its electorate is its names, and removing someone from the roster does not remove them from a rule that names them. This is the corner that will be got wrong; test it explicitly.decision.madeonce; a decided proposal's winner anddecided_atare untouched by any later removal; a removed person's ballot stops counting on an open proposal; anamed:proposal's tally does not move; the warning's counts match what the write then does; re-adding the person does not un-decide anything.bun testis green.Files I expect to change:
src/actions.ts,src/actions.test.ts,src/pages/group.ts,src/routes.ts,src/mcp.ts,src/server.test.ts,README.md.Risks: the re-tally must share #5's decide path exactly — two places that can decide a proposal is two places that can decide it twice, and only one of them will have the
WHERE state = 'open'guard. A roster of 256 (ROSTER_MAX) against a hundred open proposals is still one transaction: keep it to one query per proposal at worst, and say in the pull how long it took with the list full. Do not add an undecide door, however tempting it looks once a removal can decide something.Fit: Ledger — the rule written down first, then the transaction that keeps it. A person assigns; I do not.