Skip to content

Commit 0e8b39b

Browse files
jordanpadamsclaude
andcommitted
Fix superseded version detection for missing bundles and collections
Queries now fetch all products (not just found_in_registry=false) so that version ordering is determined across the full set. Python filters to missing rows after annotating superseded status, ensuring a missing LIDVID is correctly marked superseded when a higher version exists in the registry. Also adds CSV headers to output files and skips header rows in count aggregation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent c035e13 commit 0e8b39b

3 files changed

Lines changed: 46 additions & 21 deletions

File tree

conf/status/missing_bundles_per_node.json

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
{
3-
"_source": ["node", "lidvid", "product_class"],
3+
"_source": ["node", "lidvid", "product_class", "found_in_registry"],
44
"size": 10000,
55
"query": {
66
"bool": {
@@ -9,11 +9,6 @@
99
"match_phrase": {
1010
"product_class": "Product_Bundle"
1111
}
12-
},
13-
{
14-
"match_phrase": {
15-
"found_in_registry": "false"
16-
}
1712
}
1813
]
1914
}

conf/status/missing_collections_per_node.json

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
{
3-
"_source": ["node", "lidvid", "product_class"],
3+
"_source": ["node", "lidvid", "product_class", "found_in_registry"],
44
"size": 10000,
55
"query": {
66
"bool": {
@@ -9,11 +9,6 @@
99
"match_phrase": {
1010
"product_class": "Product_Collection"
1111
}
12-
},
13-
{
14-
"match_phrase": {
15-
"found_in_registry": "false"
16-
}
1712
}
1813
]
1914
}

scripts/generate_registry_status_reports.py

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,9 @@ def run_query(query_file: Path, endpoint: str) -> dict[str, Any]:
108108
return json.loads(result.stdout)
109109

110110

111-
def extract_rows(data: dict[str, Any], include_harvest_date: bool = False) -> list[tuple]:
111+
def extract_rows(
112+
data: dict[str, Any], include_harvest_date: bool = False, include_found_in_registry: bool = False
113+
) -> list[tuple]:
112114
"""Extract result rows from an OpenSearch query response."""
113115
rows = []
114116
for hit in data.get("hits", {}).get("hits", []):
@@ -135,16 +137,23 @@ def extract_rows(data: dict[str, Any], include_harvest_date: bool = False) -> li
135137
if isinstance(harvest_date, list):
136138
harvest_date = harvest_date[0] if harvest_date else ""
137139
rows.append((node, lidvid, product_class, harvest_date))
140+
elif include_found_in_registry:
141+
found = source.get("found_in_registry", "")
142+
if isinstance(found, list):
143+
found = found[0] if found else ""
144+
rows.append((node, lidvid, product_class, str(found).lower()))
138145
else:
139146
rows.append((node, lidvid, product_class))
140147

141148
return rows
142149

143150

144-
def write_rows_to_csv(rows: list[tuple], output_file: Path) -> int:
151+
def write_rows_to_csv(rows: list[tuple], output_file: Path, header: tuple | None = None) -> int:
145152
"""Write rows to a CSV file. Returns the number of rows written."""
146153
with open(output_file, "w", newline="") as csvfile:
147154
writer = csv.writer(csvfile)
155+
if header:
156+
writer.writerow(header)
148157
for row in rows:
149158
writer.writerow(row)
150159
return len(rows)
@@ -157,9 +166,13 @@ def annotate_version_status(rows: list[tuple]) -> list[tuple]:
157166
``urn:nasa:pds:<lid>::<major>.<minor>``. Version comparison is numeric so
158167
that e.g. ``3.9 < 3.13``.
159168
169+
Rows must include ``found_in_registry`` as the fourth element (index 3).
170+
The highest-versioned LIDVID across *all* rows (missing or not) for each LID
171+
determines the superseded flag. A row is superseded if a higher version
172+
exists anywhere in the full set.
173+
160174
Returns a new list of rows with an additional ``superseded`` column appended
161-
(string ``"true"`` or ``"false"``). The highest-versioned row per LID gets
162-
``"false"``; all others get ``"true"``.
175+
(string ``"true"`` or ``"false"``).
163176
"""
164177
by_lid: dict[str, list[tuple[tuple[int, ...], int]]] = defaultdict(list)
165178

@@ -186,6 +199,21 @@ def annotate_version_status(rows: list[tuple]) -> list[tuple]:
186199
return [row + ("true" if idx in superseded_indices else "false",) for idx, row in enumerate(rows)]
187200

188201

202+
def filter_missing_rows(rows: list[tuple]) -> list[tuple]:
203+
"""Filter rows to only those where found_in_registry is false.
204+
205+
Expects rows in the form (node, lidvid, product_class, found_in_registry, superseded).
206+
Returns rows with the found_in_registry column removed, preserving the superseded column.
207+
"""
208+
result = []
209+
for row in rows:
210+
# found_in_registry is at index 3; superseded is at index 4
211+
found = str(row[3]).lower()
212+
if found != "true":
213+
result.append(row[:3] + row[4:])
214+
return result
215+
216+
189217
def _count_by_node(csv_path: Path, superseded: bool | None = None) -> dict[str, int]:
190218
"""Return a node→count mapping from a CSV file (node is the first column).
191219
@@ -198,7 +226,7 @@ def _count_by_node(csv_path: Path, superseded: bool | None = None) -> dict[str,
198226
if csv_path.exists():
199227
with open(csv_path, "r") as f:
200228
for row in csv.reader(f):
201-
if not row:
229+
if not row or row[0] == "node":
202230
continue
203231
if superseded is not None:
204232
if len(row) < 4:
@@ -535,13 +563,20 @@ def main() -> int:
535563
try:
536564
print_info(f"Querying for {description}...")
537565
data = run_query(query_file, endpoint)
538-
rows = extract_rows(data, include_harvest_date)
566+
rows = extract_rows(data, include_harvest_date, include_found_in_registry=split_versions)
539567

540568
if split_versions:
541-
# Annotate each row with a superseded column before writing
569+
# Annotate using all returned rows (including found_in_registry=true) so that
570+
# version ordering is determined across the full set, then filter to missing only.
542571
rows = annotate_version_status(rows)
543-
544-
count = write_rows_to_csv(rows, output_file)
572+
rows = filter_missing_rows(rows)
573+
header = ("node", "lidvid", "product_class", "superseded")
574+
elif include_harvest_date:
575+
header = ("node", "lidvid", "product_class", "harvest_date")
576+
else:
577+
header = ("node", "lidvid", "product_class")
578+
579+
count = write_rows_to_csv(rows, output_file, header=header)
545580
print_info(f" → {output_file.name} ({count} records)")
546581
output_files.append(output_file)
547582

0 commit comments

Comments
 (0)