Skip to content
Closed
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
3 changes: 3 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# SPDX-FileCopyrightText: 2026 Polymath Robotics, Inc.
# SPDX-License-Identifier: Apache-2.0
* @iliabaranov @rajasimman-madhivanan @davidt315
130 changes: 130 additions & 0 deletions .github/ISSUE_TEMPLATE/change-request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
---
name: Change Request
description: Request an assessed change to Protective Stop
title: '[CR] '
labels: [change-request, status:proposed]
body:
- type: textarea
id: reason
attributes:
label: Reason for the change
description: Why this change is needed. A defect, a new requirement, a dependency update, a corrective action. Link to the source if there is one.
placeholder: State the reason and source.
validations:
required: true
- type: textarea
id: hazards
attributes:
label: Hazards that may be affected
description: Which identified hazards this change could bear on. Reference the HARA entries. "None identified, because…" is a valid answer; blank is not.
placeholder: None identified, because…
validations:
required: true
- type: textarea
id: description
attributes:
label: Description of the proposed change
description: What specifically is proposed, covering both hardware and software. Enough detail that someone other than the requester can assess it.
validations:
required: true
- type: textarea
id: baseline
attributes:
label: Baseline affected
description: Firmware, host and hardware versions.
validations:
required: true
- type: input
id: requester
attributes:
label: Requester
description: Name and date.
validations:
required: false
- type: textarea
id: impact-analysis
attributes:
label: Impact Analysis
description: Link to or paste the completed Impact Analysis. Required before authorization.
validations:
required: false
- type: dropdown
id: class
attributes:
label: Proposed class
description: The Impact Analyst proposes and the Authorizer confirms the class.
options:
- A
- B
- C
default: 2
validations:
required: true
- type: textarea
id: authorization
attributes:
label: Authorization
description: Authorizer, decision, date and basis. Class C requires two distinct Authorizers.
validations:
required: false
- type: textarea
id: implementation
attributes:
label: Implementation
description: Implementer; competency basis; pull requests covering software, hardware and tests; documentation updated; and upstream pstop_c change required - Yes / No, with link.
validations:
required: false
- type: textarea
id: gate-0
attributes:
label: Gate 0 - Build Acceptance Test
description: Version under test, CI run, date and result.
validations:
required: false
- type: textarea
id: gate-1
attributes:
label: Gate 1 - Merge qualification
description: Scope per the change class and Impact Analysis. Record test, version under test, Run by, date and result. For Class C record Forward - affected safety requirements to verification performed; Backward - verification performed to requirements
covered.
validations:
required: false
- type: textarea
id: review
attributes:
label: Review
description: Reviewer, who is not the Implementer; pull request review link; date; and outcome.
validations:
required: false
- type: textarea
id: deviations
attributes:
label: Deviations
description: Any deviation from this procedure, with justification. Includes the case where the Authorizer and Implementer are the same person.
validations:
required: false
- type: input
id: release
attributes:
label: Release Record
description: Release is handled separately in the Release Record. Record only the link here once this change ships.
validations:
required: false
- type: dropdown
id: status
attributes:
label: Status
description: Current Change Request lifecycle status.
options:
- Proposed
- Under Analysis
- Authorized
- Rejected
- In Implementation
- In Verification
- Merged
- Released
- Closed
default: 0
validations:
required: false
6 changes: 6 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
blank_issues_enabled: true
contact_links:
- name: Private safety and security reports
url: https://github.com/polymathrobotics/protective-stop/security/policy
about: Read SECURITY.md and report suspected safety or security defects privately.
13 changes: 13 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## Change control

- Change Request: Closes #NN or Refs #NN
- Class: A / B / C
- Impact Analysis: link

## Completion

- [ ] Authorization preceded implementation
- [ ] Named tests and affected interfaces were exercised
- [ ] Documentation identified by the Impact Analysis is updated
- [ ] Review is by someone other than the implementer
- [ ] Gate evidence is attached to the Change Request
36 changes: 36 additions & 0 deletions .github/workflows/change-control.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
name: Change control

on:
pull_request:
types: [opened, synchronize, reopened, labeled, unlabeled, edited]
pull_request_review:
types: [submitted, dismissed]

concurrency:
group: change-control-${{ github.event.pull_request.number }}
cancel-in-progress: true

permissions:
contents: read
issues: write
pull-requests: write
checks: read
actions: read

jobs:
change-control:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Run tests
run: python3 tools/change_control/self_test.py
- name: Check modification records
env:
GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ github.event.pull_request.number }}
CAN_COMMENT: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
run: |-
args=()
[ "$CAN_COMMENT" = 'true' ] || args+=(--no-comment)
python3 -m tools.change_control --repository '${{ github.repository }}' --pr "$PR_NUMBER" "${args[@]}"
35 changes: 35 additions & 0 deletions .github/workflows/coverage-delta.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
name: Coverage delta

on:
pull_request:

concurrency:
group: coverage-delta-${{ github.event.pull_request.number }}
cancel-in-progress: true

permissions:
contents: read
issues: write
pull-requests: write

