Code / scripts/ml_training/essay_scoring/features/feature_input.py
scripts/ml_training/essay_scoring/features/feature_input.py
1
"""Label-free inputs for ledger-first feature materialization.
2
3
Feature extraction needs source text and governed prompt authority, never
4
training targets or dataset-specific score columns. This module makes that
5
boundary explicit so every producer gives the shared pipeline the same
6
materialization inputs.
7
"""
8
9
from __future__ import annotations
10
11
from dataclasses import dataclass
12
13
from ..datasets.canonical_research_input import (
14
CanonicalResearchEssayInputRow,
15
)
16
from ..datasets.prompt_authority import (
17
SemanticPromptAuthority,
18
semantic_prompt_authority_for_record,
19
validate_semantic_prompt_authority,
20
)
21
from ..datasets.records import EssayRecord
22
23
24
@dataclass(frozen=True)
25
class FeaturePipelineInput:
26
"""One immutable, label-free row accepted by ``FeaturePipeline``.
27
28
``prompt_authority`` carries the governed semantic prompt text and its
29
provenance. The mirrored prompt fields make the exact request inputs
30
visible without making feature extraction depend on a training record.
31
"""
32
33
record_id: str
34
source_text: str
35
prompt_label: str
36
prompt_text: str
37
prompt_authority: SemanticPromptAuthority
38
39
def __post_init__(self) -> None:
40
"""Reject input rows whose visible fields differ from prompt authority."""
41
42
if not self.record_id.strip():
43
raise ValueError("Feature pipeline input requires a record_id.")
44
if not self.source_text.strip():
45
raise ValueError("Feature pipeline input requires source_text.")
46
validate_semantic_prompt_authority(self.prompt_authority)
47
if self.prompt_authority.record_id != self.record_id:
48
raise ValueError("Feature pipeline input record_id differs from prompt authority.")
49
if self.prompt_authority.prompt_label != self.prompt_label:
50
raise ValueError("Feature pipeline input prompt_label differs from prompt authority.")
51
if self.prompt_authority.prompt_text != self.prompt_text:
52
raise ValueError("Feature pipeline input prompt_text differs from prompt authority.")
53
54
55
def feature_pipeline_input_from_essay_record(record: EssayRecord) -> FeaturePipelineInput:
56
"""Project a current dataset row into the label-free materialization contract."""
57
58
prompt_authority = semantic_prompt_authority_for_record(record)
59
return FeaturePipelineInput(
60
record_id=record.record_id,
61
source_text=record.essay,
62
prompt_label=prompt_authority.prompt_label,
63
prompt_text=prompt_authority.prompt_text,
64
prompt_authority=prompt_authority,
65
)
66
67
68
def feature_pipeline_inputs_from_essay_records(
69
records: list[EssayRecord],
70
) -> list[FeaturePipelineInput]:
71
"""Project current dataset rows before they enter feature materialization."""
72
73
return [feature_pipeline_input_from_essay_record(record) for record in records]
74
75
76
def feature_pipeline_input_from_canonical_row(
77
row: CanonicalResearchEssayInputRow,
78
) -> FeaturePipelineInput:
79
"""Project one canonical essay row without consulting metadata or score labels."""
80
81
authority = SemanticPromptAuthority(
82
record_id=row.record_id,
83
prompt_label=row.prompt_authority_id,
84
prompt_id=row.prompt_authority_id,
85
prompt_title=row.prompt_authority_id,
86
prompt_text=row.prompt_text,
87
prompt_text_sha256=row.prompt_text_sha256,
88
authority_kind="canonical_research_input.v1",
89
source_id=row.dataset_id,
90
source_title=row.dataset_id,
91
source_uri="",
92
source_page=0,
93
source_document_sha256=row.source_artifact_sha256,
94
authority_origin="canonical_research_input.v1",
95
)
96
return feature_pipeline_input_from_canonical_row_with_authority(row=row, authority=authority)
97
98
99
def feature_pipeline_input_from_canonical_row_with_authority(
100
*,
101
row: CanonicalResearchEssayInputRow,
102
authority: SemanticPromptAuthority,
103
) -> FeaturePipelineInput:
104
"""Compose a canonical row only with its exact resolved prompt authority."""
105
106
validate_semantic_prompt_authority(authority)
107
if authority.record_id != row.record_id:
108
raise ValueError("canonical row record_id differs from resolved prompt authority")
109
if authority.prompt_id != row.prompt_authority_id:
110
raise ValueError("canonical row prompt authority ID differs from resolved authority")
111
if authority.prompt_text != row.prompt_text:
112
raise ValueError("canonical row prompt text differs from resolved prompt authority")
113
if authority.prompt_text_sha256 != row.prompt_text_sha256:
114
raise ValueError("canonical row prompt digest differs from resolved prompt authority")
115
return FeaturePipelineInput(
116
record_id=row.record_id,
117
source_text=row.essay_text,
118
prompt_label=authority.prompt_label,
119
prompt_text=row.prompt_text,
120
prompt_authority=authority,
121
)