Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
0ba76cc
Record v1.3 canonical-migration blast-radius review in docs
sergeyf Jul 4, 2026
93270d6
Freeze canonical name-normalization example table (migration step 1)
sergeyf Jul 4, 2026
e76cb6b
Ratify canonical name rulings D1/D3/D6 in the example table
sergeyf Jul 4, 2026
b52f95b
Strengthen example-table enforcement per review
sergeyf Jul 4, 2026
68b6768
Fix work_plan section-2 correctness bugs (Python+Rust lockstep)
sergeyf Jul 4, 2026
9ce4255
Mirror D6 empty-surname NaN into Rust name-count artifact path
sergeyf Jul 5, 2026
a19adf8
Revert Arrow reader NULL-strictness; NULL is the legitimate empty value
sergeyf Jul 5, 2026
ee290fb
Revert speculative same-signature guard in raw_paper_evidence_features
sergeyf Jul 5, 2026
6c9d327
Remove the Sinonym Chinese-name normalization path
sergeyf Jul 5, 2026
3e50d58
docs(work_plan): record 2026-07-04 migration decisions and the Tier B…
sergeyf Jul 5, 2026
1082eb4
Language detection: mandatory fastText + agreement-based is_reliable …
sergeyf Jul 5, 2026
88d2ae5
Fail fast on non-initial_char name-count semantics at Arrow conversion
sergeyf Jul 5, 2026
f1c6f39
Pin ORCID flag-is-authoritative invariant (work_plan #229 verified co…
sergeyf Jul 5, 2026
711456e
Expand canonical name migration fixture cleanup
sergeyf Jul 5, 2026
9414fef
Keep fastText enabled outside tests
sergeyf Jul 5, 2026
027b961
Improve canonical name normalization parity
sergeyf Jul 6, 2026
00c947d
Complete Rust Arrow migration
sergeyf Jul 8, 2026
e98ce96
Format eval prod models script
sergeyf Jul 8, 2026
a8df96a
Fix py-only CI rust test gating
sergeyf Jul 8, 2026
c4edc11
Fix Rust runtime regression issues
sergeyf Jul 9, 2026
2ad68a3
Fix lower-priority runtime cleanup issues
sergeyf Jul 9, 2026
5c24fe7
Remove fastText language detection
sergeyf Jul 9, 2026
f1fb763
Update canonical migration status
sergeyf Jul 9, 2026
0f21a45
Update work plan for canonical cutover
sergeyf Jul 9, 2026
64275ef
Fix CI lint and canonical test gates
sergeyf Jul 9, 2026
7638ab3
Rule space-insensitive last-name comparison as compare-time policy
sergeyf Jul 9, 2026
519334c
Refactor annotation pipeline and update supporting code
sergeyf Jul 10, 2026
a7010ea
Fix CI gating and cross-platform checks
sergeyf Jul 10, 2026
60a3c62
Complete canonical v2 runtime migration
sergeyf Jul 10, 2026
d71603c
Fix CI after canonical runtime migration
sergeyf Jul 10, 2026
9be9f6c
Fix Rust lane dependency sync
sergeyf Jul 10, 2026
4089089
Remove unsupported Rust-free CI lane
sergeyf Jul 10, 2026
56a58c4
Stabilize local CI guardrail environment
sergeyf Jul 10, 2026
e919ba1
Simplify canonical v2 migration
sergeyf Jul 10, 2026
3ea8396
Fix native extension type boundaries
sergeyf Jul 10, 2026
fdffdca
Restore selected archive provenance
sergeyf Jul 10, 2026
a03a068
Simplify runtime and remove compatibility layers
sergeyf Jul 10, 2026
f6ad605
Fix Rust parity tooling and CI guardrails
sergeyf Jul 11, 2026
97786d4
Fix correctness issues across data and Arrow pipelines
sergeyf Jul 11, 2026
a7e2db9
Fix canonical migration and add pair ablation tooling
sergeyf Jul 18, 2026
2ade7cd
Simplify pair ablation and harden canonical v2
sergeyf Jul 19, 2026
dad1d52
Make legacy data-root test environment-independent
sergeyf Jul 19, 2026
b6385a8
Reduce canonical v2 migration complexity
sergeyf Jul 19, 2026
2756989
Fix canonical Arrow validation fixtures
sergeyf Jul 19, 2026
4ea7ca9
Simplify canonical v2 artifact contracts
sergeyf Jul 19, 2026
aff38d1
Fix canonical v2 CI regressions
sergeyf Jul 19, 2026
d6b8e49
Simplify canonical v2 migration
sergeyf Jul 20, 2026
1aafd93
Sync Rust Arrow schema contract
sergeyf Jul 20, 2026
ff3f3f2
Harden retraining input lineage
sergeyf Jul 20, 2026
4c2fbdc
Match Python whitespace in Rust name and email parsing
sergeyf Jul 20, 2026
c933268
Canonicalize ORCID prefix-count generation
sergeyf Jul 20, 2026
25814a3
Verify pairwise models bind name-count provenance
sergeyf Jul 20, 2026
46f6e00
Correct name-count limit help
sergeyf Jul 20, 2026
88c6f19
Reject existing pairwise output before artifact loading
sergeyf Jul 20, 2026
735a064
Record completed retrain-safety phases
sergeyf Jul 20, 2026
7952c98
Format raw Arrow candidate-plan tests
sergeyf Jul 20, 2026
883b662
Replace pair-feature SQLite cache with featurized-split snapshot cache
sergeyf Jul 21, 2026
a1d03dd
Record cache supersession and approved owner decisions
sergeyf Jul 21, 2026
debc401
Make pairwise_bundle_binding the single artifact authority
sergeyf Jul 21, 2026
23f7cc9
Adopt name-tuple artifact v3 with full input-pair accounting
sergeyf Jul 21, 2026
d9ae678
Pass v3 duplicate count in data-loader tuple test
sergeyf Jul 21, 2026
d16aa2a
Remove pair-source ablation study from the migration PR
sergeyf Jul 21, 2026
bc1454e
Bind linker artifact v4 to the training target digest
sergeyf Jul 21, 2026
0673781
Harden pairwise fixture and config validation
sergeyf Jul 21, 2026
6d87461
Validate bundles in a single pass during model loading
sergeyf Jul 21, 2026
a1d978f
Drop duplicate contract validation on artifact save
sergeyf Jul 21, 2026
8780119
Prove Arrow prediction entrypoints reject unindexed input
sergeyf Jul 21, 2026
6fda33c
Narrow the name-count publication contract with a crash-window test
sergeyf Jul 21, 2026
c43f58e
Remove one-off benchmark machinery
sergeyf Jul 21, 2026
c7891cd
Delete proven dead private code
sergeyf Jul 21, 2026
aca89b4
Finish Rust and test cleanup
sergeyf Jul 21, 2026
1774bc9
Simplify canonical-v2 runtime and release contracts
sergeyf Jul 21, 2026
ddc3e41
Harden canonical v2 runtime and trim legacy paths
sergeyf Jul 21, 2026
d71fcd7
Harden canonical v2 migration
sergeyf Jul 21, 2026
d74eac2
Fix ty ignore diagnostics
sergeyf Jul 21, 2026
e7f8cc5
Fix script typecheck diagnostics
sergeyf Jul 21, 2026
b7a5992
Fix training and artifact integrity
sergeyf Jul 22, 2026
bf9b316
Finish canonical v2 migration cleanup
sergeyf Jul 22, 2026
28f9996
Prune obsolete migration documentation
sergeyf Jul 22, 2026
c196deb
Harden canonical artifact contracts and runtime reuse
sergeyf Jul 22, 2026
f986d0a
Fix canonical v2 migration edge cases
sergeyf Jul 22, 2026
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
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
* text=auto eol=lf

s2and/data/production_model_v*.pickle filter=lfs diff=lfs merge=lfs -text
s2and/data/production_model_v*.pkl filter=lfs diff=lfs merge=lfs -text
s2and/data/production_model_v*/** filter=lfs diff=lfs merge=lfs -text
Expand Down
20 changes: 8 additions & 12 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,14 @@ if ! git diff --cached --name-only --diff-filter=ACM | grep -qx "VERSION"; then
exit 0
fi

VERSION_FILES=(
"VERSION"
"pyproject.toml"
"s2and_rust/pyproject.toml"
"s2and_rust/Cargo.toml"
"s2and/runtime.py"
"README.md"
"docs/development.md"
"s2and_rust/README.md"
"uv.lock"
"s2and_rust/Cargo.lock"
)
VERSION_TARGETS="$(uv run python scripts/sync_version.py --print-targets)"
VERSION_FILES=()
while IFS= read -r version_file; do
version_file="${version_file%$'\r'}"
if [[ -n "$version_file" ]]; then
VERSION_FILES+=("$version_file")
fi
done <<< "$VERSION_TARGETS"

if uv run python scripts/sync_version.py --check; then
exit 0
Expand Down
180 changes: 9 additions & 171 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,39 +26,14 @@ jobs:
~/.cache/uv
key: uv-cache-${{ runner.os }}-${{ hashFiles('pyproject.toml', 'uv.lock') }}

# Sync environment from lock if present so tool versions come from pyproject.toml/uv.lock
- name: Sync deps (locked if available)
shell: bash
run: |
if [[ -f uv.lock ]]; then
uv sync --extra dev --frozen
else
uv sync --extra dev
fi

- name: version sync check
run: uv run python scripts/sync_version.py --check
- name: ruff check
run: uv run ruff check s2and scripts tests
- name: ruff format (s2and/)
run: uv run ruff format --check s2and
- name: ruff format (scripts/*.py)
shell: bash
run: |
shopt -s nullglob
files=(scripts/*.py)
if (( ${#files[@]} )); then
uv run ruff format --check "${files[@]}"
fi
- name: Run shared lint policy
run: uv run --no-project python scripts/run_ci_locally.py lint

typecheck-and-test:
name: typecheck-and-test (${{ matrix.lane }})
runs-on: ubuntu-latest
needs: [lint]
strategy:
fail-fast: false
matrix:
lane: [py-only, rust-enabled]
env:
S2AND_TEST_REQUIRE_RUST: "1"
steps:
- uses: actions/checkout@v5
with:
Expand All @@ -73,73 +48,12 @@ jobs:
with:
python-version: '3.11'

- name: Hydrate CI LFS artifacts
run: git lfs pull --include="s2and/data/production_model_v*.pickle,s2and/data/production_model_v*/**,tests/fixtures/arrow/pubmed_specter2/**"

- name: Verify hydrated CI LFS artifacts
run: |
uv run --no-project python - <<'PY'
from pathlib import Path

pointer_prefix = b"version https://git-lfs.github.com/spec/v1"
required_paths = [
Path("s2and/data/production_model_v1.0.pickle"),
Path("s2and/data/production_model_v1.1.pickle"),
Path("s2and/data/production_model_v1.2.pickle"),
]
required_paths.extend(
sorted(path for path in Path("s2and/data/production_model_v1.21").rglob("*") if path.is_file())
)
required_paths.extend(
[
Path("tests/fixtures/arrow/pubmed_specter2/pubmed/signatures.arrow"),
Path("tests/fixtures/arrow/pubmed_specter2/pubmed/papers.arrow"),
Path("tests/fixtures/arrow/pubmed_specter2/pubmed/paper_authors.arrow"),
Path("tests/fixtures/arrow/pubmed_specter2/pubmed/specter2.arrow"),
Path("tests/fixtures/arrow/pubmed_specter2/pubmed/signatures.signatures_batch_index.bin"),
Path("tests/fixtures/arrow/pubmed_specter2/pubmed/papers.papers_batch_index.bin"),
Path("tests/fixtures/arrow/pubmed_specter2/pubmed/paper_authors.paper_authors_batch_index.bin"),
Path("tests/fixtures/arrow/pubmed_specter2/pubmed/specter2.specter_batch_index.bin"),
Path("tests/fixtures/arrow/pubmed_specter2/pubmed/name_counts_index/manifest.json"),
Path(
"tests/fixtures/arrow/pubmed_specter2/pubmed/name_counts_index/"
"generations/pubmed-specter2/first.bin"
),
Path(
"tests/fixtures/arrow/pubmed_specter2/pubmed/name_counts_index/"
"generations/pubmed-specter2/last.bin"
),
Path(
"tests/fixtures/arrow/pubmed_specter2/pubmed/name_counts_index/"
"generations/pubmed-specter2/first_last.bin"
),
Path(
"tests/fixtures/arrow/pubmed_specter2/pubmed/name_counts_index/"
"generations/pubmed-specter2/last_first_initial.bin"
),
]
)

failures = []
for path in required_paths:
if not path.exists():
failures.append(f"missing: {path}")
continue
head = path.read_bytes()[: len(pointer_prefix)]
if head == pointer_prefix:
failures.append(f"LFS pointer was not hydrated: {path}")

if failures:
raise SystemExit("\n".join(failures))
print(f"Verified {len(required_paths)} hydrated CI LFS artifact files.")
PY

- name: Setup Rust
if: matrix.lane == 'rust-enabled'
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy

- name: Cache cargo build
if: matrix.lane == 'rust-enabled'
uses: actions/cache@v5
with:
path: |
Expand All @@ -157,86 +71,10 @@ jobs:
path: |
~/.cache/uv
.venv
key: uv-venv-${{ runner.os }}-py311-${{ matrix.lane }}-${{ hashFiles('pyproject.toml', 'uv.lock') }}
key: uv-venv-${{ runner.os }}-py311-${{ hashFiles('pyproject.toml', 'uv.lock') }}
restore-keys: |
uv-venv-${{ runner.os }}-py311-${{ matrix.lane }}-
uv-venv-${{ runner.os }}-py311-
uv-venv-

# Sync environment from lock if present (fast; no network if cached)
- name: Sync deps (locked if available)
shell: bash
run: |
if [[ -f uv.lock ]]; then
if [[ "${{ matrix.lane }}" == "rust-enabled" ]]; then
uv sync --extra dev --extra rust --frozen --no-install-package s2and-rust
else
uv sync --extra dev --frozen
fi
else
# No lock present; resolve once, then install
if [[ "${{ matrix.lane }}" == "rust-enabled" ]]; then
uv sync --extra dev --extra rust --no-install-package s2and-rust
else
uv sync --extra dev
fi
fi

# Build/install Rust extension for parity tests
- name: Build Rust extension
if: matrix.lane == 'rust-enabled'
run: uv run --with maturin maturin develop -m s2and_rust/Cargo.toml

- name: "Rust artifact guardrail: default incremental linker"
if: matrix.lane == 'rust-enabled'
run: uv run pytest -q tests/test_incremental_linking_default_artifact.py

- name: "Rust parity guardrail: feature parity"
if: matrix.lane == 'rust-enabled'
run: uv run pytest -q tests/test_feature_port_parity.py

- name: "Rust parity guardrail: signature preprocess parity"
if: matrix.lane == 'rust-enabled'
run: uv run pytest -q tests/test_rust_signature_preprocess.py

- name: "Rust parity guardrail: batch chunking/fallback parity"
if: matrix.lane == 'rust-enabled'
run: uv run pytest -q tests/test_rust_batch_chunking.py

# Type checking (ty with tuned migration rules)
- name: ty (s2and)
run: |
uv run ty check s2and \
--ignore unresolved-import \
--ignore unused-type-ignore-comment \
--ignore possibly-missing-attribute \
--ignore unresolved-global
- name: ty (scripts)
shell: bash
run: |
shopt -s nullglob
files=(scripts/*.py)
if (( ${#files[@]} )); then
uv run ty check "${files[@]}" \
--ignore unresolved-import \
--ignore unused-type-ignore-comment \
--ignore possibly-missing-attribute \
--ignore unresolved-global \
--ignore unresolved-reference \
--ignore unresolved-attribute
fi

- name: pytest (coverage, py-only)
if: matrix.lane == 'py-only'
env:
# keep startup lean; avoid user-level plugins on hosted runners
S2AND_BACKEND: python
run: |
uv run pytest tests/ \
--cov=s2and --cov-report=term-missing --cov-fail-under=40

- name: pytest (coverage, rust-enabled)
if: matrix.lane == 'rust-enabled'
run: |
uv run pytest tests/ \
--cov=s2and --cov-report=term-missing --cov-fail-under=40
- name: Run shared typecheck-and-test policy
run: uv run --no-project python scripts/run_ci_locally.py typecheck-and-test
Loading
Loading