Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 16 additions & 23 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,30 @@
**A fix or improvement outside a module?** Title it `Fix: …`, `Improvement: …` or `Docs: …` (it is labelled from that), keep it to one change, delete everything below and answer three questions in plain words:
**A fix or improvement outside a module?** Title it `Fix: …`, `Improvement: …` or `Docs: …` (it is labelled from that), keep it to one change, delete everything below and answer four questions in plain words:

- **What was wrong or hard:**
- **What this changes:**
- **How I checked it:** (`npm run pr:ready` and anything else you ran)
- **What the guides lacked or got wrong, and where I fixed it:** ("nothing" is a fine answer)

**A module or module update:** describe the change in behavior, module version(s), compatibility and source/media attribution. Then say what the guides lacked or got wrong while you built it and link the `Docs:` pull request that fixes it, or write "nothing"; the module release itself stays free of guide edits.
**A module or module update:** describe the change in behaviour, module version(s), compatibility and source/media attribution. Then say what the guides lacked or got wrong while you built it and link the `Docs:` pull request that fixes it, or write "nothing"; the module release itself stays free of guide edits.

Existing module authors can opt into [automatic publication](../docs/MODULE_AUTHOR_UPDATES.md) after reviewing all evidence:
The checks do the rest. `npm run pr:ready` (a registered author: `npm run pr:ready -- --author <login>`) runs what CI runs: the module contract, version and release notes, compatibility and UI claims, resource and qualification records, documentation and licences. A pull request with a red check is labelled `needs-work` and leaves the review queue until it is green; after 14 days without a new commit it is closed, and you can reopen it once it is green. Until your first module is published, one module pull request is reviewed at a time.

No check can prove these, so you vouch for them:

- [ ] Changing a module someone else wrote: its author said yes before I started, and I link it here (a GitHub link, or Discord and the day). [Ask the author first](../docs/DEVELOPER_WORKFLOW.md#ask-the-author-first)
- [ ] I read the guide for its category in `docs/module-guides/` (and `sequencing.md` if it acts in time), and TESTING.md lists what I did not test.
- [ ] Source and media are mine or properly licensed, with authors and full licence texts kept. Nothing comes from Elektron firmware: no extracted code or tables, upgrade files or factory content.
- [ ] Screenshots are real captures of the current module UI. Hardware results are what a named person saw on this exact build; emulator results are labelled as emulator results.

Registered module authors can opt into [automatic publication](../docs/MODULE_AUTHOR_UPDATES.md) after reviewing all the evidence. An update that reaches firmware or hardware addresses the published version did not use goes to owner review instead, and followers hear about an automatic release 48 hours after it goes live:

- [ ] Automatically merge and publish my module update after checks pass.
- [ ] I verified the source, licences, UI and qualification reports, including instance isolation and Part/project/reboot persistence where applicable; no required acceptance check is failed or untested.

- [ ] Changing a module someone else wrote: its author said yes before I started, and I link it here (a GitHub link, or Discord and the day). [Ask the author first](../docs/DEVELOPER_WORKFLOW.md#ask-the-author-first)
- [ ] New or changed module: I read the guide for its category in `docs/module-guides/` (and `sequencing.md` if it acts in time), walked its checklists, and TESTING.md lists what I did not test. `npm run module:doctor -- <id>` is green.
- [ ] The module builds, installs and works when it is the only module chosen. It depends on no other module: no `requires`, no hooks into another module, not stacked on another module's pull request. Its key gestures and stock screens are in `compatibility.uiClaims` (`[]` for none).
- [ ] Every code change to a module has a greater semantic version and exact catalog pin (documentation and media edits need none).
- [ ] Source and media are original or properly licensed; authors and full licence texts are preserved.
- [ ] No Elektron firmware, extracted routines/tables, upgrade files or other infringing material is included.
- [ ] Every new/changed module with OT UI has real screenshots of its location and relevant control pages, manifest `access` instructions, and `media[].otUi` version/build/setup provenance. Automatic USB modules without OT UI use the narrow `access.noUiReason` declaration for reviewer verification.
- [ ] I verified the captions, button/menu steps, screenshot authenticity and page coverage against the current module UI.
- [ ] TESTING.md records commands, results, exact source, conditions and limitations; emulator and hardware evidence are separate.
- [ ] CPU, DSP core and memory gauges are populated in `resources.impact` with rough load tiers, workload, rationale and source records. Reviewer: I checked the estimates; they do not imply exact hardware headroom percentages.
- [ ] Runtime/resource changes and new modules: `tests.qualification` contains worst-case cycle counts for every processor used, under parameter extremes, simultaneous modulation, mode changes and maximum load, within the declared real-time budget.
- [ ] Runtime/resource changes and new modules: exact memory regions include code, state, tables, buffers, stack/heap, padding and shared allocations; words, word widths, bytes and maximum-instance totals agree with the native allocation/build report.
- [ ] Runtime/resource changes and new modules: this version/source/build has attributed real-hardware test evidence verified by the reviewer (the owner for first releases; the registered author for scoped updates). Record tester, date, source/build identity, observed behavior, workload and limitations. A reported functional test must stay labelled as reported; unknown model, duration and maximum load must stay explicit.
- [ ] Reviewer: for new modules and runtime/resource changes, I verified the actual cycle/memory reports, coverage of modulation and maximum load, and attributed hardware evidence and its actual coverage against the submitted source/build. A declaration or emulator-only result is insufficient.
- [ ] Complete README/TESTING/licence/control/compatibility documentation, at least three practical tutorial steps and real black-and-white PNG screenshots document the current behavior with honest version/build provenance; README and the applicable qualification/retained-evidence documentation record are synchronized. Yellow captures do not qualify.
- [ ] Reviewer: I verified tutorial usefulness, all relevant control/page coverage, screenshot authenticity, exact access instructions and full documentation completeness.
- [ ] I rebased onto current main and ran module/version checks on this revision.
Reviewer (the owner for a first release, the registered author for their own update):

Validation commands and results:
- [ ] I checked the cycle and memory reports against the worst case, the attributed hardware evidence against the submitted source and build, and the screenshots, tutorial and access steps against the current UI.

For an editorial-only update, use `tests.retainedEvidence` referencing the original published version in approved main history. CI compares protected source, defaults, compatibility, resource claims, reports and shared runtime/build inputs before permitting reuse; preserve original measurement/hardware status and capture provenance. All version, documentation and media/rights requirements still apply; reviewer verification follows the author/owner scope above.
Validation commands and results:

Owner merge or the verified author-release workflow approves the exact source version. Link issues with “Related to #...”; close them only after successful deployment and live download verification. Failed source builds retain the previous publication. Metadata validation and successful assembly are not hardware qualification.
Link issues with "Related to #…"; they are closed after the release is live and its download is verified.
4 changes: 4 additions & 0 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ jobs:
actions: read
outputs:
modules: ${{ steps.changes.outputs.modules }}
author-modules: ${{ steps.approval.outputs.author-modules }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
Expand All @@ -30,6 +31,7 @@ jobs:
with:
node-version: 24
- name: Verify owner or scoped module-author approval for this exact source commit
id: approval
run: node scripts/verify-merge-approval.mjs
env:
GITHUB_TOKEN: ${{ github.token }}
Expand Down Expand Up @@ -137,6 +139,8 @@ jobs:
- run: npm run licenses:check && npm run machines:check && npm run modules:check && npm run elekloader:check && npm run sdk:check
- run: npm run build
env:
# Followers hear about an author's own release 48 hours after it goes live (server/module-updates.ts).
MODWERK_AUTHOR_RELEASE_MODULES: ${{ needs.approval.outputs.author-modules }}
VITE_COMMUNITY_API_URL: ${{ vars.COMMUNITY_API_URL }}
VITE_REPOSITORY_URL: ${{ github.server_url }}/${{ github.repository }}
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
Expand Down
30 changes: 30 additions & 0 deletions .github/workflows/pr-triage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Triage pull requests
# Keeps red and queued pull requests out of the owner's review list (scripts/pr-triage.mjs).
# Checks out trusted main only and reads PR metadata through the API: no PR code, dependency or cache.
on:
schedule:
- cron: '41 * * * *'
workflow_dispatch:
permissions:
contents: read
pull-requests: write
issues: write
checks: read
concurrency:
group: pr-triage
cancel-in-progress: false
jobs:
triage:
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: main
persist-credentials: false
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 24
- run: node scripts/pr-triage.mjs
env:
GITHUB_TOKEN: ${{ github.token }}
9 changes: 9 additions & 0 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Code of conduct

The [Modwerk community rules](https://modwerk.app/#community-rules) apply here too: in issues, pull requests and reviews.

- Modules are free and experimental, and most are made by one person in their spare time. Authors and maintainers owe no fix, feature or reply time.
- Criticise the work, not the person. A change to someone else's module needs its author's agreement.
- Credit the people whose work you build on, and keep licences intact.

For rude or hostile behaviour the usual steps are a reminder, then hidden comments, then a temporary block, then a permanent one. Threats, harassment and unlawful content can skip steps. Report a problem to [support@modwerk.app](mailto:support@modwerk.app).
1 change: 1 addition & 0 deletions changelog/2026-10-25-maintainer-safeguards.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Module releases and community: a registered author's automatic release now goes to owner review when it reaches firmware or hardware addresses its published version never used, the owner is told about every automatic release, and followers hear about one 48 hours after it goes live, so a bad or hijacked update can be replaced first. Pull requests with red checks leave the review queue (`needs-work`, closed after 14 quiet days, reopen any time), the pull request template keeps only what no check can prove, and the report forms, forum tips and community rules now say what to expect from module authors and how moderation escalates.
11 changes: 11 additions & 0 deletions docs/COMMUNITY_OPERATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,17 @@ For suspected credential compromise, pause registrations and affected writes thr

Developer OAuth setup and report-consent boundaries are documented in [DEVELOPER_WORKSPACE.md](DEVELOPER_WORKSPACE.md). Rotating the GitHub OAuth client secret invalidates developer sessions; claims are retained for independent revocation/review. GitHub-only identities use the support contact for removal requests rather than a password-based member request.

## Review queue and saved replies

`.github/workflows/pr-triage.yml` keeps red and queued pull requests out of the owner's list (see [Make it mergeable](DEVELOPER_WORKFLOW.md#make-it-mergeable)). The owner's review list is `is:pr is:open draft:false -label:needs-work -label:one-at-a-time`. `PR_TRIAGE_DRY_RUN=1 GITHUB_REPOSITORY=repeat98/modwerk GITHUB_TOKEN=$(gh auth token) node scripts/pr-triage.mjs` prints what the next run would do without writing.

Steps for rude or hostile behaviour are in the community rules: a reminder, hidden content, a temporary suspension, then a permanent one. Threats, harassment and unlawful content can skip steps. These replies keep a rule from sounding like a brush-off; adapt them, keep them short and first-person:

- **Someone else's module:** "Thanks for working on this. Changes to a module go through its author, so please open this as a suggestion on their module, or ask them first and send it with their OK. If you want to take it in another direction, a module of your own is welcome: Start developing walks you through it."
- **A demand for a fix or feature:** "Thanks for the report. Modules are free and made in spare time, so there is no fix date. The steps and log you gave are exactly what helps whoever picks it up."
- **Rude message (first step):** "I want to help with this, and I will once we keep it about the module. The community rules ask everyone to criticise the work, not the person."
- **Duplicate report:** "This is the same problem as #N, so I am closing this one to keep the discussion in one place. Please add anything new there."

## Administrator role

A verified, unsuspended member whose `users.is_admin` is `1` sees the Admin workspace and passes every `/api/admin/*` check; nobody else sees it, and the page tells other visitors it is for administrators only. The role cannot be set through the API. The owner grants or removes it directly in D1 (`UPDATE users SET is_admin=1 WHERE username='…'`). Migration 0022 adds the column and must be applied **before** the Worker that reads it is deployed. The separate administrator key (`ADMIN_KEY_SHA256`, `POST /api/auth/admin`) still works for API access as break-glass access, but the website no longer offers a key form.
Expand Down
1 change: 1 addition & 0 deletions docs/DEVELOPER_WORKFLOW.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ These stumbling blocks have each cost a contributor and the owner a repair round
- **Merged before green.** The `main` ruleset requires the `module-pr-ok` check, which passes only when every other PR check passed or was skipped by scope. The owner approves a first-time contributor's run and turns on auto-merge, and GitHub merges once it is green; a red or unfinished PR does not merge.
- **Compiled packages.** The `octatrack-source` and `elemod-source` jobs rebuild packages in the pinned Docker toolchain and require the committed ones to match. Reproduce them before you push: `bash scripts/build-modules-isolated.sh <clean checkout> <new dir> <image id>` for the Octatrack, `bash scripts/build-elemod-isolated.sh` and `node scripts/verify-elemod-release-exports.mjs <dir>` for the Digitakt and Digitone, from a clean, committed tree.
- **Local Python helpers.** Use `python3 -B` or `PYTHONDONTWRITEBYTECODE=1`: bytecode caches under preserved imports fail the import-integrity check, even when the authored source is unchanged.
- **Red checks leave the review queue.** An hourly job labels a pull request with a failing check `needs-work` and comments once; the label goes away when the checks are green. A PR still red 14 days after the label, without a new commit, is closed; reopen it once `pr:ready` says Ready. Until your first module is published, a second open module PR is labelled `one-at-a-time` and waits for the first.
- **Your first PR waits for the owner.** GitHub holds a first-time contributor's CI runs until the owner approves them, after every push. Run `pr:ready` locally and push once, rather than often, so each approval counts.


Expand Down
Loading
Loading