linkeval 0.0.1__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.
- linkeval-0.0.1/.gitattributes +9 -0
- linkeval-0.0.1/.github/ISSUE_TEMPLATE/bug.yml +38 -0
- linkeval-0.0.1/.github/ISSUE_TEMPLATE/spike.yml +33 -0
- linkeval-0.0.1/.github/ISSUE_TEMPLATE/story.yml +46 -0
- linkeval-0.0.1/.github/workflows/ci.yml +68 -0
- linkeval-0.0.1/.github/workflows/release.yml +170 -0
- linkeval-0.0.1/.gitignore +11 -0
- linkeval-0.0.1/.pre-commit-config.yaml +14 -0
- linkeval-0.0.1/.release-please-manifest.json +3 -0
- linkeval-0.0.1/CHANGELOG.md +8 -0
- linkeval-0.0.1/CONTRIBUTING.md +79 -0
- linkeval-0.0.1/PKG-INFO +26 -0
- linkeval-0.0.1/README.md +5 -0
- linkeval-0.0.1/docs/agile/definition-of-done.md +13 -0
- linkeval-0.0.1/docs/agile/definition-of-ready.md +11 -0
- linkeval-0.0.1/docs/agile/sprint-01.md +30 -0
- linkeval-0.0.1/docs/agile/velocity.md +15 -0
- linkeval-0.0.1/docs/agile/working-agreement.md +50 -0
- linkeval-0.0.1/docs/decisions/0001-release-automation.md +27 -0
- linkeval-0.0.1/pyproject.toml +71 -0
- linkeval-0.0.1/release-please-config.json +17 -0
- linkeval-0.0.1/src/linkeval/__init__.py +3 -0
- linkeval-0.0.1/tests/test_package.py +10 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Report incorrect or unexpected linkeval behavior
|
|
3
|
+
title: "[Bug] "
|
|
4
|
+
labels:
|
|
5
|
+
- bug
|
|
6
|
+
body:
|
|
7
|
+
- type: textarea
|
|
8
|
+
id: problem
|
|
9
|
+
attributes:
|
|
10
|
+
label: Problem
|
|
11
|
+
description: Describe the observed behavior.
|
|
12
|
+
validations:
|
|
13
|
+
required: true
|
|
14
|
+
|
|
15
|
+
- type: textarea
|
|
16
|
+
id: expected
|
|
17
|
+
attributes:
|
|
18
|
+
label: Expected behavior
|
|
19
|
+
description: State what should have happened instead.
|
|
20
|
+
validations:
|
|
21
|
+
required: true
|
|
22
|
+
|
|
23
|
+
- type: textarea
|
|
24
|
+
id: reproduce
|
|
25
|
+
attributes:
|
|
26
|
+
label: Minimal reproduction
|
|
27
|
+
description: Provide the smallest reproducible example.
|
|
28
|
+
render: python
|
|
29
|
+
validations:
|
|
30
|
+
required: true
|
|
31
|
+
|
|
32
|
+
- type: textarea
|
|
33
|
+
id: environment
|
|
34
|
+
attributes:
|
|
35
|
+
label: Environment
|
|
36
|
+
description: Include linkeval version, Python version, and operating system.
|
|
37
|
+
validations:
|
|
38
|
+
required: true
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
name: Spike
|
|
2
|
+
description: Timeboxed investigation used to reduce technical or statistical uncertainty
|
|
3
|
+
title: "[Spike] "
|
|
4
|
+
labels:
|
|
5
|
+
- spike
|
|
6
|
+
body:
|
|
7
|
+
- type: textarea
|
|
8
|
+
id: question
|
|
9
|
+
attributes:
|
|
10
|
+
label: Question
|
|
11
|
+
description: What uncertainty must this spike resolve?
|
|
12
|
+
validations:
|
|
13
|
+
required: true
|
|
14
|
+
|
|
15
|
+
- type: textarea
|
|
16
|
+
id: outcome
|
|
17
|
+
attributes:
|
|
18
|
+
label: Expected outcome
|
|
19
|
+
description: State what decision or evidence should exist when the spike ends.
|
|
20
|
+
validations:
|
|
21
|
+
required: true
|
|
22
|
+
|
|
23
|
+
- type: dropdown
|
|
24
|
+
id: estimate
|
|
25
|
+
attributes:
|
|
26
|
+
label: Estimate
|
|
27
|
+
options:
|
|
28
|
+
- "1"
|
|
29
|
+
- "2"
|
|
30
|
+
- "3"
|
|
31
|
+
- "5"
|
|
32
|
+
validations:
|
|
33
|
+
required: true
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
name: User story
|
|
2
|
+
description: A planned increment of user-facing or maintainer-facing value
|
|
3
|
+
title: "[Story] "
|
|
4
|
+
labels: []
|
|
5
|
+
body:
|
|
6
|
+
- type: textarea
|
|
7
|
+
id: story
|
|
8
|
+
attributes:
|
|
9
|
+
label: User story
|
|
10
|
+
description: State who needs what and why.
|
|
11
|
+
placeholder: "As a [who], I want [what], so that [why]."
|
|
12
|
+
validations:
|
|
13
|
+
required: true
|
|
14
|
+
|
|
15
|
+
- type: textarea
|
|
16
|
+
id: acceptance
|
|
17
|
+
attributes:
|
|
18
|
+
label: Acceptance criteria
|
|
19
|
+
description: List explicit, checkable conditions for completion.
|
|
20
|
+
placeholder: |
|
|
21
|
+
- [ ] Criterion 1
|
|
22
|
+
- [ ] Criterion 2
|
|
23
|
+
validations:
|
|
24
|
+
required: true
|
|
25
|
+
|
|
26
|
+
- type: dropdown
|
|
27
|
+
id: estimate
|
|
28
|
+
attributes:
|
|
29
|
+
label: Estimate
|
|
30
|
+
description: Fibonacci story-point estimate. Stories above 5 must be split.
|
|
31
|
+
options:
|
|
32
|
+
- "1"
|
|
33
|
+
- "2"
|
|
34
|
+
- "3"
|
|
35
|
+
- "5"
|
|
36
|
+
validations:
|
|
37
|
+
required: true
|
|
38
|
+
|
|
39
|
+
- type: textarea
|
|
40
|
+
id: dependencies
|
|
41
|
+
attributes:
|
|
42
|
+
label: Dependencies
|
|
43
|
+
description: List unresolved dependencies, or write None.
|
|
44
|
+
placeholder: "None"
|
|
45
|
+
validations:
|
|
46
|
+
required: true
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches:
|
|
7
|
+
- main
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
name: Test Python ${{ matrix.python-version }}
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
|
|
14
|
+
strategy:
|
|
15
|
+
fail-fast: false
|
|
16
|
+
matrix:
|
|
17
|
+
python-version:
|
|
18
|
+
- "3.10"
|
|
19
|
+
- "3.11"
|
|
20
|
+
- "3.12"
|
|
21
|
+
- "3.13"
|
|
22
|
+
|
|
23
|
+
steps:
|
|
24
|
+
- name: Check out repository
|
|
25
|
+
uses: actions/checkout@v7
|
|
26
|
+
|
|
27
|
+
- name: Set up Python
|
|
28
|
+
uses: actions/setup-python@v7
|
|
29
|
+
with:
|
|
30
|
+
python-version: ${{ matrix.python-version }}
|
|
31
|
+
|
|
32
|
+
- name: Install package
|
|
33
|
+
run: |
|
|
34
|
+
python -m pip install --upgrade pip
|
|
35
|
+
python -m pip install -e ".[dev]"
|
|
36
|
+
|
|
37
|
+
- name: Run tests
|
|
38
|
+
run: pytest
|
|
39
|
+
|
|
40
|
+
quality:
|
|
41
|
+
name: Quality
|
|
42
|
+
runs-on: ubuntu-latest
|
|
43
|
+
|
|
44
|
+
steps:
|
|
45
|
+
- name: Check out repository
|
|
46
|
+
uses: actions/checkout@v7
|
|
47
|
+
|
|
48
|
+
- name: Set up Python
|
|
49
|
+
uses: actions/setup-python@v7
|
|
50
|
+
with:
|
|
51
|
+
python-version: "3.13"
|
|
52
|
+
|
|
53
|
+
- name: Install package
|
|
54
|
+
run: |
|
|
55
|
+
python -m pip install --upgrade pip
|
|
56
|
+
python -m pip install -e ".[dev]"
|
|
57
|
+
|
|
58
|
+
- name: Lint
|
|
59
|
+
run: ruff check .
|
|
60
|
+
|
|
61
|
+
- name: Check formatting
|
|
62
|
+
run: ruff format --check .
|
|
63
|
+
|
|
64
|
+
- name: Type check
|
|
65
|
+
run: mypy src/linkeval
|
|
66
|
+
|
|
67
|
+
- name: Build distributions
|
|
68
|
+
run: python -m build
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: write
|
|
11
|
+
pull-requests: write
|
|
12
|
+
issues: write
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
release-please:
|
|
16
|
+
name: Release Please
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
|
|
19
|
+
outputs:
|
|
20
|
+
release_created: ${{ steps.release.outputs.release_created }}
|
|
21
|
+
version: ${{ steps.release.outputs.version }}
|
|
22
|
+
tag_name: ${{ steps.release.outputs.tag_name }}
|
|
23
|
+
|
|
24
|
+
steps:
|
|
25
|
+
- name: Run Release Please
|
|
26
|
+
id: release
|
|
27
|
+
uses: googleapis/release-please-action@v5
|
|
28
|
+
with:
|
|
29
|
+
token: ${{ secrets.RELEASE_PLEASE_TOKEN }}
|
|
30
|
+
config-file: release-please-config.json
|
|
31
|
+
manifest-file: .release-please-manifest.json
|
|
32
|
+
|
|
33
|
+
build:
|
|
34
|
+
name: Build distribution
|
|
35
|
+
needs: release-please
|
|
36
|
+
if: ${{ needs.release-please.outputs.release_created == 'true' }}
|
|
37
|
+
runs-on: ubuntu-latest
|
|
38
|
+
|
|
39
|
+
steps:
|
|
40
|
+
- name: Check out repository
|
|
41
|
+
uses: actions/checkout@v7
|
|
42
|
+
|
|
43
|
+
- name: Set up Python
|
|
44
|
+
uses: actions/setup-python@v7
|
|
45
|
+
with:
|
|
46
|
+
python-version: "3.13"
|
|
47
|
+
|
|
48
|
+
- name: Install build frontend
|
|
49
|
+
run: python -m pip install --upgrade build
|
|
50
|
+
|
|
51
|
+
- name: Build wheel and source distribution
|
|
52
|
+
run: python -m build
|
|
53
|
+
|
|
54
|
+
- name: Store distribution artifacts
|
|
55
|
+
uses: actions/upload-artifact@v4
|
|
56
|
+
with:
|
|
57
|
+
name: python-package-distributions
|
|
58
|
+
path: dist/
|
|
59
|
+
|
|
60
|
+
publish-testpypi:
|
|
61
|
+
name: Publish to TestPyPI
|
|
62
|
+
needs:
|
|
63
|
+
- release-please
|
|
64
|
+
- build
|
|
65
|
+
runs-on: ubuntu-latest
|
|
66
|
+
environment: testpypi
|
|
67
|
+
|
|
68
|
+
permissions:
|
|
69
|
+
id-token: write
|
|
70
|
+
|
|
71
|
+
steps:
|
|
72
|
+
- name: Download distribution artifacts
|
|
73
|
+
uses: actions/download-artifact@v4
|
|
74
|
+
with:
|
|
75
|
+
name: python-package-distributions
|
|
76
|
+
path: dist/
|
|
77
|
+
|
|
78
|
+
- name: Publish package to TestPyPI
|
|
79
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
80
|
+
with:
|
|
81
|
+
repository-url: https://test.pypi.org/legacy/
|
|
82
|
+
|
|
83
|
+
verify-testpypi:
|
|
84
|
+
name: Verify TestPyPI installation
|
|
85
|
+
needs:
|
|
86
|
+
- release-please
|
|
87
|
+
- publish-testpypi
|
|
88
|
+
runs-on: ubuntu-latest
|
|
89
|
+
|
|
90
|
+
steps:
|
|
91
|
+
- name: Set up Python
|
|
92
|
+
uses: actions/setup-python@v7
|
|
93
|
+
with:
|
|
94
|
+
python-version: "3.13"
|
|
95
|
+
|
|
96
|
+
- name: Download package from TestPyPI
|
|
97
|
+
env:
|
|
98
|
+
VERSION: ${{ needs.release-please.outputs.version }}
|
|
99
|
+
run: |
|
|
100
|
+
mkdir testpypi-download
|
|
101
|
+
for attempt in 1 2 3 4 5 6; do
|
|
102
|
+
python -m pip download \
|
|
103
|
+
--no-deps \
|
|
104
|
+
--index-url https://test.pypi.org/simple/ \
|
|
105
|
+
"linkeval==$VERSION" \
|
|
106
|
+
--dest testpypi-download && break
|
|
107
|
+
echo "TestPyPI package not visible yet; retrying in 10 seconds."
|
|
108
|
+
sleep 10
|
|
109
|
+
done
|
|
110
|
+
test -n "$(find testpypi-download -type f -print -quit)"
|
|
111
|
+
|
|
112
|
+
- name: Install downloaded TestPyPI package
|
|
113
|
+
run: python -m pip install testpypi-download/*
|
|
114
|
+
|
|
115
|
+
- name: Verify installed version
|
|
116
|
+
env:
|
|
117
|
+
VERSION: ${{ needs.release-please.outputs.version }}
|
|
118
|
+
run: |
|
|
119
|
+
python -c "from importlib.metadata import version; assert version('linkeval') == '$VERSION'"
|
|
120
|
+
|
|
121
|
+
publish-pypi:
|
|
122
|
+
name: Publish to PyPI
|
|
123
|
+
needs:
|
|
124
|
+
- release-please
|
|
125
|
+
- build
|
|
126
|
+
- verify-testpypi
|
|
127
|
+
runs-on: ubuntu-latest
|
|
128
|
+
environment: pypi
|
|
129
|
+
|
|
130
|
+
permissions:
|
|
131
|
+
id-token: write
|
|
132
|
+
|
|
133
|
+
steps:
|
|
134
|
+
- name: Download distribution artifacts
|
|
135
|
+
uses: actions/download-artifact@v4
|
|
136
|
+
with:
|
|
137
|
+
name: python-package-distributions
|
|
138
|
+
path: dist/
|
|
139
|
+
|
|
140
|
+
- name: Publish package to PyPI
|
|
141
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
142
|
+
|
|
143
|
+
verify-pypi:
|
|
144
|
+
name: Verify PyPI installation
|
|
145
|
+
needs:
|
|
146
|
+
- release-please
|
|
147
|
+
- publish-pypi
|
|
148
|
+
runs-on: ubuntu-latest
|
|
149
|
+
|
|
150
|
+
steps:
|
|
151
|
+
- name: Set up Python
|
|
152
|
+
uses: actions/setup-python@v7
|
|
153
|
+
with:
|
|
154
|
+
python-version: "3.13"
|
|
155
|
+
|
|
156
|
+
- name: Install released package
|
|
157
|
+
env:
|
|
158
|
+
VERSION: ${{ needs.release-please.outputs.version }}
|
|
159
|
+
run: |
|
|
160
|
+
for attempt in 1 2 3 4 5 6; do
|
|
161
|
+
python -m pip install "linkeval==$VERSION" && break
|
|
162
|
+
echo "PyPI package not visible yet; retrying in 10 seconds."
|
|
163
|
+
sleep 10
|
|
164
|
+
done
|
|
165
|
+
|
|
166
|
+
- name: Verify installed version
|
|
167
|
+
env:
|
|
168
|
+
VERSION: ${{ needs.release-please.outputs.version }}
|
|
169
|
+
run: |
|
|
170
|
+
python -c "from importlib.metadata import version; assert version('linkeval') == '$VERSION'"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
3
|
+
rev: v0.16.6
|
|
4
|
+
hooks:
|
|
5
|
+
- id: ruff-check
|
|
6
|
+
args: [--fix]
|
|
7
|
+
- id: ruff-format
|
|
8
|
+
|
|
9
|
+
- repo: https://github.com/pre-commit/mirrors-mypy
|
|
10
|
+
rev: v2.3.1
|
|
11
|
+
hooks:
|
|
12
|
+
- id: mypy
|
|
13
|
+
args: [src/linkeval]
|
|
14
|
+
pass_filenames: false
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Contributing to linkeval
|
|
2
|
+
|
|
3
|
+
## Development setup
|
|
4
|
+
|
|
5
|
+
Clone the repository and create a virtual environment:
|
|
6
|
+
|
|
7
|
+
python -m venv .venv
|
|
8
|
+
|
|
9
|
+
Activate the environment and install the package with development dependencies:
|
|
10
|
+
|
|
11
|
+
python -m pip install -e ".[dev]"
|
|
12
|
+
pre-commit install
|
|
13
|
+
|
|
14
|
+
## Quality checks
|
|
15
|
+
|
|
16
|
+
Before opening a pull request, run:
|
|
17
|
+
|
|
18
|
+
pytest
|
|
19
|
+
ruff check .
|
|
20
|
+
ruff format --check .
|
|
21
|
+
mypy src/linkeval
|
|
22
|
+
python -m build
|
|
23
|
+
pre-commit run --all-files
|
|
24
|
+
|
|
25
|
+
## Branches and pull requests
|
|
26
|
+
|
|
27
|
+
Development happens on short-lived branches using an issue number, for example:
|
|
28
|
+
|
|
29
|
+
feat/12-cluster-representation
|
|
30
|
+
fix/18-empty-truth-set
|
|
31
|
+
docs/21-bootstrap-guide
|
|
32
|
+
chore/6-release-pipeline
|
|
33
|
+
|
|
34
|
+
Changes reach `main` only through pull requests. CI must pass before merge.
|
|
35
|
+
|
|
36
|
+
Pull requests are squash merged and should include `Closes #n` for their associated issue.
|
|
37
|
+
|
|
38
|
+
## Conventional Commits
|
|
39
|
+
|
|
40
|
+
Commit messages follow Conventional Commits.
|
|
41
|
+
|
|
42
|
+
Examples:
|
|
43
|
+
|
|
44
|
+
feat: add cluster representation
|
|
45
|
+
fix: reject self-pairs
|
|
46
|
+
docs: explain record-level bootstrap
|
|
47
|
+
chore: update release workflow
|
|
48
|
+
|
|
49
|
+
The commit type is part of the release system. Release Please uses Conventional Commits to determine the next version and generate the changelog.
|
|
50
|
+
|
|
51
|
+
## Releases
|
|
52
|
+
|
|
53
|
+
Release Please manages release preparation.
|
|
54
|
+
|
|
55
|
+
1. Conventional Commits merged to `main` are inspected by Release Please.
|
|
56
|
+
2. Release Please opens or updates a release pull request.
|
|
57
|
+
3. The release pull request contains the calculated version and generated changelog.
|
|
58
|
+
4. The release pull request must pass the normal review and CI gates.
|
|
59
|
+
5. Merging the release pull request creates the Git tag and GitHub release.
|
|
60
|
+
6. The release workflow builds the wheel and source distribution.
|
|
61
|
+
7. The distributions are published to TestPyPI using GitHub OIDC trusted publishing.
|
|
62
|
+
8. Installation from TestPyPI is verified.
|
|
63
|
+
9. The same distributions are published to PyPI using GitHub OIDC trusted publishing.
|
|
64
|
+
10. Installation from PyPI is verified.
|
|
65
|
+
|
|
66
|
+
No PyPI API token is stored in repository secrets.
|
|
67
|
+
|
|
68
|
+
## Release credentials
|
|
69
|
+
|
|
70
|
+
TestPyPI and PyPI trust the GitHub Actions workflow through OpenID Connect.
|
|
71
|
+
|
|
72
|
+
Authorized workflow:
|
|
73
|
+
|
|
74
|
+
.github/workflows/release.yml
|
|
75
|
+
|
|
76
|
+
GitHub environments:
|
|
77
|
+
|
|
78
|
+
testpypi
|
|
79
|
+
pypi
|
linkeval-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: linkeval
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Evaluation and uncertainty quantification for entity resolution.
|
|
5
|
+
Author: Abrar Ahmed
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.10
|
|
8
|
+
Requires-Dist: numpy
|
|
9
|
+
Requires-Dist: scipy
|
|
10
|
+
Provides-Extra: dev
|
|
11
|
+
Requires-Dist: build; extra == 'dev'
|
|
12
|
+
Requires-Dist: hypothesis; extra == 'dev'
|
|
13
|
+
Requires-Dist: mypy; extra == 'dev'
|
|
14
|
+
Requires-Dist: pre-commit; extra == 'dev'
|
|
15
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
16
|
+
Requires-Dist: pytest-cov; extra == 'dev'
|
|
17
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
18
|
+
Provides-Extra: pandas
|
|
19
|
+
Requires-Dist: pandas; extra == 'pandas'
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# linkeval
|
|
23
|
+
|
|
24
|
+
Evaluation and uncertainty quantification for entity resolution � bring your own linker.
|
|
25
|
+
|
|
26
|
+
> Early development version. The public metric API has not yet been implemented.
|
linkeval-0.0.1/README.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Definition of Done
|
|
2
|
+
|
|
3
|
+
A story is Done only when all of the following are true:
|
|
4
|
+
|
|
5
|
+
- It is merged to `main` through a pull request and is never pushed directly to `main`.
|
|
6
|
+
- CI is green: tests, Ruff, and mypy all pass.
|
|
7
|
+
- Test coverage has not decreased.
|
|
8
|
+
- Public API changes are fully typed and documented with docstrings.
|
|
9
|
+
- Documentation is updated when the public API changes.
|
|
10
|
+
- Commit messages follow Conventional Commits.
|
|
11
|
+
- An ADR exists in `docs/decisions/` when the story introduces a significant technical or statistical decision.
|
|
12
|
+
|
|
13
|
+
A story that has completed implementation but has not satisfied every condition remains In Review rather than moving to Done.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Definition of Ready
|
|
2
|
+
|
|
3
|
+
A story may enter a sprint only when all of the following are true:
|
|
4
|
+
|
|
5
|
+
- It is written as a user story: As a [who], I want [what], so that [why].
|
|
6
|
+
- It has explicit and checkable acceptance criteria.
|
|
7
|
+
- It has an estimate of 5 points or fewer.
|
|
8
|
+
- It has no unresolved dependency on a story that has not started.
|
|
9
|
+
- It is plausibly finishable in one focused work session.
|
|
10
|
+
|
|
11
|
+
A story that does not satisfy every condition remains in Backlog rather than moving to Ready.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Sprint 01
|
|
2
|
+
|
|
3
|
+
## Sprint goal
|
|
4
|
+
|
|
5
|
+
Establish a professional, installable `linkeval` skeleton whose quality gates and release path work before introducing metric logic.
|
|
6
|
+
|
|
7
|
+
## Committed stories
|
|
8
|
+
|
|
9
|
+
1. Repository and installable package skeleton - 2 points
|
|
10
|
+
2. Local quality gates - 2 points
|
|
11
|
+
3. Pull-request CI gate - 2 points
|
|
12
|
+
4. Scrumban project foundation - 2 points
|
|
13
|
+
5. Publish `0.0.1` through TestPyPI and PyPI - 2 points
|
|
14
|
+
|
|
15
|
+
## Current state
|
|
16
|
+
|
|
17
|
+
- Story 1 - Done
|
|
18
|
+
- Story 2 - Done
|
|
19
|
+
- Story 3 - Done
|
|
20
|
+
- Story 4 - In Review
|
|
21
|
+
- Story 5 - In Review
|
|
22
|
+
- Story 5 - In Review - release pipeline merged; 0.0.1 publication pending
|
|
23
|
+
|
|
24
|
+
## Review
|
|
25
|
+
|
|
26
|
+
_To be completed at sprint review._
|
|
27
|
+
|
|
28
|
+
## Retrospective
|
|
29
|
+
|
|
30
|
+
_To be completed at sprint retrospective._
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Velocity
|
|
2
|
+
|
|
3
|
+
Velocity is recorded only for sprints that were actually worked.
|
|
4
|
+
|
|
5
|
+
| Sprint | Committed points | Delivered points | Notes |
|
|
6
|
+
|---|---:|---:|---|
|
|
7
|
+
| Sprint 01 | 10 | TBD | First sprint; initial estimate intentionally not treated as a hard capacity constraint. |
|
|
8
|
+
|
|
9
|
+
## Rules
|
|
10
|
+
|
|
11
|
+
- Do not re-estimate stories after the sprint starts.
|
|
12
|
+
- Record committed points and delivered points separately.
|
|
13
|
+
- Skipped sprints are recorded as skipped and excluded from velocity calculations.
|
|
14
|
+
- From Sprint 4 onward, use the rolling three-sprint average velocity as the planning reference.
|
|
15
|
+
- Velocity is a planning aid, not a performance target.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Working Agreement
|
|
2
|
+
|
|
3
|
+
## Cadence
|
|
4
|
+
|
|
5
|
+
- Work is organized in two-week sprints.
|
|
6
|
+
- Sprints start on Saturday.
|
|
7
|
+
- Sprints may be skipped for defence preparation, interviews, or other higher-priority commitments.
|
|
8
|
+
- A skipped sprint is recorded as skipped rather than silently removed.
|
|
9
|
+
|
|
10
|
+
## Ceremony timeboxes
|
|
11
|
+
|
|
12
|
+
- Sprint planning: 15 minutes.
|
|
13
|
+
- Sprint review: 5 minutes.
|
|
14
|
+
- Sprint retrospective: 10 minutes.
|
|
15
|
+
- Total ceremony budget: 30 minutes per sprint.
|
|
16
|
+
|
|
17
|
+
## Board workflow
|
|
18
|
+
|
|
19
|
+
Work moves through:
|
|
20
|
+
|
|
21
|
+
Backlog -> Ready -> In Progress -> In Review -> Done
|
|
22
|
+
|
|
23
|
+
The In Progress column has a WIP limit of 1.
|
|
24
|
+
|
|
25
|
+
## Branching and review
|
|
26
|
+
|
|
27
|
+
- `main` is protected.
|
|
28
|
+
- Work happens on short-lived branches using `feat/`, `fix/`, `docs/`, or `chore/` prefixes plus the issue number.
|
|
29
|
+
- Changes reach `main` through pull requests.
|
|
30
|
+
- CI must pass before merge.
|
|
31
|
+
- Pull requests are squash merged.
|
|
32
|
+
- Every PR body links its issue using `Closes #n`.
|
|
33
|
+
- Before merge, the maintainer reads the full diff and leaves at least one substantive self-review comment.
|
|
34
|
+
|
|
35
|
+
## Commits
|
|
36
|
+
|
|
37
|
+
Commit messages follow Conventional Commits:
|
|
38
|
+
|
|
39
|
+
- `feat:` for user-facing functionality.
|
|
40
|
+
- `fix:` for bug fixes.
|
|
41
|
+
- `docs:` for documentation changes.
|
|
42
|
+
- `test:` for test-only changes.
|
|
43
|
+
- `refactor:` for internal code changes without user-facing behavior changes.
|
|
44
|
+
- `chore:` for tooling, infrastructure, packaging, or maintenance work.
|
|
45
|
+
|
|
46
|
+
## Definition enforcement
|
|
47
|
+
|
|
48
|
+
- A story may move from Backlog to Ready only when it satisfies the Definition of Ready.
|
|
49
|
+
- A story may move to Done only when it satisfies the Definition of Done.
|
|
50
|
+
- Significant technical or statistical decisions require an ADR in `docs/decisions/`.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# ADR 0001: Release automation
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
|
|
5
|
+
Accepted
|
|
6
|
+
|
|
7
|
+
## Context
|
|
8
|
+
|
|
9
|
+
`linkeval` needs a release process that keeps version numbers, changelog entries, GitHub releases, and package publication consistent with one another. Because the project uses protected `main`, pull-request-only changes, and Conventional Commits, the release mechanism should fit that workflow rather than bypass it. The aim is to avoid manually deciding version bumps or reconstructing a changelog at release time.
|
|
10
|
+
|
|
11
|
+
## Decision
|
|
12
|
+
|
|
13
|
+
We will use Release Please for release versioning and changelog generation. Release Please derives the next release from Conventional Commits and prepares the version and changelog changes in a release pull request. This fits the repository's PR-gated workflow because release-related changes remain reviewable and must pass CI before reaching `main`. Publishing to TestPyPI and PyPI will then be triggered from the resulting GitHub release using trusted publishing.
|
|
14
|
+
|
|
15
|
+
## Alternatives considered
|
|
16
|
+
|
|
17
|
+
### python-semantic-release
|
|
18
|
+
|
|
19
|
+
`python-semantic-release` was a reasonable alternative because it also derives version changes from Conventional Commits and can automate changelog generation and publishing. We did not choose it because Release Please's release-PR model fits more naturally with this repository's protected-branch workflow. It keeps the version and changelog update inside the same pull-request process used for normal development rather than relying on release automation to write changes directly to `main`.
|
|
20
|
+
|
|
21
|
+
### Manual versioning and changelog maintenance
|
|
22
|
+
|
|
23
|
+
Manual versioning would give full control over each release, but it would introduce a repetitive maintenance step that is easy to forget or apply inconsistently. It would also weaken the purpose of adopting Conventional Commits, since commit history would no longer directly drive release metadata. For this project, the additional manual control is not worth the risk of version and changelog drift.
|
|
24
|
+
|
|
25
|
+
## Consequences
|
|
26
|
+
|
|
27
|
+
Release preparation becomes reproducible and visible in pull requests, and the changelog is derived from the same commit history used for development. The trade-off is that commit messages now form part of the release system: incorrect Conventional Commit prefixes can lead to an incorrect version bump or missing changelog entry. This means commit-message discipline is a functional requirement rather than only a style preference.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "linkeval"
|
|
7
|
+
version = "0.0.1"
|
|
8
|
+
description = "Evaluation and uncertainty quantification for entity resolution."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Abrar Ahmed" }
|
|
14
|
+
]
|
|
15
|
+
dependencies = [
|
|
16
|
+
"numpy",
|
|
17
|
+
"scipy",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
[project.optional-dependencies]
|
|
21
|
+
pandas = [
|
|
22
|
+
"pandas",
|
|
23
|
+
]
|
|
24
|
+
dev = [
|
|
25
|
+
"pytest",
|
|
26
|
+
"pytest-cov",
|
|
27
|
+
"hypothesis",
|
|
28
|
+
"ruff",
|
|
29
|
+
"mypy",
|
|
30
|
+
"pre-commit",
|
|
31
|
+
"build",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[tool.hatch.build.targets.wheel]
|
|
35
|
+
packages = ["src/linkeval"]
|
|
36
|
+
|
|
37
|
+
[tool.pytest.ini_options]
|
|
38
|
+
testpaths = ["tests"]
|
|
39
|
+
addopts = [
|
|
40
|
+
"--strict-markers",
|
|
41
|
+
"--strict-config",
|
|
42
|
+
"--cov=linkeval",
|
|
43
|
+
"--cov-report=term-missing",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
[tool.coverage.run]
|
|
47
|
+
branch = true
|
|
48
|
+
source = ["linkeval"]
|
|
49
|
+
|
|
50
|
+
[tool.coverage.report]
|
|
51
|
+
show_missing = true
|
|
52
|
+
skip_covered = true
|
|
53
|
+
|
|
54
|
+
[tool.ruff]
|
|
55
|
+
target-version = "py310"
|
|
56
|
+
line-length = 88
|
|
57
|
+
src = ["src", "tests"]
|
|
58
|
+
|
|
59
|
+
[tool.ruff.lint]
|
|
60
|
+
select = [
|
|
61
|
+
"E",
|
|
62
|
+
"F",
|
|
63
|
+
"I",
|
|
64
|
+
"UP",
|
|
65
|
+
"B",
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
[tool.mypy]
|
|
69
|
+
python_version = "3.10"
|
|
70
|
+
strict = true
|
|
71
|
+
files = ["src/linkeval"]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
|
|
3
|
+
"release-type": "python",
|
|
4
|
+
"include-v-in-tag": true,
|
|
5
|
+
"include-component-in-tag": false,
|
|
6
|
+
"release-as": "0.0.1",
|
|
7
|
+
"packages": {
|
|
8
|
+
".": {
|
|
9
|
+
"extra-files": [
|
|
10
|
+
{
|
|
11
|
+
"type": "generic",
|
|
12
|
+
"path": "src/linkeval/__init__.py"
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""Basic tests for the installed linkeval package."""
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import version
|
|
4
|
+
|
|
5
|
+
import linkeval
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_package_version_matches_distribution_metadata() -> None:
|
|
9
|
+
"""The public version matches the installed distribution metadata."""
|
|
10
|
+
assert linkeval.__version__ == version("linkeval")
|