@@ -142,43 +142,50 @@ def get_file_picker_prompt(
142142 records contributor-to-employer/organization mappings.
143143 """
144144 return f"""
145- Your task is to identify the file that records which organization or employer
146- contributors represent when contributing to this repository.
145+ Identify the repository file that matches the criteria below.
147146
148147 <repository_url>
149148 { repo_url }
150149 </repository_url>
151150
152151 <what_to_find>
153- The target file records contributor-to-employer/organization mappings.
154-
155- Contributors may be identified by name, email address, or GitHub username.
156- Organizations may be identified by their name, domain,
157- or contact email address.
158-
159- There is no standard filename or file format. The file may be plain text,
160- CSV, YAML, JSON, Markdown, or another text-based format.
161-
162- Judge candidates primarily by their contents. Filenames are only hints.
152+ Find the file that explicitly records contributor affiliations: which
153+ organization or employer a contributor belongs to.
154+
155+ The mapping must be stated by the file, for example:
156+ - an organization, company, employer, or affiliation field on each contributor
157+ - contributors grouped under the organization they belong to
158+ - explicit domain/email-pattern rules that the file defines for assigning
159+ contributors to organizations
163160 </what_to_find>
164161
165162 <what_to_reject>
166- Reject candidates whose preview shows:
167- - Source code or scripts (for example, shebangs, imports, or function/class definitions)
168- - Generic contributor or author credits
169- - Governance files that lack organization or employer information
163+ Reject candidates whose preview does not explicitly associate contributors
164+ with organizations, including:
165+ - Lists of names, emails, or usernames with no stated organization
166+ (e.g. AUTHORS, CONTRIBUTORS, CREDITS).
167+ - Identity or alias mappings such as .mailmap.
168+ - Governance or ownership files that name people but not their employer
169+ (e.g. OWNERS, CODEOWNERS, MAINTAINERS without organization information).
170+ - Source code, scripts, or configuration files.
171+
172+ Email addresses and email domains alone do not make a file a match, unless
173+ the file explicitly defines those domains or patterns as affiliation rules.
170174 </what_to_reject>
171175
172176 <candidates>
173- Each candidate includes its repository-relative path and a preview from the
174- beginning of the file. The preview is only a partial view of the file.
177+ Each candidate includes its repository-relative path and a preview from
178+ the beginning of the file. The preview is only a partial view of the file.
175179
180+ Base your decision only on the provided preview.
176181 { candidates_with_previews }
177182 </candidates>
178183
179184 <rules>
185+ - Judge candidates by their content, not their filename.
180186 - Return the repository-relative path exactly as shown in the candidates.
181187 - If no candidate matches, return {{"error": "not_found"}}.
188+ - Prefer precision over recall. The wrong file is worse than no file.
182189 </rules>
183190
184191 <output_format>
@@ -267,11 +274,10 @@ def get_extraction_prompt(self, content_to_analyze: str) -> str:
267274 """
268275
269276 return f"""
270- Your task is to extract contributor-to-employer/organization mappings from the file content below.
271-
272277 <what_to_extract>
273278
274- Identify contributor-to-organization mappings in the file content.
279+ Extract, per person, the organization or employer the file explicitly
280+ assigns to each contributor.
275281
276282 Emit one entry per contributor-organization pair.
277283
@@ -282,12 +288,19 @@ def get_extraction_prompt(self, content_to_analyze: str) -> str:
282288 - Reproduce identifiers as written. Do not normalize, reformat, or repair them.
283289
284290 Organization:
285- - Provide the organization name when the file gives one.
286- - Provide the organization's primary domain: use a domain present in the
287- file, otherwise infer it from the organization name when you are confident.
288- - If the file marks a contributor as not employed / independent / unaffiliated
289- / personal / no organization, set "isUnaffiliated" to true and set
290- "domain" to "unknown". Do not invent a company or domain for these.
291+ - Only record an organization the file explicitly ties to the contributor.
292+ Do not infer one from a plain email, email domain, username, or repo/project name.
293+ It is valid to use an email/domain pattern only when the file itself explicitly
294+ defines that pattern as an affiliation rule.
295+ - name: the organization name the file states, else null.
296+ - domain: use a domain the file states; otherwise infer it from the stated
297+ organization name only when confident (e.g. "Google" -> google.com), else null.
298+ Never infer a domain from an email.
299+ - isUnaffiliated: set true only when the file explicitly marks the person as
300+ independent / unaffiliated / personal / no employer — not as a fallback when
301+ the organization is merely missing. When true, set name and domain to null.
302+ - If the file states neither an organization nor explicit unaffiliation for a
303+ person, do not emit a row for them.
291304
292305 Time period (only when the file states it):
293306 - "dateStart" and "dateEnd" as ISO dates (YYYY-MM-DD).
@@ -321,7 +334,7 @@ def get_extraction_prompt(self, content_to_analyze: str) -> str:
321334 }},
322335 "organization": {{
323336 "name": "... or null",
324- "domain": "...",
337+ "domain": "... or null ",
325338 "dateStart": "YYYY-MM-DD or null",
326339 "dateEnd": "YYYY-MM-DD or null",
327340 "isUnaffiliated": false
@@ -384,8 +397,6 @@ def group_parse_rows(
384397 organization = row .organization
385398 is_unaffiliated = organization .is_unaffiliated
386399 domain = cls ._strip (organization .domain )
387- if domain and domain .lower () in {"unknown" , "no@organization.net" }:
388- is_unaffiliated = True
389400
390401 if is_unaffiliated :
391402 stint = AffiliationOrganizationStint (
0 commit comments