Skip to content

feat: admin members roster with human spam votes - #187

Merged
themightychris merged 9 commits into
developfrom
feat/admin-members-moderation
Sep 18, 2026
Merged

themightychris merged 9 commits into
developfrom
feat/admin-members-moderation

Conversation

@themightychris

@themightychris themightychris commented Sep 18, 2026

Copy link
Copy Markdown
Member

Implements plans/admin-members-moderation.md: staff get one place to see who joined and what they've done on the site, and to record a human spam/not-spam judgment the offline pipeline treats as final.

What's here

  • API (specs/api/moderation.md): GET /api/admin/members (newest first; q, vote, joined range, includeDeactivated, sort, paging; staff-visible email, last sign-in, GitHub-linked, footprint counts, latest vote), GET /api/admin/members/:slug (full footprint + vote history), POST /api/admin/members/:slug/vote. All 404 to non-staff. A spam vote deactivates in the same transaction; a legit vote reactivates only when it reverses a prior spam vote; self-votes 422; re-voting replaces the caller's record. Votes commit as the voter (Test staffer <staffer@users.noreply…> asserted in tests).
  • Store: person-evaluations loaded from published into InMemoryState (personEvaluations + evaluationsByPerson), applied via StateApply, covered by the hot-reload swap test.
  • Web (specs/screens/admin-members.md): /admin/members — filters, expandable footprint, Spam / Not spam with an optional note, "Hidden by {voter}" state, own row disabled; linked from the staff menu.
  • Pipeline: prune-spam takes --evaluations-repo (the private clone) and --human-votes-ref; the latest human vote is final and a human spam vote bypasses membership protection. docs/operations/spam-detection.md rewritten for the two-repo layout and the mandatory evaluate-llm --filter spam step.
  • Specs: spam-exclusion.md (sources, human-vote-is-final, heuristic-has-no-confidence), person-lifecycle.md (vote-driven deactivate + reversal rule). Evaluator naming is human-<slug> — gitsheets 2.x rejects : in path components.

Done outside this repo tonight

  • Private repo CodeForPhilly/codeforphilly-spam-detection created (house shape: develop default, merge-only, rulesets), on gitsheets 2.x, scripts refactored to read public data from a CFP_DATA_GIT_DIR clone; heuristic dry-run verified in the new layout. spam-detection and the stray conflicts/* branch deleted from the public data repo (codeforphilly-data Smooth out getting started #5).
  • person-evaluations sheet config added to the data repo's empty, published, and fixture branches.

Validation

type-check and lint clean; API 37 files / 460 tests; web 28 / 124. Browser check on sandbox after deploy.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LFyA5poHwrhAktrnsKrUiQ

themightychris and others added 8 commits September 18, 2026 14:30
Staff get one place to see who joined and what they have done on the
site, and to record a human verdict the offline pipeline treats as
final. Human votes live on published as person-evaluations records
authored by the voter; a spam vote deactivates immediately. Machine
evaluations and Slack-derived inputs move to a private repo, so the
public data repo never carries message text or LLM prose about people.
Also records that heuristic records have no confidence and must be
LLM-confirmed before they can prune.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFyA5poHwrhAktrnsKrUiQ
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFyA5poHwrhAktrnsKrUiQ
…Method

gitsheets 2.x rejects ':' in a path component, so the May-era
`human:<slug>` naming cannot be written. Also drop `lastLoginMethod`
from the roster row — session metadata records when a session was
issued, not how.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFyA5poHwrhAktrnsKrUiQ
Register the sheet, keep the records in InMemoryState keyed
personSlug/evaluator with a per-person index, apply them through
StateApply, and declare the config in every test fixture — gitsheets'
openStore is strict about validators whose config is missing.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFyA5poHwrhAktrnsKrUiQ
GET /api/admin/members (newest first, filters, staff-visible email and
last sign-in, footprint counts, latest vote), GET /api/admin/members/:slug
(full footprint + vote history), POST /api/admin/members/:slug/vote. A
spam vote deactivates in the same transaction; a legit vote reactivates
only when it reverses a prior spam vote. Every endpoint 404s to
non-staff. Votes commit as the voter.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFyA5poHwrhAktrnsKrUiQ
…ns repo

--evaluations-repo points at the private codeforphilly-spam-detection
clone; --human-votes-ref (default: the pruned branch) supplies staff
votes from the data repo. The latest human vote is final and a human
spam vote bypasses the project-membership protection. The operations
doc now describes the two-repo layout and the mandatory
`evaluate-llm --filter spam` confirmation step.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFyA5poHwrhAktrnsKrUiQ
Staff-only page: newest signups first, search and vote/sort filters,
expandable footprint and vote history, Spam / Not spam buttons with an
optional reasoning note. Linked from the user menu for staff.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFyA5poHwrhAktrnsKrUiQ
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFyA5poHwrhAktrnsKrUiQ
@themightychris themightychris changed the title docs(specs): admin members roster with human spam votes feat: admin members roster with human spam votes Sep 18, 2026
@themightychris
themightychris marked this pull request as ready for review September 18, 2026 19:30
@themightychris
themightychris merged commit d1ed8ea into develop Sep 18, 2026
@themightychris
themightychris deleted the feat/admin-members-moderation branch September 18, 2026 19:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant