Repository navigation
Bedrock model cards: accept the new Legacy period and EOL shapes, tighten fail-closed checks - #107
Merged
Merged
Conversation
… cards The scheduled feed refresh failed on 2026-09-28 and 2026-10-05 (issue 106). The Claude Opus 5.5 and Sonnet 5.5 cards say "Legacy period: 6 months" without "at least", which the card parser rejected. With that fixed, a live run then stopped on the GPT-6.1 Sol card: "Model EOL date: Not announced.". "at least" is now optional in the Legacy period check. The period is only validated, never used for a date, so no feed value changes. "Not announced" (with or without the trailing period) is treated exactly like N/A. Near-miss shapes such as "Not yet announced", "TBA", "six months" and "6 weeks" still fail closed. Verified: npm test passes; live provider and distributor --check runs both complete (exit 3, changes pending) instead of exit 1. Implemented directly by Claude rather than delegated to Codex: two regex changes plus tests, below the handoff threshold.
Codex review of PR 107: once "Not announced." passed as N/A, a card with that EOL and a regional "Legacy (EOL: YYYY-MM-DD)" cell lost the regional date. It skipped as "no lifecycle fields" (region cells were scanned after that skip), skipped as "no day-precision date", or with a floor emitted a tentative active record that dropped the regional shutdown and legacy status. Before PR 107 that card threw. The same gap already existed for N/A and for "No sooner than" tentative EOLs. Region cells are now scanned before any skip, and a regional EOL with no exact Model EOL date throws. Exact-date agreement is unchanged. The live distributor --check diff is byte-identical before and after this change, so no current card has that shape. Not fixed (pre-existing, out of scope): the Legacy period check accepts "1 days" and "0 days"; an exact EOL earlier than the "EOL no sooner than" floor is not rejected.
Pass 1 Low and missing check, pass 2 Lows: - Legacy period number and unit must agree and be non-zero: "1 month", "1 day", "N months|days" for N >= 2. "1 days", "2 month", "0 days" and zero-padded numbers now fail closed. - An exact Model EOL date (plain or Legacy:) earlier than a day-precision "EOL no sooner than" floor now throws. A month-only floor is still ignored, as before. - Regional "Legacy (EOL: ...)" cells are validated before the "no model ids" skip, so a malformed cell on an all-N/A card fails closed. A valid regional cell on such a card still skips: there is no id to record. - Tests pin the intended error precedence (malformed regional cell is reported before an invalid Model EOL date), and cover Legacy: EOL plus matching regional cells. The live distributor --check diff is byte-identical before and after.
Codex review pass 3 of PR 107: - Medium: only cells starting with the exact text "Legacy (EOL:" were validated, so "legacy (EOL: ...)", "Legacy (EOL : ...)" and "Legacy(EOL: ...)" bypassed the regional check and could yield an active record. Cells are now detected case- and space-insensitively, then must match the exact grammar or the card fails closed. - Low: the Legacy period number had no upper bound. It is now one to three digits. Live distributor --check diff is byte-identical before and after.
…grammar Codex review pass 4 of PR 107 raised two opposing P2s about the regional EOL detector: it still missed shapes such as "US East (N. Virginia): Legacy (EOL: 2028-01-01)" and "Legacy (End of life: ...)" (silent loss), while it could also throw on a glossary cell like "Legacy (EOL policy)". An inventory of all 133 live cards on 2026-10-05 settles it. Regional status cells only hold yes/no icons, "Supported", "Not supported" and "Legacy (EOL: YYYY-MM-DD)"; no cell outside the regional tables mentions legacy or EOL; and the regional tables use three different headers, so scoping by header would miss some. Any td that mentions legacy, EOL or end of life must now match the exact regional grammar, or the card fails closed. The glossary-cell false positive is accepted deliberately: nothing live has one, and a stopped refresh is preferred to a lost shutdown date. Live distributor --check diff is byte-identical before and after.
… cells Codex review pass 5 of PR 107: - P3 regression from ce945bb: a valid id such as vendor.legacy-model-v1:0 or vendor.eol-model-v1:0 made its own Model ID cell look like a regional status and stopped the refresh. Cells whose text is only Bedrock ids (Model ID, Geo and Global inference ID) are now skipped. - P2: a regional status in img alt, title or aria-label text, in a row header th, or split by inline markup ("Leg<span>acy</span>") bypassed detection. All of those are now read. - P3: "end of lifecycle", "end of support", "E.O.L." and "retired" are now detected alongside legacy, EOL and end of life. A detected cell still has to be exactly "Legacy (EOL: YYYY-MM-DD)" in its visible text, or the card fails closed. The live distributor --check diff over all 133 cards is byte-identical before and after, so no live card uses any of the newly detected shapes.
…e word check Codex review pass 6 of PR 107 found three regressions and one gap in ff6b70e's detector: - Digits and underscores counted as word boundaries, so "us.vendor.eol2- v1:0 N/A", "legacy_model" ids and "EOL2" headers threw. Boundaries now exclude [a-z0-9_], and Bedrock id tokens (first segment of two or more characters, so "E.O.L." is not mistaken for one) and URL tokens are removed before the check. - The attribute regex found "title" inside data-title and "alt=" inside another attribute's quoted value. Attributes are now tokenized per tag, which also reads unquoted alt/title/aria-label values (the gap). - Visible text was entity-decoded twice, so "l&#101;gacy" read as "legacy". Each candidate is now decoded exactly once. Live distributor --check diff over all 133 cards is byte-identical.
…butes Codex review pass 7 of PR 107 (no regressions; one bug): the per-tag matcher stopped at the first >, so <img alt="Legacy > Active"> cut the alt value short and the lifecycle word was missed, where c1f3e08's parent had thrown. Tags are now matched quote-aware. Live distributor --check diff over all 133 cards is byte-identical.
…ifecycle word check CodeQL js/incomplete-multi-character-sanitization (alert 19) flagged the tag-stripped joined text, since <scr<x>ipt> collapses to <script. The text is only matched against BEDROCK_LIFECYCLE_WORD and never rendered, but any leftover < or > is now replaced with a space so the alert does not stand. Word detection is unchanged; live distributor --check diff is identical.
9d9defa did not clear CodeQL js/incomplete-multi-character-sanitization (new alert 20 on the same line): a later replace of < and > is not recognised as sanitising when entity decoding runs afterwards. The joined text is now built by splitting the cell HTML on tags, decoding each text segment once, and joining them. Same text for detection; no tag-stripping replace remains. Live distributor --check diff identical.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the scheduled feed-refresh failures logged on #106 (runs 36417815597 and 37309158163), and closes every finding from two Codex adversarial review passes.
Cause
Legacy period: 6 months. The parser requiredat least N months|days.Model EOL date: Not announced.Changes (
refresh/distributors.mjs)1 month,1 day,N months|daysfor N ≥ 2).BEDROCK_CARD_NO_EOLtreatsNot announced/Not announced.exactly likeN/A.Legacy (EOL: …)cells are validated before any skip. A regional EOL with no exact Model EOL date now throws (review pass 1, High: it was silently dropped).EOL no sooner thanfloor now throws.Tests (
refresh/test/run.mjs)N/A,Not announced., tentative, and missing EOLs, alone, with a launch date, and with a floor.Legacy:EOL with matching regional cells; EOL-before-floor; period grammar.Verification
npm testpasses.refresh.mjs --checkfor providers and foraws-bedrock,vertex-ai,azure-ai-foundrycomplete with exit 3 (changes pending), not exit 1. The live distributor diff is byte-identical across all three commits.🤖 Generated with Claude Code