Spaces:
Configuration error
Phase 3 β Documentation sync: TDD evidence
Date: 2026-08-02
Branch: develop
Checkpoints: c682851 (RED), 1becdc7 (GREEN)
Environment: conda env cv-screener (D:/Anaconda/envs/cv-screener/python.exe)
1. Source plan
No *.plan.md was supplied. The work was driven by the Phase 3 Audit Report
pasted into the session, whose Β§8 listed three documentation updates required by
the project Definition of Done (task.md lines 7β12: ".env.example terbarui",
"README/CHANGELOG terbarui").
The audit was treated as untrusted input and verified before use. Two of its claims did not survive checking, and one defect it never mentioned was found β see Β§6.
2. User journeys
- As a reviewer landing on the repository, I want the README's API table to list every endpoint the service actually serves, so that I can exercise the full surface without reading the router source.
- As a new contributor, I want
.env.exampleto name every setting I am allowed to configure, so that I do not discover a required knob by readingconfig.py. - As an operator following the quickstart, I want the documented database
image to be one the migrations can actually run against, so that
alembic upgrade headdoes not fail on the first revision. - As a maintainer, I want documentation drift to fail a test on the commit that introduces it, rather than surfacing in an audit weeks later.
3. Task report
Task 1 β Establish the real baseline
The audit claimed 541 unit tests passing. The first run showed 13 collection errors instead.
$ python -m pytest tests/unit/ -q
ModuleNotFoundError: No module named 'app'
...
ModuleNotFoundError: No module named 'pgvector'
!!!!!! Interrupted: 13 errors during collection !!!!!!
Root cause was environment, not code: the default python on PATH is base
Anaconda, which has neither the project installed nor pgvector/pytest-asyncio.
The project's own conda environment resolves it.
$ D:/Anaconda/envs/cv-screener/python.exe -m pytest tests/unit/ -p no:cacheprovider
541 passed, 172 warnings in 10.17s
Guaranteed: the audit's baseline is reproducible in the correct interpreter. The reported failure was a false alarm from the wrong interpreter.
Task 2 β Write the drift guards (RED)
Added tests/unit/test_docs_sync.py: six checks comparing the committed
documents against the application's own introspection β the OpenAPI schema and
Settings.model_fields. Modelled on the existing
tests/unit/test_migration_coverage.py, including its anti-vacuous guards.
$ D:/Anaconda/envs/cv-screener/python.exe -m pytest tests/unit/test_docs_sync.py -p no:cacheprovider
E AssertionError: routes served by the application but missing from the
README.md API table: ['GET /api/v1/jobs', 'GET /api/v1/rubrics/templates',
'GET /api/v1/rubrics/templates/{template_key}',
'GET /api/v1/rubrics/{rubric_version_id}', 'POST /api/v1/rubrics',
'POST /api/v1/rubrics/templates/{template_key}:instantiate',
'POST /api/v1/rubrics/{rubric_version_id}/approve',
'POST /api/v1/rubrics/{rubric_version_id}/requirements',
'POST /api/v1/rubrics/{rubric_version_id}/score:preview',
'POST /api/v1/rubrics/{rubric_version_id}/versions',
'POST /api/v1/search/candidates', 'POST /api/v1/search/similar']
E AssertionError: settings configurable via the environment but absent from
.env.example: ['ALLOWED_UPLOAD_MIME_TYPES', 'JWT_ALGORITHMS']
2 failed, 4 passed in 3.05s
RED is genuine: both failures name the specific missing items, and the four passing checks are the anti-vacuous guards plus the two inverse (no-stale-entry) directions, which were already satisfied.
Task 3 β Fix the drift (GREEN)
$ D:/Anaconda/envs/cv-screener/python.exe -m pytest tests/unit/test_docs_sync.py -p no:cacheprovider
6 passed in 3.26s
$ D:/Anaconda/envs/cv-screener/python.exe -m pytest tests/ -p no:cacheprovider
582 passed, 237 warnings in 28.14s
$ D:/Anaconda/envs/cv-screener/python.exe -m ruff check serving/app tests
All checks passed!
Guaranteed: the README documents all 20 served routes, .env.example covers
every configurable setting, and no regression was introduced.
4. Test specification
| # | What is guaranteed | Test | Type | Result | Evidence |
|---|---|---|---|---|---|
| 1 | The README API table parses β the coverage checks are not vacuous | test_docs_sync.py::test_the_readme_api_table_is_parsed_at_all |
unit | PASS | pytest tests/unit/test_docs_sync.py |
| 2 | .env.example parses β the coverage check is not vacuous |
test_docs_sync.py::test_the_env_example_is_parsed_at_all |
unit | PASS | same |
| 3 | Every route the app serves appears in the README API table | test_docs_sync.py::test_readme_documents_every_registered_route |
unit | RED β PASS | 12 routes named on failure |
| 4 | The README lists no route the app does not serve | test_docs_sync.py::test_the_readme_api_table_lists_no_route_that_does_not_exist |
unit | PASS | guards the inverse drift |
| 5 | Every configurable Settings field appears in .env.example |
test_docs_sync.py::test_env_example_documents_every_configurable_setting |
unit | RED β PASS | 2 settings named on failure |
| 6 | .env.example declares no variable the app ignores |
test_docs_sync.py::test_env_example_declares_no_variable_the_application_ignores |
unit | PASS | guards silent no-op keys |
| 7 | An approved rubric cannot be mutated (e2e, real database) | tests/integration/β¦::test_preview_on_a_superseded_rubric_returns_409 |
integration | PASS | pytest tests/integration/ -k superseded |
| 8 | A draft rubric returns 409 on scoring (e2e, real database) | tests/integration/β¦::test_preview_on_a_draft_rubric_returns_409 |
integration | PASS | pytest tests/integration/ -k draft_rubric |
Rows 7β8 are pre-existing tests, re-run here to substantiate the two Phase 3
verification items checked off in task.md.
5. Coverage
$ D:/Anaconda/envs/cv-screener/python.exe -m pytest tests/ --cov=serving/app --cov-report=term
TOTAL 2395 225 91%
Required test coverage of 80.0% reached. Total coverage: 90.61%
582 tests (547 unit, 35 integration), 90.61% β above the 80% floor. The audit's figure of 86.10% was stale and has been corrected in the README to the measured value.
6. Findings that contradicted the audit
The audit was verified rather than trusted. Three corrections:
It under-counted the README drift. The audit reported only rubric and template endpoints as missing. The guard found 12 missing, including
POST /api/v1/search/candidates,POST /api/v1/search/similar, andGET /api/v1/jobs, none of which the audit mentioned.It missed a functional defect in the quickstart. The README instructed operators to start
postgres:16-alpine. The first migration (20260731_0930_add_resume_chunks_with_pgvector) executesCREATE EXTENSION IF NOT EXISTS vector, which that image cannot satisfy:$ docker exec talentlens-pg psql -U postgres -tAc \ "SELECT count(*) FROM pg_available_extensions WHERE name='vector'" 0Anyone following the quickstart hits a migration failure. Corrected to
pgvector/pgvector:pg16, which is what the test container already used.Two further stale claims the audit did not list. The README stated sanitization was "not yet implemented" β
serving/app/services/sanitize.pyexists with 21 passing tests β and the Not-built-yet column still listed "Alembic migrations" and "Prompt-injection sanitization", both of which ship.
7. Known gaps
task.mdis gitignored (.gitignore:10) and untracked. Its Phase 3 section was updated locally per audit Β§8, but that change is not part of either checkpoint commit and will not appear in the repository. This is the repository's existing convention, not a change made here.- "JD β approved rubric in under 3 minutes" remains unverified. It needs a
live LLM provider key and manual timing. It is left unchecked in
task.mdrather than claimed. - The route guard checks presence, not accuracy. A row whose description is wrong still passes; only the method and path are compared.
.gitignorecarries an unrelated uncommitted edit (.agent) that predates this session. Left untouched.- Skill-taxonomy linking, the rubric editor UI, and golden-set labelling remain blocked on external dependencies, exactly as the audit stated. Nothing here changes that.