From 28b2df61327acfbf8f5e8c67e00cb20915a73cac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= Date: Fri, 8 May 2026 11:50:43 -0400 Subject: [PATCH 1/3] Implemented democratic voting process for project decisions Establishes a formal, EDP-compliant decision-making process for Eclipse ThreadX using GitHub Discussions and immutable git-backed decision records. Changes: - VOTING.md: full voting rules (eligibility, vendor neutrality, 2-week window, majority rules, tie-breaking by project leads, mailing list announcements, grievance escalation, governing docs appendix) - decisions/TEMPLATE.md: decision record authoring template - decisions/README.md: directory anchor - .github/CODEOWNERS: decisions/ gated to project leads - .github/DISCUSSION_TEMPLATE/proposal.yml: structured proposal form - .github/PULL_REQUEST_TEMPLATE/decision_record.md: PR checklist - .github/scripts/validate_decision.py: CI validator for DR format - .github/workflows/validate-decisions.yml: validation workflow - SSH-SIGNING.md: SSH commit signing setup guide (Windows/Ubuntu/Fedora/macOS) - README.md: participation guide, committer election info, key doc links - CONTRIBUTING.md, LICENSE: standard project files Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/CODEOWNERS | 4 + .github/DISCUSSION_TEMPLATE/proposal.yml | 48 +++++ .../PULL_REQUEST_TEMPLATE/decision_record.md | 19 ++ .github/scripts/validate_decision.py | 131 ++++++++++++ .github/workflows/validate-decisions.yml | 40 ++++ CONTRIBUTING.md | 92 ++++++++ LICENSE | 21 ++ README.md | 23 +- SSH-SIGNING.md | 197 ++++++++++++++++++ VOTING.md | 116 +++++++++++ decisions/README.md | 6 + decisions/TEMPLATE.md | 25 +++ 12 files changed, 720 insertions(+), 2 deletions(-) create mode 100644 .github/CODEOWNERS create mode 100644 .github/DISCUSSION_TEMPLATE/proposal.yml create mode 100644 .github/PULL_REQUEST_TEMPLATE/decision_record.md create mode 100644 .github/scripts/validate_decision.py create mode 100644 .github/workflows/validate-decisions.yml create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 SSH-SIGNING.md create mode 100644 VOTING.md create mode 100644 decisions/README.md create mode 100644 decisions/TEMPLATE.md diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..5ddf28f --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,4 @@ +@eclipse-threadx/admins + +# Decision records require a project lead to review and approve +decisions/ @eclipse-threadx/iot-threadx-project-leads diff --git a/.github/DISCUSSION_TEMPLATE/proposal.yml b/.github/DISCUSSION_TEMPLATE/proposal.yml new file mode 100644 index 0000000..6133496 --- /dev/null +++ b/.github/DISCUSSION_TEMPLATE/proposal.yml @@ -0,0 +1,48 @@ +title: "[Proposal] " +labels: ["proposal"] +body: + - type: markdown + attributes: + value: | + > **Who can open proposals?** Only members of `@eclipse-threadx/iot-threadx-committers` + > or `@eclipse-threadx/iot-threadx-project-leads`. + > + > Voting opens immediately and closes **14 days** from the date this discussion is opened. + + - type: textarea + id: proposal + attributes: + label: Proposal + description: What are you proposing? Be specific and self-contained. + placeholder: "I propose that we..." + validations: + required: true + + - type: textarea + id: motivation + attributes: + label: Motivation + description: Why is this change needed? What problem does it solve? + validations: + required: true + + - type: textarea + id: alternatives + attributes: + label: Alternatives considered + description: What other approaches were considered and why were they rejected? + validations: + required: false + + - type: markdown + attributes: + value: | + --- + ### How to vote + Eligible voters (committers and project leads) cast their vote by posting a comment + containing exactly one of: + - `vote: yes` + - `vote: no` + - `vote: abstain` + + Your last such comment is your final vote. Votes are tallied after the 14-day window closes. diff --git a/.github/PULL_REQUEST_TEMPLATE/decision_record.md b/.github/PULL_REQUEST_TEMPLATE/decision_record.md new file mode 100644 index 0000000..772b0b4 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/decision_record.md @@ -0,0 +1,19 @@ +# Decision Record PR + + + +## Checklist + +- [ ] File is named `DR-NNN-short-title.md` +- [ ] All required metadata fields are filled in (Status, Opened, Closed, Discussion) +- [ ] Discussion link points to the correct GitHub Discussion +- [ ] Vote tally is complete with one row per voter +- [ ] `**Result:**` line is present in the Vote Tally section +- [ ] The linked Discussion has been locked (no further voting) + +## Linked Discussion + + diff --git a/.github/scripts/validate_decision.py b/.github/scripts/validate_decision.py new file mode 100644 index 0000000..1622f97 --- /dev/null +++ b/.github/scripts/validate_decision.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python3 +# *************************************************************************** +# * Copyright (C) 2026 Eclipse ThreadX contributors +# * +# * This program and the accompanying materials are made available under the +# * terms of the MIT License which is available at +# * https://opensource.org/licenses/MIT. +# * +# * AI Disclosure: This file was largely AI-generated by Copilot (Sonnet 4.6). +# * The AI-generated portions may be considered public domain (CC0-1.0) +# * and not subject to the project's licence. The human contributor has +# * reviewed and verified that the code is correct. +# * +# * SPDX-License-Identifier: MIT and CC0-1.0 +# *************************************************************************** +""" +Validates that decision record files conform to the required template. +Usage: python validate_decision.py decisions/DR-001-example.md [...] +Exits non-zero if any file fails validation. +""" + +import re +import sys +from pathlib import Path + +FILENAME_RE = re.compile(r"^DR-\d{3,}-[\w-]+\.md$") +VALID_STATUSES = {"Accepted", "Rejected", "Deferred"} + +REQUIRED_TABLE_FIELDS = ["Status", "Opened", "Closed", "Discussion"] +REQUIRED_SECTIONS = ["## Proposal", "## Vote Tally"] + +VOTE_ROW_RE = re.compile(r"^\|\s*@\w+\s*\|\s*(yes|no|abstain)\s*\|", re.IGNORECASE | re.MULTILINE) +RESULT_RE = re.compile(r"\*\*Result:\*\*", re.IGNORECASE) +STATUS_RE = re.compile(r"\|\s*Status\s*\|\s*(\w+)\s*\|") +DISCUSSION_RE = re.compile(r"\|\s*Discussion\s*\|\s*(https://github\.com/[^\s|]+)\s*\|") +DATE_RE = re.compile(r"\|\s*(Opened|Closed)\s*\|\s*(\d{4}-\d{2}-\d{2})\s*\|") + + +def validate(path: Path) -> list[str]: + errors = [] + + # 1. File name convention + if not FILENAME_RE.match(path.name): + errors.append( + f"Filename '{path.name}' must match DR-NNN-short-title.md " + "(e.g. DR-001-add-ci-pipeline.md)" + ) + + text = path.read_text(encoding="utf-8") + + # 2. Required table fields + for field in REQUIRED_TABLE_FIELDS: + if not re.search(rf"\|\s*{field}\s*\|", text): + errors.append(f"Missing required metadata field: '{field}'") + + # 3. Valid status value + status_match = STATUS_RE.search(text) + if status_match: + status = status_match.group(1) + if status not in VALID_STATUSES: + errors.append( + f"Invalid Status '{status}'. Must be one of: {', '.join(sorted(VALID_STATUSES))}" + ) + # (missing Status field already caught above) + + # 4. Discussion link is a real GitHub URL + disc_match = DISCUSSION_RE.search(text) + if not disc_match: + errors.append( + "Discussion field must contain a full GitHub URL " + "(e.g. https://github.com/eclipse-threadx/discussions/discussions/42)" + ) + + # 5. Opened and Closed dates are present and valid + dates_found = {m.group(1) for m in DATE_RE.finditer(text)} + for field in ("Opened", "Closed"): + if field not in dates_found: + errors.append(f"'{field}' date is missing or not in YYYY-MM-DD format") + + # 6. Required sections + for section in REQUIRED_SECTIONS: + if section not in text: + errors.append(f"Missing required section: '{section}'") + + # 7. Vote tally has at least one data row + if "## Vote Tally" in text: + tally_block = text.split("## Vote Tally", 1)[1].split("##")[0] + if not VOTE_ROW_RE.search(tally_block): + errors.append( + "## Vote Tally must contain at least one vote row " + "in the format '| @username | yes/no/abstain |'" + ) + + # 8. Result line is present + if not RESULT_RE.search(tally_block): + errors.append( + "## Vote Tally must contain a result line starting with '**Result:**'" + ) + + return errors + + +def main(): + if len(sys.argv) < 2: + print("Usage: validate_decision.py [file ...]") + sys.exit(1) + + files = [Path(p) for p in sys.argv[1:]] + all_passed = True + + for path in files: + if not path.exists(): + print(f"ERROR: File not found: {path}") + all_passed = False + continue + + errors = validate(path) + if errors: + all_passed = False + print(f"\n❌ {path}") + for e in errors: + print(f" • {e}") + else: + print(f"✅ {path}") + + if not all_passed: + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/.github/workflows/validate-decisions.yml b/.github/workflows/validate-decisions.yml new file mode 100644 index 0000000..8c437c8 --- /dev/null +++ b/.github/workflows/validate-decisions.yml @@ -0,0 +1,40 @@ +name: Validate Decision Records + +on: + pull_request: + paths: + - "decisions/**.md" + +permissions: + contents: read + pull-requests: write + +jobs: + validate: + name: Validate decision record format + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Find changed decision records + id: changed + run: | + files=$(git diff --name-only origin/${{ github.base_ref }}...HEAD -- 'decisions/*.md' | tr '\n' ' ') + echo "files=$files" >> $GITHUB_OUTPUT + + - name: Validate records + if: steps.changed.outputs.files != '' + run: python .github/scripts/validate_decision.py ${{ steps.changed.outputs.files }} + + - name: Post validation failure comment + if: failure() + uses: actions/github-script@v7 + with: + script: | + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: "❌ **Decision record validation failed.**\n\nPlease check the workflow logs and ensure your `decisions/*.md` file follows the required template. See `VOTING.md` for the template." + }) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..1a47ebf --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,92 @@ +# Contributing to Eclipse ThreadX + +Thanks for your interest in this project. + +## About this repository +This repository is used to host community discussions. It also contains decision records by the project's core team. + +Non-team members cannot propose pull requests on this repository. However, everyone is welcome to participate in discussions and comment on decisions considered by the core team. + +The rest of this document applies to the project as a whole. Code and documentation contributions are welcome on most of our other repositories. + +## Project description + +Eclipse ThreadX provides a vendor-neutral, open source, safety-certified OS for +real-time applications published on under a permissive license. The Eclipse +ThreadX suite encompasses: +* ThreadX - advanced real-time operating system (RTOS) designed specifically for deeply embedded applications +* NetX Duo - advanced, industrial-grade TCP/IP network stack designed specifically for deeply embedded real-time and IoT applications +* FileX - high-performance, FAT-compatible file system that’s fully integrated with ThreadX kernel +* GUIX - provides a complete, embedded graphical user interface (GUI) library +* USBX - high-performance USB host, device, and on-the-go (OTG) embedded stack, that is fully integrated with ThreadX kernel +* LevelX - flash wear leveling for FileX and stand-alone purposes +* GuiX Studio - design environment, facilitating the creation and maintenance of all graphical elements for GUIX +* TraceX - analysis tool that provides a graphical view of real-time system events to better understand the behavior of real-time systems + +Project websites: +* https://threadx.io +* https://projects.eclipse.org/projects/iot.threadx + +## Terms of Use + +This repository is subject to the Terms of Use of the Eclipse Foundation +https://www.eclipse.org/legal/termsofuse.php + +## Developer resources + +Information regarding source code management, builds, coding standards, and more. +https://projects.eclipse.org/projects/iot.threadx/developer + +The project maintains the following source code repositories + +* https://github.com/eclipse-threadx/.github +* https://github.com/eclipse-threadx/cmsis-packs +* https://github.com/eclipse-threadx/filex +* https://github.com/eclipse-threadx/guix +* https://github.com/eclipse-threadx/levelx +* https://github.com/eclipse-threadx/netxduo +* https://github.com/eclipse-threadx/rtos-docs-asciidoc +* https://github.com/eclipse-threadx/rtos-docs-html +* https://github.com/eclipse-threadx/samplex +* https://github.com/eclipse-threadx/threadx +* https://github.com/eclipse-threadx/tracex +* https://github.com/eclipse-threadx/usbx + +## Eclipse Development Process + +This Eclipse Foundation open project is governed by the Eclipse Foundation +Development Process and operates under the terms of the Eclipse IP Policy. + +* https://eclipse.org/projects/dev_process +* https://www.eclipse.org/org/documents/Eclipse_IP_Policy.pdf + +## Eclipse Contributor Agreement + +In order to be able to contribute to Eclipse Foundation projects you must electronically sign the Eclipse Contributor Agreement (ECA). +https://www.eclipse.org/legal/ECA.php + +The ECA provides the Eclipse Foundation with a permanent record that you agree +that each of your contributions will comply with the commitments documented in +the Developer Certificate of Origin (DCO). Having an ECA on file associated with +the email address matching the "Author" field of your contribution's Git commits +fulfills the DCO's requirement that you sign-off on your contributions. + +For more information, please see the Eclipse Committer Handbook: +https://www.eclipse.org/projects/handbook/#resources-commit + +## Contact + +The project owns several mailing lists. + +### Main ThreadX mailing list +News and updates about the ThreadX project and the ThreadX Alliance. +https://accounts.eclipse.org/mailing-list/threadx + +### Developer mailing list +Project team conversations. Feel free to jump in and ask non-technical questions there. +https://accounts.eclipse.org/mailing-list/threadx-dev + +### User mailing list +Ask your technical questions and discuss issues here. +https://accounts.eclipse.org/mailing-list/threadx-users + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..012162c --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Eclipse ThreadX Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 15cd245..5cef476 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,21 @@ -# discussions -Community discussion forum for Q&A, feedback, and announcements. Decisions by the project team are also documented here. +# Discussions + +Community discussion forum for Q&A, feedback, and announcements. Formal decisions by the project team are documented here as immutable decision records. + +**Everyone is welcome to participate in discussions and comment on proposals.** Only elected [committers](https://projects.eclipse.org/projects/iot.threadx/who) may vote on formal decisions. See [VOTING.md](VOTING.md) for the full rules. + +## Becoming a committer + +Interested in having a vote? Start by contributing! Submit pull requests to any Eclipse ThreadX repository. Once you have built a public record of merged contributions over time, you become eligible to be nominated and elected as a committer by the existing committer team. See the [Eclipse Foundation Project Handbook — Committer Elections](https://www.eclipse.org/projects/handbook/#elections-committer) for the full process. + +## Current committers + +The current list of committers is published on the [Eclipse ThreadX project page](https://projects.eclipse.org/projects/iot.threadx/who). + +## Key documents + +| Document | Purpose | +|---|---| +| [VOTING.md](VOTING.md) | Voting rules and decision-making process | +| [decisions/TEMPLATE.md](decisions/TEMPLATE.md) | Template for authoring a decision record | +| [SSH-SIGNING.md](SSH-SIGNING.md) | How to set up SSH commit signing (required for merging decision records) | diff --git a/SSH-SIGNING.md b/SSH-SIGNING.md new file mode 100644 index 0000000..550d635 --- /dev/null +++ b/SSH-SIGNING.md @@ -0,0 +1,197 @@ +# SSH Commit Signing Setup + +All commits merged into the `decisions/` directory of this repository must be **signed**. This document explains how to generate an SSH key, register it with GitHub, and configure Git to sign commits automatically. + +> **Git version requirement:** SSH commit signing requires Git **2.34** or later. The steps below install a current version on each platform. + +--- + +## 1. Install prerequisites + +### Windows + +Install Git for Windows using [WinGet](https://learn.microsoft.com/windows/package-manager/winget/). Open **PowerShell** or **Command Prompt** and run: + +```powershell +winget install --id Git.Git --exact --source winget +``` + +Git for Windows bundles OpenSSH, so no separate SSH installation is needed. After installation, open a new **Git Bash** terminal for the remaining steps. + +--- + +### Ubuntu + +SSH signing requires Git 2.34+. Ubuntu 22.04 (Jammy) and later ship a new enough version. Ubuntu 20.04 (Focal) requires the upstream Git PPA. + +**Ubuntu 22.04 and later:** + +```bash +sudo apt update +sudo apt install -y git openssh-client +``` + +**Ubuntu 20.04:** + +```bash +sudo add-apt-repository ppa:git-core/ppa +sudo apt update +sudo apt install -y git openssh-client +``` + +--- + +### Fedora + +```bash +sudo dnf install -y git openssh +``` + +Fedora's default repositories carry a recent enough version of Git. + +--- + +### macOS + +Install [Homebrew](https://brew.sh) if you haven't already, then install Git and OpenSSH: + +```bash +brew install git openssh +``` + +> macOS ships with Apple's own Git and OpenSSH, but they can lag behind upstream versions. Homebrew ensures you have current releases. + +After installation, make sure the Homebrew binaries take precedence: + +```bash +echo 'export PATH="$(brew --prefix)/bin:$PATH"' >> ~/.zprofile +source ~/.zprofile +``` + +--- + +## 2. Verify your Git version + +Confirm you have Git 2.34 or later: + +```bash +git --version +# Example output: git version 2.47.0 +``` + +--- + +## 3. Generate an SSH key + +If you don't already have an Ed25519 key, generate one now. Use the email address associated with your GitHub account. + +```bash +ssh-keygen -t ed25519 -C "your@email.com" +``` + +When prompted: +- **File location:** press Enter to accept the default (`~/.ssh/id_ed25519`). +- **Passphrase:** enter a strong passphrase (recommended). + +This creates two files: +- `~/.ssh/id_ed25519` — your private key (never share this) +- `~/.ssh/id_ed25519.pub` — your public key + +--- + +## 4. Add the key to GitHub + +You must register your public key with GitHub **twice**: once as an authentication key and once as a signing key. + +1. Copy your public key to the clipboard: + + **Windows (Git Bash) / Linux:** + ```bash + cat ~/.ssh/id_ed25519.pub + ``` + **macOS:** + ```bash + cat ~/.ssh/id_ed25519.pub | pbcopy + ``` + +2. Go to **GitHub → Settings → SSH and GPG keys → New SSH key**. + +3. Add it as an **Authentication Key** (for push access). + +4. Return to **SSH and GPG keys → New SSH key** and add the **same public key** again, this time choosing **Signing Key**. + +--- + +## 5. Configure Git + +Run the following commands. They apply globally to your user account. + +```bash +# Tell Git to use SSH for signing +git config --global gpg.format ssh + +# Point to your public key +git config --global user.signingkey ~/.ssh/id_ed25519.pub + +# Sign every commit automatically +git config --global commit.gpgsign true +``` + +> **Windows note:** Git Bash understands `~` as your home directory. You can also use the full Windows path, e.g. `C:/Users/YourName/.ssh/id_ed25519.pub` (forward slashes required). + +--- + +## 6. Set up the allowed signers file + +Git uses an *allowed signers* file to verify signatures locally (e.g. when you run `git log --show-signature`). + +1. Create the file: + + ```bash + touch ~/.ssh/allowed_signers + ``` + +2. Add your own key to it. The format is `email namespaces="git" `: + + ```bash + echo "$(git config user.email) namespaces=\"git\" $(cat ~/.ssh/id_ed25519.pub)" >> ~/.ssh/allowed_signers + ``` + +3. Tell Git where the file is: + + ```bash + git config --global gpg.ssh.allowedSignersFile ~/.ssh/allowed_signers + ``` + +--- + +## 7. Verify the setup + +Make a test commit and confirm it is signed: + +```bash +cd /tmp +git init test-signing && cd test-signing +git commit --allow-empty -m "test: verify SSH signing" +git log --show-signature -1 +``` + +A successful signature looks like: + +``` +Good "git" signature for your@email.com with ED25519 key SHA256:... +``` + +GitHub will also display a **Verified** badge on signed commits in the web UI once your signing key is registered. + +--- + +## Troubleshooting + +| Symptom | Likely cause | Fix | +|---|---|---| +| `error: gpg.format=ssh requires --global user.signingkey` | Signing key not configured | Re-run step 5 | +| `error: Load key "…": invalid format` | Path to public key is wrong or contains spaces | Use the full path without spaces | +| `No principal matched` when verifying | Key not in allowed_signers | Re-run step 6 | +| GitHub shows **Unverified** | Key not added as a Signing Key on GitHub | Re-do step 4, choosing **Signing Key** | +| Old Git version on Ubuntu 20.04 | System Git is < 2.34 | Add the `git-core` PPA (see step 1) | diff --git a/VOTING.md b/VOTING.md new file mode 100644 index 0000000..00802a2 --- /dev/null +++ b/VOTING.md @@ -0,0 +1,116 @@ +# Eclipse ThreadX — Decision-Making and Voting Process + +This document defines the process for making major decisions in the Eclipse ThreadX project. + +## 1. Scope + +This process applies to significant decisions affecting the project direction, governance, architecture, or community norms. Day-to-day maintenance decisions do not require a formal vote. + +Certain decisions are outside the scope of this process and require a formal review by the Eclipse Management Organization (EMO). These include — but are not limited to — changes to project scope, project restructuring, renaming, and project termination. Such decisions must follow the [Eclipse Foundation Development Process](#appendix-governing-documents) rather than this document. + +## 2. Eligible Participants + +| Role | Can open proposals | Can vote | Can observe and comment | +|---|---|---|---| +| Project leads (`@eclipse-threadx/iot-threadx-project-leads`) | ✅ | ✅ | ✅ | +| Committers (`@eclipse-threadx/iot-threadx-committers`) | ✅ | ✅ | ✅ | +| Public | ❌ | ❌ | ✅ | + +**Vendor concentration limit:** To preserve vendor neutrality as required by the Eclipse Foundation Development Process, no single legal entity (company or organisation) may cast more than 50% of the binding (`yes` or `no`) votes in any one proposal. If this limit would be breached, the excess votes from that entity are excluded, starting from the most recently cast. A note explaining the exclusion must be included in the tally summary. + +## 3. Opening a Proposal + +Before opening a Discussion in the **Proposals** category, proposers must do their due diligence: + +- If the idea is still being shaped or requires community input to be confirmed, post it first in the **Feedback Needed** category to gather feedback and firm up the details. +- A proposal must be complete and self-contained before it is moved to **Proposals**. Incomplete or speculative proposals may be shut down by a project lead without a vote. + +Once the proposal is ready: + +1. Open a new Discussion in the **Proposals** category using the provided form. The opening post must include: + - A clear statement of what is being proposed. + - The motivation and problem being solved. + - Alternatives considered. +2. A project lead reviews the proposal for completeness. If it is vote-ready, the lead opens the voting period by posting a comment in the following format: + + `vote open: closes YYYY-MM-DD at 23:59 UTC` + +3. The 14-day voting window starts on the date that comment is posted. If no such comment has been posted, voting has not yet begun. +4. **The lead must also send an announcement to the [`threadx-dev` mailing list](https://accounts.eclipse.org/mailing-list/threadx-dev)** with a link to the Discussion and the closing date. +5. Project leads may shut down a proposal at any time before voting opens if it does not meet the completeness criteria, posting a reason in the Discussion. + +## 4. Deliberation + +- Anyone may comment during the deliberation period. +- The proposer may amend the proposal in response to feedback, provided the amendment is clearly marked. The 14-day window must be restarted: a project lead posts a new `vote open:` comment with the updated closing date. + +## 5. Casting a Vote + +- Eligible voters cast their vote by posting a comment containing exactly one of: + - `vote: yes` + - `vote: no` + - `vote: abstain` +- One vote per person. If a voter posts multiple vote comments, their **last** such comment counts. +- Votes must be posted before the voting window closes at **23:59 UTC** on the closing date stated in the `vote open:` comment. + +## 6. Closing the Vote + +After the closing date and time stated in the `vote open:` comment (23:59 UTC), a project lead (or a committer delegated by a lead) closes the voting by: + +1. Tallying all `vote: yes`, `vote: no`, and `vote: abstain` comments, keeping only the last vote per person. +2. Verifying each voter's eligibility against current team membership. +3. Applying the vendor concentration limit (see §2) if necessary. +4. Posting a summary comment in the Discussion with the full tally and outcome. +5. Sending the outcome to the [`threadx-dev` mailing list](https://accounts.eclipse.org/mailing-list/threadx-dev) with a link to the Discussion and the Decision Record PR once merged. +6. Locking the Discussion to prevent further comments. + +## 7. Decision Rules + +- **Quorum:** At least **3 eligible voters** must have cast a `yes` or `no` vote for the result to be binding. If quorum is not reached, the proposal is deferred and may be reopened. +- **Simple majority:** A proposal passes if the number of `yes` votes exceeds the number of `no` votes (abstentions are excluded from this calculation). +- **Tie:** Project leads confer and cast a collective deciding vote, which is recorded in the summary comment. + +## 8. Recording the Decision + +After voting closes, the lead (or delegate) who tallied the vote opens a Pull Request adding a Decision Record to the `decisions/` directory: + +1. File name: `DR-NNN-short-title.md` (NNN is a zero-padded sequential number). +2. Use the template in [`decisions/TEMPLATE.md`](decisions/TEMPLATE.md). +3. The PR must pass the automated validation check (`Validate decision record format`). +4. A project lead reviews and merges the PR using a **signed, squash commit**. +5. The merge commit SHA is added to the Decision Record's `Commit` field (may be done as a follow-up commit or noted in the PR). + +## 9. Immutability + +Decision Records in `decisions/` are append-only: + +- Branch protection requires a signed commit and a project-lead review before anything can be merged. +- No force-pushes are permitted. +- Git's content-addressed history means any retroactive edit changes the commit SHA — detectable by anyone with a clone. +- The linked Discussion is locked after the vote closes and serves as a secondary audit trail. + +## 10. Amending a Decision + +A prior decision may only be amended by opening a new proposal that explicitly references the original Decision Record. The amendment follows the same full process. + +## 11. Grievance and Escalation + +If a participant believes this process has been misapplied or that a decision violates Eclipse Foundation policy, they may escalate the matter through the following chain: + +1. Raise the concern in the relevant Discussion before it is locked, or by contacting the project leads directly. +2. If unresolved, escalate to the Eclipse IoT Project Management Committee (PMC). +3. If still unresolved, file a grievance with the Eclipse Management Organization (EMO) per the [Eclipse Foundation Development Process §6.5](https://www.eclipse.org/projects/dev_process/#6_5_Grievance_Handling). + +## Appendix: Governing Documents + +The following Eclipse Foundation documents take precedence over this process in the event of any conflict. + +| Document | URL | +|---|---| +| Eclipse Foundation Development Process (EDP) | https://www.eclipse.org/projects/dev_process/ | +| Eclipse Foundation Project Handbook | https://www.eclipse.org/projects/handbook/ | +| Eclipse Foundation IP Policy | https://www.eclipse.org/org/documents/Eclipse_IP_Policy.pdf | +| Eclipse Foundation Bylaws | https://www.eclipse.org/org/documents/eclipse_foundation-bylaws.pdf | +| Eclipse Foundation Terms of Use | https://www.eclipse.org/legal/termsofuse.php | +| Eclipse Contributor Agreement (ECA) | https://www.eclipse.org/legal/ECA.php | +| Eclipse Foundation Community Code of Conduct | https://www.eclipse.org/org/documents/Community_Code_of_Conduct.php | diff --git a/decisions/README.md b/decisions/README.md new file mode 100644 index 0000000..a91860b --- /dev/null +++ b/decisions/README.md @@ -0,0 +1,6 @@ +# Decision Records + +This directory contains the official record of all decisions made under the +[voting process](../VOTING.md). + +Each file follows the naming convention `DR-NNN-short-title.md`. diff --git a/decisions/TEMPLATE.md b/decisions/TEMPLATE.md new file mode 100644 index 0000000..a41d537 --- /dev/null +++ b/decisions/TEMPLATE.md @@ -0,0 +1,25 @@ +# DR-NNN: + +| Field | Value | +|---|---| +| Status | Accepted / Rejected / Deferred | +| Opened | YYYY-MM-DD | +| Closed | YYYY-MM-DD | +| Discussion | https://github.com/eclipse-threadx/discussions/discussions/NNN | +| Commit | <!-- filled in after merge --> | + +## Proposal + +<!-- Copy the proposal text from the Discussion here. --> + +## Vote Tally + +| Voter | Vote | +|---|---| +| @username | yes | + +**Result:** X yes, Y no, Z abstain — **Accepted / Rejected** by simple majority. + +## Notes + +<!-- Tie-breaking rationale, quorum notes, or other relevant context. --> From 39f0e2de4c8b558334abf5c8e935a97af8f0bb66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= <frederic.desbiens@eclipse-foundation.org> Date: Fri, 8 May 2026 12:06:59 -0400 Subject: [PATCH 2/3] Allowed committers to approve decision record PRs With a single project lead, self-approval is impossible. Any committer who participated in the vote can now approve a decision record PR to confirm the record faithfully reflects the outcome. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/CODEOWNERS | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5ddf28f..a5dbf00 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,4 +1,6 @@ @eclipse-threadx/admins -# Decision records require a project lead to review and approve -decisions/ @eclipse-threadx/iot-threadx-project-leads +# Decision records can be approved by any project lead or committer. +# A committer who participated in the vote can confirm the record +# faithfully reflects the outcome. +decisions/ @eclipse-threadx/iot-threadx-project-leads @eclipse-threadx/iot-threadx-committers From f54380d99c17a4b17f846fad5f8fcb294c6e2c27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= <frederic.desbiens@eclipse-foundation.org> Date: Fri, 8 May 2026 12:09:52 -0400 Subject: [PATCH 3/3] Allowed leads and committers to approve all PRs Changed the catch-all CODEOWNERS entry from admins-only to project leads and committers, consistent with the decisions/ rule. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a5dbf00..f3e34d3 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,4 +1,4 @@ -@eclipse-threadx/admins +@eclipse-threadx/iot-threadx-project-leads @eclipse-threadx/iot-threadx-committers # Decision records can be approved by any project lead or committer. # A committer who participated in the vote can confirm the record