jobs:
coverage-delta:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Compare safety-linter citations
env:
GH_TOKEN: ${{ github.token }}
CAN_COMMENT: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
run: |-
args=()
[ "$CAN_COMMENT" = 'true' ] || args+=(--no-comment)
python3 -m tools.change_control.coverage_delta \
--base '${{ github.event.pull_request.base.sha }}' \
--head '${{ github.event.pull_request.head.sha }}' \
--repository '${{ github.repository }}' \
--pr '${{ github.event.pull_request.number }}' \
"${args[@]}"
25 changes: 25 additions & 0 deletions .github/workflows/safety-lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
name: Safety traceability lint

on:
push:
branches: [main]
pull_request:

permissions:
contents: read

jobs:
safety_lint:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v7
with:
persist-credentials: false

- name: Safety linter self-tests
run: python3 tools/safety_lint/self_test.py

- name: Safety traceability check
run: python3 -m tools.safety_lint --check
58 changes: 58 additions & 0 deletions .github/workflows/wire-break.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
name: Wire break

on:
pull_request:

permissions:
contents: read
issues: write

jobs:
wire-break:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Detect watched changes and apply wire-break label
env:
GH_TOKEN: ${{ github.token }}
BASE_SHA: ${{ github.event.pull_request.base.sha }}
PR_NUMBER: ${{ github.event.pull_request.number }}
CAN_LABEL: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
run: |
set -eu
signature_changed=false
expectation_preexisted=false
if git cat-file -e "$BASE_SHA:tools/change_control/wire_format.sha256" 2>/dev/null; then
expectation_preexisted=true
fi
watched_paths='pstop_c/pstop/include/pstop/config.h
pstop_c/pstop/include/pstop/constants.h
pstop_c/pstop/include/pstop/protocol.h
pstop_c/pstop/include/pstop/protocol_data.h
pstop_c/pstop/include/pstop/pstop_msg.h
pstop_c/pstop/include/pstop/checksum.h
pstop_c/pstop/include/pstop/device_id.h
pstop_c/pstop/include/pstop/endian.h
pstop_c/pstop/src/pstop/pstop_msg.c
pstop_c/pstop/src/pstop/checksum.c
pstop_c/pstop/src/pstop/endian.c'
if { [ "$expectation_preexisted" = true ] && \
git diff --name-only "$BASE_SHA"...HEAD | grep -Eq '^tools/change_control/wire_format\.sha256$'; } || \
{ [ "$expectation_preexisted" = false ] && \
git diff --name-only "$BASE_SHA"...HEAD | grep -Fqx -f <(printf '%s\n' "$watched_paths"); }; then
signature_changed=true
elif ! python3 -m tools.change_control.wire_format check --root . >/dev/null; then
signature_changed=true
fi
if [ "$signature_changed" = true ] && [ "$CAN_LABEL" = true ]; then
gh api --method POST 'repos/${{ github.repository }}/issues/'"$PR_NUMBER"'/labels' -f 'labels[]=wire-break' >/dev/null
fi
labels=$(gh api 'repos/${{ github.repository }}/issues/'"$PR_NUMBER" --jq '[.labels[].name] | join(",")')
printf 'PSTOP_PR_LABELS=%s\n' "$labels" >> "$GITHUB_ENV"
- name: Enforce wire-format declaration
env:
PSTOP_BASE_SHA: ${{ github.event.pull_request.base.sha }}
run: scripts/check_wire_format.sh
16 changes: 16 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,13 @@ Note `pstop_c/` is intentionally excluded from the C/C++ hooks.

## Pull request expectations

### Maintainer-owned change records

You do not need to understand or write the project's safety Change Request or
Impact Analysis before contributing. If a pull request arrives without one, a
maintainer follows [`docs/process/EXTERNAL_CONTRIBUTIONS.md`](docs/process/EXTERNAL_CONTRIBUTIONS.md),
opens and assesses the record, and then starts review.

- **CI green.** Firmware build, host build, `pstop_c` build + tests, and
pre-commit must all pass.
- **Pre-commit clean.** Run it locally before pushing; do not disable
Expand All @@ -100,6 +107,15 @@ Note `pstop_c/` is intentionally excluded from the C/C++ hooks.
- **No changes to `pstop_c/`** (contribute upstream instead).
- **Clear commits.** Explain the design intent, not just the diff.
Reference the relevant `docs/` design note where one applies.
- **Keep safety traceability lint clean.** The linter checks requirement and
function mappings, statuses, evidence citations, and ownership of numeric
coverage claims. Generated coverage becomes stale whenever document
citations or statuses change; refresh it with
`python3 -m tools.safety_lint --write`. This command recounts citations and
statuses from the documents; it does not execute tests or establish that
cited tests pass. Write mode refuses to modify the document while
unbaselined errors exist. Automatic pre-commit rewriting is deliberately not
configured because coverage drops require human review.

Contributions are licensed according to where they land: software and firmware
under Apache-2.0, hardware design files under CERN-OHL-P-2.0, and documentation
Expand Down
2 changes: 0 additions & 2 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ Please report suspected vulnerabilities **privately**. Do not open a
public issue, pull request, or discussion for a security problem.

- Email: **security@polymathrobotics.com**
_(placeholder — please confirm the correct security contact before this
policy is published)_

Include, where possible:

Expand Down
Loading
Loading