| name | new-bill-feature |
|---|---|
| description | Guide for adding a new feature to the Bill/voting system in webiscite |
| disable-model-invocation | true |
| argument-hint | [description of the feature] |
Implement a new feature for the Bill/voting system: $ARGUMENTS
The Bill system spans these files. Review each to determine if it needs changes:
Models & Logic:
democrasite/webiscite/models.py— Bill, Vote, PullRequest models (fields,vote(),submit(),_check_approval(), Status choices)democrasite/webiscite/managers.py—BillManager.create_from_github(), queryset annotations (yes_percent, no_percent, user_vote)democrasite/webiscite/constitution.py—is_constitutional(),update_constitution()for protected file rangesdemocrasite/webiscite/tasks.py—submit_bill()Celery task (approval check → GitHub merge → constitution update)democrasite/webiscite/webhooks.py—PullRequestHandler(opened/reopened/closed) and HMAC-validatedGithubWebhookView
Views & API:
democrasite/webiscite/views.py— BillListView, BillDetailView, BillUpdateView, vote_view (AJAX POST)democrasite/webiscite/api/views.py— BillViewSet (list/retrieve/update + vote action), IsAuthorOrReadOnly permissiondemocrasite/webiscite/api/serializers.py— BillSerializer, PullRequestSerializerdemocrasite/webiscite/urls.py— Template view URL patternsconfig/api_router.py— DRF router registration
Templates & Frontend:
democrasite/templates/webiscite/bill_list.html— Card grid of billsdemocrasite/templates/webiscite/bill_detail.html— Single bill pagedemocrasite/templates/webiscite/snippets/vote.html— Vote progress bar + yes/no buttonsdemocrasite/templates/webiscite/bill_form.html— Edit form (name, description)democrasite/static/js/vote.js— AJAX vote handler, DOM updates for counts and progress bar
Tests (mirror each area above):
democrasite/webiscite/tests/test_models.pydemocrasite/webiscite/tests/test_views.pydemocrasite/webiscite/tests/test_tasks.pydemocrasite/webiscite/tests/test_webhooks.pydemocrasite/webiscite/tests/test_constitution.pydemocrasite/webiscite/tests/test_templates.pydemocrasite/webiscite/tests/factories.py— PullRequestFactory, BillFactory, TaskFactory
Config & Admin:
democrasite/webiscite/admin.py— SimpleHistoryAdmin for Bill, PullRequestdemocrasite/webiscite/context_processors.py— Exposesgithub_repoto templatesconfig/settings/base.py— WEBISCITE_* settings (quorum, majority thresholds, voting period, GitHub token/repo)
- Bill status choices: DRAFT, OPEN, APPROVED, AMENDED, REJECTED, FAILED, CLOSED
- Votes are M2M through Vote model with unique constraint on (bill, user)
- Bill.vote() toggles existing votes; raises ClosedBillVoteError if bill not OPEN
- Constitutional bills need WEBISCITE_SUPERMAJORITY (66.67%), normal need WEBISCITE_NORMAL_MAJORITY (50%)
- Each Bill has a OneToOne PeriodicTask for scheduled submission
- Managers annotate querysets with vote percentages and user vote status
- API vote endpoint expects {"support": true/false}, template vote_view expects POST with "vote" field
- django-simple-history tracks Bill and Vote changes automatically
- PullRequest has a
draftboolean field tracking GitHub's draft state - Draft bills (from draft PRs) cannot be voted on or submitted; they transition to OPEN via Bill.publish() when the PR is marked ready for review
- The
unique_active_pull_requestconstraint prevents duplicate bills for the same PR in bothopenanddraftstatuses - PullRequest.close() closes both open and draft bills
- The submit PeriodicTask is created disabled for draft bills; Bill.publish() enables it and resets last_run_at so the voting period starts from publication
- GitHub's
ready_for_reviewwebhook action triggers PullRequestHandler.ready_for_review(), which updates the PR and publishes the draft bill - GitHub's
synchronizewebhook action (new commits pushed to PR) triggers PullRequestHandler.synchronize(), which updates the PR SHA and closes any open bill with AMENDED status; draft bills are not affected - Bill.close() accepts an optional
statusparameter (default Bill.Status.CLOSED) to set a different terminal status (e.g. AMENDED)
- Read the relevant files from the checklist above
- Plan the changes needed across all layers (model → serializer → view → template → test)
- If adding a model field, create a migration with
just manage makemigrations - Implement changes
- Update or add factories in factories.py for any new model fields
- Write tests covering the new functionality
- Run
just run pytest democrasite/webiscite/tests/to verify - Run
just lintto check style - Update documentation:
- Update the "Key patterns to follow" section in this skill file (
.claude/skills/new-bill-feature/SKILL.md) with the new feature's patterns - Update
docs/webiscite.rstif the feature changes the pull request processing pipeline or bill lifecycle - If files were created or deleted, run
just run make -C docs apidocsto regenerate API docs
- Update the "Key patterns to follow" section in this skill file (