Summary
Match test files and functions to existing spec files and scenarios by naming convention. Annotates draft specs with inferred traceability links and enriches specleft status output with convention-matched entries.
Depends on: #124, #133, #134
New file
src/specleft/discovery/traceability.py
from specleft.discovery.models import DiscoveredItem
from specleft.schema import SpecsConfig
@dataclass(frozen=True)
class TraceabilityLink:
test_file: Path
test_function: str
spec_file: Path
scenario_id: str
match_kind: str # "filename" | "function" | "both"
confidence: float
def infer_traceability(
discovered: list[DiscoveredItem],
specs: SpecsConfig,
) -> list[TraceabilityLink]:
"""
Pure function: accepts pre-loaded specs rather than resolving internally.
Caller is responsible for loading SpecsConfig from the correct directory.
This keeps the discovery package decoupled from spec resolution.
Does not scan .specleft/specs/_discovered/ — caller should load specs
from resolve_specs_dir() which excludes underscore-prefixed directories.
"""
Matching algorithm
Step 1 — Filename match
Normalise both sides (replace -, _ with space, strip test_ prefix from test filename stem):
.specleft/specs/user-authentication.md → "user authentication"
tests/test_user_authentication.py → "user authentication"
Exact normalised match = filename link.
Step 2 — Function match within a filename-matched pair
Normalise scenario slug and function name (strip test_, replace _ with space):
Scenario: valid-credentials → "valid credentials"
def test_valid_credentials() → "valid credentials"
- Exact match →
confidence=0.9, match_kind="both"
- Common prefix >=60% of shorter string →
confidence=0.6, match_kind="function"
Step 3 — Annotate draft specs
For matched scenarios, add a frontmatter block to the generated markdown:
---
linked_tests:
- file: tests/test_user_authentication.py
function: test_valid_credentials
confidence: 0.9
---
Integration with specleft status
Update src/specleft/commands/status.py:
- After the existing
_index_specleft_tests() check, if a scenario has no decorator-based match, attempt convention-based lookup via infer_traceability()
- Pass pre-loaded
SpecsConfig — do not re-resolve specs internally
- If a convention match is found, set
match_kind: "convention" in the status entry
- Table output: show
✓ (convention) instead of ✓ for convention-matched scenarios
Acceptance criteria
Summary
Match test files and functions to existing spec files and scenarios by naming convention. Annotates draft specs with inferred traceability links and enriches
specleft statusoutput with convention-matched entries.Depends on: #124, #133, #134
New file
src/specleft/discovery/traceability.pyMatching algorithm
Step 1 — Filename match
Normalise both sides (replace
-,_with space, striptest_prefix from test filename stem):Exact normalised match = filename link.
Step 2 — Function match within a filename-matched pair
Normalise scenario slug and function name (strip
test_, replace_with space):confidence=0.9,match_kind="both"confidence=0.6,match_kind="function"Step 3 — Annotate draft specs
For matched scenarios, add a frontmatter block to the generated markdown:
Integration with
specleft statusUpdate
src/specleft/commands/status.py:_index_specleft_tests()check, if a scenario has no decorator-based match, attempt convention-based lookup viainfer_traceability()SpecsConfig— do not re-resolve specs internallymatch_kind: "convention"in the status entry✓ (convention)instead of✓for convention-matched scenariosAcceptance criteria
tests/test_user_authentication.py::test_valid_credentialslinks to.specleft/specs/user-authentication.mdscenariovalid-credentialstests/test_payment.pydoes not link to.specleft/specs/user-authentication.md(no false positives)infer_traceability()acceptsSpecsConfigdirectly (dependency injection, not path resolution)infer_traceability()returns[](not an error) whenSpecsConfighas no features.specleft/specs/_discovered/files are excluded (caller loads specs fromresolve_specs_dir()which skips_-prefixed dirs)specleft statustable shows(convention)tag for convention-matched scenariostests/discovery/test_traceability.pyusing fixture spec files and test filesfeatures/feature-spec-discovery.mdto cover the functionality introduced by this issue