nnrp-py 1.0.0rc2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. nnrp_py-1.0.0rc2/.editorconfig +14 -0
  2. nnrp_py-1.0.0rc2/.github/PULL_REQUEST_TEMPLATE/bugfix.md +38 -0
  3. nnrp_py-1.0.0rc2/.github/PULL_REQUEST_TEMPLATE/docs.md +28 -0
  4. nnrp_py-1.0.0rc2/.github/PULL_REQUEST_TEMPLATE/feature.md +35 -0
  5. nnrp_py-1.0.0rc2/.github/PULL_REQUEST_TEMPLATE/maintenance.md +36 -0
  6. nnrp_py-1.0.0rc2/.github/PULL_REQUEST_TEMPLATE/release.md +44 -0
  7. nnrp_py-1.0.0rc2/.github/pull_request_template.md +41 -0
  8. nnrp_py-1.0.0rc2/.github/workflows/ci.yml +104 -0
  9. nnrp_py-1.0.0rc2/.github/workflows/release.yml +139 -0
  10. nnrp_py-1.0.0rc2/.gitignore +30 -0
  11. nnrp_py-1.0.0rc2/CONTRIBUTING.md +108 -0
  12. nnrp_py-1.0.0rc2/LICENSE +160 -0
  13. nnrp_py-1.0.0rc2/PKG-INFO +473 -0
  14. nnrp_py-1.0.0rc2/README.md +284 -0
  15. nnrp_py-1.0.0rc2/doc/todo/v1-preview1/implementation-todo.md +170 -0
  16. nnrp_py-1.0.0rc2/doc/todo/v1-preview2/implementation-todo.md +232 -0
  17. nnrp_py-1.0.0rc2/doc/todo/v1-preview3/01-foundation-and-contract.md +21 -0
  18. nnrp_py-1.0.0rc2/doc/todo/v1-preview3/02-connection-session-flow-control.md +20 -0
  19. nnrp_py-1.0.0rc2/doc/todo/v1-preview3/02a-connection-session-lifecycle.md +7 -0
  20. nnrp_py-1.0.0rc2/doc/todo/v1-preview3/02b-scheduling-credits-and-diagnostics.md +6 -0
  21. nnrp_py-1.0.0rc2/doc/todo/v1-preview3/02c-control-events-and-recovery.md +6 -0
  22. nnrp_py-1.0.0rc2/doc/todo/v1-preview3/03-cache-schema-profile-registry.md +19 -0
  23. nnrp_py-1.0.0rc2/doc/todo/v1-preview3/04-implementation-surface.md +20 -0
  24. nnrp_py-1.0.0rc2/doc/todo/v1-preview3/04a-rust-binding-adoption.md +5 -0
  25. nnrp_py-1.0.0rc2/doc/todo/v1-preview3/04b-python-host-api-surface.md +6 -0
  26. nnrp_py-1.0.0rc2/doc/todo/v1-preview3/04c-async-runtime-integration.md +5 -0
  27. nnrp_py-1.0.0rc2/doc/todo/v1-preview3/05-validation-and-docs.md +17 -0
  28. nnrp_py-1.0.0rc2/doc/todo/v1-preview3/implementation-todo.md +37 -0
  29. nnrp_py-1.0.0rc2/pyproject.toml +66 -0
  30. nnrp_py-1.0.0rc2/scripts/check_incremental_coverage.py +170 -0
  31. nnrp_py-1.0.0rc2/scripts/resolve_version.py +110 -0
  32. nnrp_py-1.0.0rc2/src/nnrp/__init__.py +152 -0
  33. nnrp_py-1.0.0rc2/src/nnrp/adapters/__init__.py +57 -0
  34. nnrp_py-1.0.0rc2/src/nnrp/adapters/quic.py +424 -0
  35. nnrp_py-1.0.0rc2/src/nnrp/adapters/tcp.py +412 -0
  36. nnrp_py-1.0.0rc2/src/nnrp/client/__init__.py +63 -0
  37. nnrp_py-1.0.0rc2/src/nnrp/client/profile.py +71 -0
  38. nnrp_py-1.0.0rc2/src/nnrp/client/transport.py +1654 -0
  39. nnrp_py-1.0.0rc2/src/nnrp/core/__init__.py +403 -0
  40. nnrp_py-1.0.0rc2/src/nnrp/core/enums.py +63 -0
  41. nnrp_py-1.0.0rc2/src/nnrp/core/header.py +97 -0
  42. nnrp_py-1.0.0rc2/src/nnrp/core/messages/__init__.py +238 -0
  43. nnrp_py-1.0.0rc2/src/nnrp/core/messages/control.py +1479 -0
  44. nnrp_py-1.0.0rc2/src/nnrp/core/messages/data.py +779 -0
  45. nnrp_py-1.0.0rc2/src/nnrp/core/packet.py +2663 -0
  46. nnrp_py-1.0.0rc2/src/nnrp/enums.py +11 -0
  47. nnrp_py-1.0.0rc2/src/nnrp/header.py +5 -0
  48. nnrp_py-1.0.0rc2/src/nnrp/server/__init__.py +17 -0
  49. nnrp_py-1.0.0rc2/src/nnrp/server/profile.py +11 -0
  50. nnrp_py-1.0.0rc2/src/nnrp/server/transport.py +509 -0
  51. nnrp_py-1.0.0rc2/src/nnrp/tools/__init__.py +107 -0
  52. nnrp_py-1.0.0rc2/src/nnrp/tools/golden_vectors.py +437 -0
  53. nnrp_py-1.0.0rc2/src/nnrp/tools/ordered_buffer.py +178 -0
  54. nnrp_py-1.0.0rc2/src/nnrp/tools/replay.py +1146 -0
  55. nnrp_py-1.0.0rc2/src/nnrp/tools/smoke.py +1056 -0
  56. nnrp_py-1.0.0rc2/tests/test_check_incremental_coverage.py +273 -0
  57. nnrp_py-1.0.0rc2/tests/test_control_messages.py +819 -0
  58. nnrp_py-1.0.0rc2/tests/test_data_messages.py +388 -0
  59. nnrp_py-1.0.0rc2/tests/test_golden_vectors.py +376 -0
  60. nnrp_py-1.0.0rc2/tests/test_header.py +148 -0
  61. nnrp_py-1.0.0rc2/tests/test_ordered_buffer.py +163 -0
  62. nnrp_py-1.0.0rc2/tests/test_packet.py +664 -0
  63. nnrp_py-1.0.0rc2/tests/test_profiles_and_exports.py +591 -0
  64. nnrp_py-1.0.0rc2/tests/test_quic_adapter.py +608 -0
  65. nnrp_py-1.0.0rc2/tests/test_release_version.py +183 -0
  66. nnrp_py-1.0.0rc2/tests/test_replay_tools.py +518 -0
  67. nnrp_py-1.0.0rc2/tests/test_server_transport.py +225 -0
  68. nnrp_py-1.0.0rc2/tests/test_smoke_tools.py +2302 -0
  69. nnrp_py-1.0.0rc2/tests/test_tcp_adapter.py +331 -0
  70. nnrp_py-1.0.0rc2/uv.lock +556 -0
@@ -0,0 +1,14 @@
1
+ root = true
2
+
3
+ [*.py]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ insert_final_newline = true
7
+ indent_style = space
8
+ indent_size = 4
9
+
10
+ [*.md]
11
+ charset = utf-8
12
+ end_of_line = lf
13
+ insert_final_newline = true
14
+ trim_trailing_whitespace = false
@@ -0,0 +1,38 @@
1
+ ## Bug
2
+
3
+ - What was broken?
4
+ - How could the issue be reproduced?
5
+
6
+ ## Root Cause
7
+
8
+ - What actually caused the issue?
9
+
10
+ ## Fix
11
+
12
+ - What changed to fix it?
13
+ - What regression risk remains?
14
+
15
+ ## Validation
16
+
17
+ - [ ] `ruff check .`
18
+ - [ ] `pytest -q`
19
+ - [ ] Regression test added or existing failure reproduced
20
+
21
+ Commands or workflow runs used:
22
+
23
+ ```text
24
+
25
+ ```
26
+
27
+ ## Release Impact
28
+
29
+ - [ ] No package output change
30
+ - [ ] Wheel or sdist contents changed
31
+ - [ ] Release workflow behavior changed
32
+
33
+ ## Checklist
34
+
35
+ - [ ] Branch name matches repository conventions
36
+ - [ ] Commit messages follow Conventional Commits
37
+ - [ ] PR is squashed to one commit unless this is necessary `release/<version>` branch work
38
+ - [ ] User-facing behavior changes are documented
@@ -0,0 +1,28 @@
1
+ ## Summary
2
+
3
+ - What documentation changed?
4
+ - Who is the primary audience?
5
+
6
+ ## Scope
7
+
8
+ - Files or sections updated:
9
+ - Any intentionally deferred follow-up:
10
+
11
+ ## Validation
12
+
13
+ - [ ] Links and paths were checked
14
+ - [ ] Examples or commands were updated if needed
15
+ - [ ] Documentation stays consistent with current package and workflow behavior
16
+
17
+ Notes:
18
+
19
+ ```text
20
+
21
+ ```
22
+
23
+ ## Checklist
24
+
25
+ - [ ] Branch name matches repository conventions
26
+ - [ ] Commit messages follow Conventional Commits
27
+ - [ ] PR is squashed to one commit unless this is necessary `release/<version>` branch work
28
+ - [ ] No hidden product or workflow behavior changes were introduced
@@ -0,0 +1,35 @@
1
+ ## Summary
2
+
3
+ - What capability does this PR add?
4
+ - Why is it needed now?
5
+
6
+ ## Implementation
7
+
8
+ - Main modules or flows changed:
9
+ - Any protocol, runtime, or packaging assumptions introduced:
10
+ - Follow-up work, if any:
11
+
12
+ ## Validation
13
+
14
+ - [ ] `ruff check .`
15
+ - [ ] `pytest -q`
16
+ - [ ] Build or packaging checked if distribution output changed
17
+
18
+ Commands or workflow runs used:
19
+
20
+ ```text
21
+
22
+ ```
23
+
24
+ ## Release Impact
25
+
26
+ - [ ] No package output change
27
+ - [ ] Wheel or sdist contents changed
28
+ - [ ] Release workflow behavior changed
29
+
30
+ ## Checklist
31
+
32
+ - [ ] Branch name matches repository conventions
33
+ - [ ] Commit messages follow Conventional Commits
34
+ - [ ] PR is squashed to one commit unless this is necessary `release/<version>` branch work
35
+ - [ ] Documentation was updated when behavior changed
@@ -0,0 +1,36 @@
1
+ ## Summary
2
+
3
+ - What maintenance change is included?
4
+ - Why is it being made now?
5
+
6
+ ## Change Type
7
+
8
+ - [ ] CI or workflow change
9
+ - [ ] Tooling or dependency maintenance
10
+ - [ ] Packaging metadata update
11
+ - [ ] Refactor with no intended behavior change
12
+
13
+ ## Validation
14
+
15
+ - [ ] `ruff check .`
16
+ - [ ] `pytest -q`
17
+ - [ ] Targeted validation for the affected tooling or workflow path
18
+
19
+ Commands or workflow runs used:
20
+
21
+ ```text
22
+
23
+ ```
24
+
25
+ ## Release Impact
26
+
27
+ - [ ] No package output change
28
+ - [ ] Wheel or sdist contents changed
29
+ - [ ] Release workflow behavior changed
30
+
31
+ ## Checklist
32
+
33
+ - [ ] Branch name matches repository conventions
34
+ - [ ] Commit messages follow Conventional Commits
35
+ - [ ] PR is squashed to one commit unless this is necessary `release/<version>` branch work
36
+ - [ ] Follow-up operational work is documented if needed
@@ -0,0 +1,44 @@
1
+ ## Summary
2
+
3
+ - What release or release-preparation change is included?
4
+
5
+ ## Versioning
6
+
7
+ - Target version:
8
+ - Why this version is needed:
9
+
10
+ ## Package Impact
11
+
12
+ - [ ] Wheel metadata changed
13
+ - [ ] Sdist contents changed
14
+ - [ ] Release workflow behavior changed
15
+
16
+ Describe the release-facing impact:
17
+
18
+ ## Validation
19
+
20
+ - [ ] `ruff check .`
21
+ - [ ] `pytest -q`
22
+ - [ ] `python -m build`
23
+ - [ ] Release workflow assumptions were checked
24
+
25
+ Commands or workflow runs used:
26
+
27
+ ```text
28
+
29
+ ```
30
+
31
+ ## Manual Registry Steps
32
+
33
+ - [ ] No manual registry work required
34
+ - [ ] PyPI or TestPyPI state was reviewed
35
+ - [ ] GitHub Release asset expectations were reviewed
36
+
37
+ Notes:
38
+
39
+ ## Checklist
40
+
41
+ - [ ] Branch name matches repository conventions
42
+ - [ ] Commit messages follow Conventional Commits
43
+ - [ ] PR is squashed to one commit unless this is necessary `release/<version>` branch work
44
+ - [ ] Release notes or docs were updated if needed
@@ -0,0 +1,41 @@
1
+ ## Summary
2
+
3
+ - PR type: feature / bugfix / docs / maintenance / release
4
+ - What changed?
5
+ - Why is it needed now?
6
+
7
+ ## Implementation
8
+
9
+ - Main modules or flows changed:
10
+ - Any protocol, runtime, or packaging assumptions introduced:
11
+ - Follow-up work, if any:
12
+
13
+ ## Validation
14
+
15
+ - [ ] `ruff check .`
16
+ - [ ] `pytest -q`
17
+ - [ ] Build or packaging checked if distribution output changed
18
+
19
+ Commands or workflow runs used:
20
+
21
+ ```text
22
+
23
+ ```
24
+
25
+ ## Release Impact
26
+
27
+ - [ ] No package output change
28
+ - [ ] Wheel or sdist contents changed
29
+ - [ ] Release workflow behavior changed
30
+
31
+ ## Checklist
32
+
33
+ - [ ] Branch name matches repository conventions
34
+ - [ ] Commit messages follow Conventional Commits
35
+ - [ ] PR is squashed to one commit unless this is necessary `release/<version>` branch work
36
+ - [ ] Documentation was updated when behavior changed
37
+
38
+ ## Notes
39
+
40
+ - Specialized reference templates still live in `.github/PULL_REQUEST_TEMPLATE/`.
41
+ - GitHub does not show an automatic chooser for those files on the standard PR page, so this file acts as the default template.
@@ -0,0 +1,104 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+ workflow_dispatch:
7
+
8
+ jobs:
9
+ commit-policy:
10
+ if: github.event_name == 'pull_request'
11
+ runs-on: ubuntu-latest
12
+
13
+ steps:
14
+ - name: Enforce single-commit PR policy
15
+ shell: bash
16
+ run: |
17
+ set -euo pipefail
18
+
19
+ head_ref="${{ github.head_ref }}"
20
+ base_ref="${{ github.base_ref }}"
21
+
22
+ if [[ "$head_ref" =~ ^release/ ]] || [[ "$base_ref" =~ ^release/ ]]; then
23
+ echo "Release/version branch PR detected; multi-commit history is allowed when needed."
24
+ exit 0
25
+ fi
26
+
27
+ commit_count='${{ github.event.pull_request.commits }}'
28
+ if [ "$commit_count" -ne 1 ]; then
29
+ echo "Normal PRs from feature/fix/docs/chore branches must contain exactly one commit before review. Current PR has $commit_count commits. Squash the history before requesting review."
30
+ exit 1
31
+ fi
32
+
33
+ test:
34
+ runs-on: ubuntu-latest
35
+
36
+ steps:
37
+ - name: Checkout
38
+ uses: actions/checkout@v4
39
+ with:
40
+ fetch-depth: 0
41
+
42
+ - name: Setup Python
43
+ uses: actions/setup-python@v5
44
+ with:
45
+ python-version: '3.11'
46
+
47
+ - name: Install dependencies
48
+ run: |
49
+ python -m pip install --upgrade pip
50
+ python -m pip install -e .[dev] build
51
+
52
+ - name: Lint
53
+ run: ruff check .
54
+
55
+ - name: Test with coverage
56
+ run: >-
57
+ pytest
58
+ --cov=src/nnrp
59
+ --cov=scripts
60
+ --cov-report=xml:artifacts/coverage/coverage.xml
61
+ --cov-fail-under=90
62
+ -q
63
+
64
+ - name: Incremental line coverage gate
65
+ if: github.event_name == 'pull_request' || github.event_name == 'push'
66
+ shell: bash
67
+ run: |
68
+ base_sha=""
69
+ head_sha=""
70
+
71
+ if [ "${{ github.event_name }}" = "pull_request" ]; then
72
+ base_sha="${{ github.event.pull_request.base.sha }}"
73
+ head_sha="${{ github.event.pull_request.head.sha }}"
74
+ else
75
+ base_sha="${{ github.event.before }}"
76
+ head_sha="${{ github.sha }}"
77
+ fi
78
+
79
+ python scripts/check_incremental_coverage.py \
80
+ --base-sha "$base_sha" \
81
+ --head-sha "$head_sha" \
82
+ --threshold 90 \
83
+ --coverage-xml artifacts/coverage/coverage.xml
84
+
85
+ required-checks:
86
+ needs:
87
+ - commit-policy
88
+ - test
89
+ if: always()
90
+ runs-on: ubuntu-latest
91
+
92
+ steps:
93
+ - name: Enforce required CI path
94
+ shell: bash
95
+ run: |
96
+ if [ "${{ github.event_name }}" = "pull_request" ] && [ "${{ needs.commit-policy.result }}" != "success" ]; then
97
+ echo "PR commit policy validation failed."
98
+ exit 1
99
+ fi
100
+
101
+ if [ "${{ needs.test.result }}" != "success" ]; then
102
+ echo "Lint, test, total coverage, or incremental coverage validation failed."
103
+ exit 1
104
+ fi
@@ -0,0 +1,139 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+ workflow_dispatch:
8
+ inputs:
9
+ ref:
10
+ description: Git ref to release when running manually
11
+ required: true
12
+ default: main
13
+ publish_github_release:
14
+ description: Publish or update the GitHub Release
15
+ required: true
16
+ type: boolean
17
+ default: true
18
+ publish_to_pypi:
19
+ description: Publish built distributions to PyPI
20
+ required: true
21
+ type: boolean
22
+ default: false
23
+
24
+ permissions:
25
+ contents: write
26
+
27
+ jobs:
28
+ package:
29
+ runs-on: ubuntu-latest
30
+ environment:
31
+ name: release
32
+ permissions:
33
+ contents: write
34
+ id-token: write
35
+ env:
36
+ PYPI_PUBLISH_MODE: ${{ vars.PYPI_PUBLISH_MODE || 'disabled' }}
37
+ PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
38
+
39
+ steps:
40
+ - name: Checkout
41
+ uses: actions/checkout@v4
42
+ with:
43
+ fetch-depth: 0
44
+ ref: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.ref }}
45
+
46
+ - name: Setup Python
47
+ uses: actions/setup-python@v5
48
+ with:
49
+ python-version: '3.11'
50
+
51
+ - name: Resolve version
52
+ id: version
53
+ run: |
54
+ python scripts/resolve_version.py show --github-output --run-number ""
55
+
56
+ - name: Validate pushed tag
57
+ if: github.event_name == 'push'
58
+ shell: bash
59
+ run: |
60
+ set -euo pipefail
61
+
62
+ expected_tag="${{ steps.version.outputs.tag_name }}"
63
+ actual_tag="${{ github.ref_name }}"
64
+
65
+ if [ "$actual_tag" != "$expected_tag" ]; then
66
+ echo "Release tag mismatch: expected $expected_tag but workflow was triggered by $actual_tag."
67
+ exit 1
68
+ fi
69
+
70
+ - name: Create git tag
71
+ if: github.event_name == 'workflow_dispatch'
72
+ shell: bash
73
+ run: |
74
+ set -euo pipefail
75
+
76
+ git fetch --tags
77
+ tag="${{ steps.version.outputs.tag_name }}"
78
+ if [ -z "$(git tag --list "$tag")" ]; then
79
+ git config user.name "github-actions[bot]"
80
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
81
+ git tag "$tag"
82
+ git push origin "$tag"
83
+ fi
84
+
85
+ - name: Apply build version
86
+ run: |
87
+ python scripts/resolve_version.py apply --package-version "${{ steps.version.outputs.package_version }}"
88
+
89
+ - name: Install dependencies
90
+ run: |
91
+ python -m pip install --upgrade pip
92
+ python -m pip install -e .[dev] build twine
93
+
94
+ - name: Test
95
+ run: pytest -q
96
+
97
+ - name: Build distribution
98
+ run: python -m build
99
+
100
+ - name: Bundle release artifacts
101
+ run: |
102
+ python - <<'PY'
103
+ import pathlib
104
+ import zipfile
105
+
106
+ version = '${{ steps.version.outputs.package_version }}'
107
+ artifact_dir = pathlib.Path('artifacts')
108
+ artifact_dir.mkdir(exist_ok=True)
109
+ artifact = artifact_dir / f'nnrp-py-{version}.zip'
110
+ with zipfile.ZipFile(artifact, 'w', compression=zipfile.ZIP_DEFLATED) as archive:
111
+ for item in sorted(pathlib.Path('dist').glob('*')):
112
+ archive.write(item, item.name)
113
+ PY
114
+
115
+ - name: Upload workflow artifacts
116
+ uses: actions/upload-artifact@v4
117
+ with:
118
+ name: nnrp-py-release-${{ steps.version.outputs.package_version }}
119
+ path: artifacts/nnrp-py-${{ steps.version.outputs.package_version }}.zip
120
+ if-no-files-found: error
121
+ retention-days: 14
122
+
123
+ - name: Publish GitHub release
124
+ if: github.event_name == 'push' || inputs.publish_github_release
125
+ uses: softprops/action-gh-release@v2
126
+ with:
127
+ tag_name: ${{ steps.version.outputs.tag_name }}
128
+ name: ${{ steps.version.outputs.release_name }}
129
+ files: artifacts/nnrp-py-${{ steps.version.outputs.package_version }}.zip
130
+
131
+ - name: Publish to PyPI with Trusted Publisher
132
+ if: (github.event_name == 'push' || inputs.publish_to_pypi) && env.PYPI_PUBLISH_MODE == 'trusted'
133
+ uses: pypa/gh-action-pypi-publish@release/v1
134
+
135
+ - name: Publish to PyPI with API token
136
+ if: (github.event_name == 'push' || inputs.publish_to_pypi) && env.PYPI_PUBLISH_MODE == 'token' && env.PYPI_API_TOKEN != ''
137
+ uses: pypa/gh-action-pypi-publish@release/v1
138
+ with:
139
+ password: ${{ env.PYPI_API_TOKEN }}
@@ -0,0 +1,30 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.pyo
4
+ *.pyd
5
+ .Python
6
+ .coverage
7
+ .coverage.*
8
+ artifacts/coverage/
9
+ .hypothesis/
10
+ .mypy_cache/
11
+ .nox/
12
+ .pytest_cache/
13
+ .ruff_cache/
14
+ .tox/
15
+ .venv/
16
+ venv/
17
+ build/
18
+ dist/
19
+ htmlcov/
20
+ pip-wheel-metadata/
21
+ site/
22
+ .venv/
23
+ __pycache__/
24
+ .pytest_cache/
25
+ .mypy_cache/
26
+ .ruff_cache/
27
+ build/
28
+ dist/
29
+ *.egg-info/
30
+ *.pyc
@@ -0,0 +1,108 @@
1
+ # Contributing to nnrp-py
2
+
3
+ This repository publishes Python SDK packages and protocol tooling, so contribution flow needs to stay predictable.
4
+
5
+ ## Branch Strategy
6
+
7
+ The protected integration branch should be the repository default branch.
8
+
9
+ For the public GitHub repository, use `main` as the protected integration branch.
10
+
11
+ Use short-lived topic branches for day-to-day work:
12
+
13
+ - `feature/<scope>-<topic>` for new capabilities
14
+ - `fix/<scope>-<topic>` for bug fixes
15
+ - `docs/<scope>-<topic>` for documentation-only changes
16
+ - `chore/<scope>-<topic>` for maintenance and tooling updates
17
+ - `release/<version>` only when stabilizing a public package release candidate
18
+
19
+ Rules:
20
+
21
+ - Branch from the latest default integration branch, normally `main`.
22
+ - Keep topic branches focused on one slice of work.
23
+ - Rebase or merge from the default integration branch regularly if the branch stays open.
24
+ - Merge back to the default integration branch through a pull request.
25
+ - Do not push directly to the default integration branch; enforce this with a GitHub ruleset or branch protection rule.
26
+ - Do not publish packages directly from topic branches.
27
+
28
+ `release/<version>` branches are optional and should be used only when a version needs stabilization passes, packaging rehearsals, or manual workflow runs without publishing from the default integration branch.
29
+
30
+ ## Commit Message Convention
31
+
32
+ Use Conventional Commits.
33
+
34
+ Preferred forms:
35
+
36
+ - `feat: add transport probe state summary`
37
+ - `fix: reject malformed session migrate ack`
38
+ - `docs: clarify wheel build prerequisites`
39
+ - `chore: tighten CI dependency bootstrap`
40
+ - `test: add protocol vector regression`
41
+ - `refactor: simplify packet decode flow`
42
+
43
+ Rules:
44
+
45
+ - Keep the subject line imperative.
46
+ - Keep the first line concise.
47
+ - Use a scope only when it adds clarity.
48
+ - You can use multiple local commits while iterating, but normal PRs from `feature/*`, `fix/*`, `docs/*`, or `chore/*` branches must be squashed to exactly one commit before review.
49
+ - Only version-maintenance PRs that target or originate from `release/<version>` branches may keep multiple commits when that history is actually needed.
50
+
51
+ ## Pull Request Expectations
52
+
53
+ Every PR should:
54
+
55
+ - target the default integration branch, normally `main`
56
+ - use the default GitHub PR template that auto-loads on the PR page; specialized reference variants remain in `.github/PULL_REQUEST_TEMPLATE/` when you need to adapt the structure
57
+ - explain the user-facing or engineering motivation
58
+ - summarize the main modules or flows changed
59
+ - list the validation performed
60
+ - mention release impact when distribution output changes
61
+ - contain exactly one commit before review unless it is a necessary `release/<version>` branch PR
62
+ - pass the `required-checks` GitHub Actions job before merge
63
+
64
+ PRs that violate the normal one-commit rule are not reviewed until they are squashed.
65
+
66
+ ## Validation Expectations
67
+
68
+ Before opening or merging a PR, prefer the narrowest validation that proves the touched slice:
69
+
70
+ - `ruff check .`
71
+ - `pytest -q`
72
+ - `pytest --cov=src/nnrp --cov=scripts --cov-report=xml:artifacts/coverage/coverage.xml --cov-fail-under=90 -q` when validating the repository-wide coverage gate
73
+ - `python -m build` when wheel or sdist output changed
74
+
75
+ PRs that affect CI, packaging, or release assets should include the exact command or workflow path used for validation.
76
+
77
+ Changed production lines under `src/nnrp/` or `scripts/` must also keep at least 90% line coverage in CI before merge.
78
+
79
+ ## Versioning and Release Notes
80
+
81
+ Do not reuse a published package version. If package contents change after publication, create a new version.
82
+
83
+ When preparing a release PR:
84
+
85
+ - update the version source intentionally
86
+ - confirm package metadata is correct
87
+ - confirm release assets have the expected names
88
+ - note any manual steps required on registries
89
+
90
+ Public package publishing is gated through the `Release` workflow and should only happen from a short release tag or an explicit manual dispatch.
91
+
92
+ - `Release` runs on pushed `v*` tags and on manual `workflow_dispatch`; normal branch pushes must not publish GitHub releases or PyPI packages.
93
+ - Use the `release` GitHub environment for any publish-capable job.
94
+ - Set `PYPI_PUBLISH_MODE` on the `release` environment to `disabled`, `trusted`, or `token` so tags do not publish to PyPI accidentally before registry binding is ready.
95
+ - If you keep token-based publishing, store `PYPI_API_TOKEN` as an environment secret on `release`, not as an unrestricted repository secret.
96
+ - If you switch to PyPI Trusted Publisher, keep `PYPI_PUBLISH_MODE=trusted`; no PyPI secret is required, but the `release` environment is still recommended for approvals, tag restrictions, and job scoping.
97
+
98
+ ## Review Guidelines
99
+
100
+ Review for:
101
+
102
+ - protocol and wire compatibility risk
103
+ - packaging and release regressions
104
+ - missing tests for changed behavior
105
+ - CI workflow correctness
106
+ - documentation drift when user-facing behavior changes
107
+
108
+ Do not start normal feature, fix, docs, or maintenance review while the PR still carries multiple commits.