Skip to content

v2026.09.25.003: OS end of life by build and edition, with Microsoft's dates - #4

Open
cdburgess75 wants to merge 1 commit into
fix/password-length-unknownfrom
fix/os-eol-by-edition
Open

cdburgess75 wants to merge 1 commit into
fix/password-length-unknownfrom
fix/os-eol-by-edition

Conversation

@cdburgess75

Copy link
Copy Markdown
Owner

Do not merge until the branch has had one real Windows run. Merging to main puts this on every endpoint, running as SYSTEM, within about 8 hours. It also moves security grades: more devices take the OS end-of-life -20. The test steps, and an impact query already checked against the PowerShell, are below.

This PR is stacked on #3, which is stacked on #2, which is stacked on #1. Its base is fix/password-length-unknown, so the diff shows only this change.

The bug

The Assessment Engine looked up os_eol by build number only, with one date per build. That value is printed in customer reports (bf/report.py) and on the device page. Since #2 it also drives the -20.

The dates were wrong. These are checked against Microsoft Learn; the sources are below.

Build Old table Microsoft, by edition
19045 (10 22H2) 2030-10-14 2025-10-14, every edition
22621 (11 22H2) 2027-10-12 Home/Pro 2024-10-08 · Ent/Edu 2025-10-14
22631 (11 23H2) 2028-10-10 Home/Pro 2025-11-11 · Ent/Edu 2026-11-10
26100 2029-10-14 11 24H2 Home/Pro 2026-10-13 · Ent/Edu 2027-10-12 · Enterprise LTSC 2024 2029-10-09 · IoT LTSC 2024 2034-10-10 · Server 2025 2034-11-14
22000 (11 21H2) 2026-10-14 Home/Pro 2023-10-10 · Ent/Edu 2024-10-08
19044 2026-10-13 10 21H2 Home/Pro 2023-06-13 · Ent/Edu 2024-06-11 · Enterprise LTSC 2021 2027-01-12 · IoT LTSC 2021 2032-01-13
17763 2029-01-09 10 1809 Home/Pro 2020-11-10 · Ent/Edu 2021-05-11 · LTSC 2019, IoT LTSC 2019, Server 2019 2029-01-09
14393 2027-01-12 10 1607 Home/Pro 2018-04-10 · Ent/Edu 2019-04-09 · 2016 LTSB and IoT 2016 LTSB 2026-10-13 · Server 2016 2027-01-12
10240 2025-10-14 10 1507 2017-05-09 · 2015 LTSB 2025-10-14
19041 / 19042 / 19043 2025-10-14 2021-12-14 / Home/Pro 2022-05-10, Ent/Edu 2023-05-09 / 2022-12-13
18362 2020-05-12 2020-12-08
15063 / 16299 / 17134 / 18363 Home/Pro date only Ent/Edu 2019-10-08 / 2020-10-13 / 2021-05-11 / 2022-05-10
9200 / 9600 2023-10-10 Windows 8 2016-01-12, 8.1 2023-01-10 · Server 2012 and 2012 R2 2023-10-10
25398 / 26200 / 28000 not in the table (Unknown) Server 23H2 2025-10-24 / 11 25H2 2027-10-12, 2028-10-10 / 11 26H1 2028-03-14, 2029-03-13

Bold dates have passed, and the old table showed them as supported. 7601, 10586 and 20348 were already right.

Sources. All are on Microsoft Learn:

How the dates were verified.

  • Two independent passes each read every date: one from the lifecycle pages, one from release-health. They agreed on every row.
  • I checked 26H1 and the 1511 announcement myself.
  • The lifecycle tables show each end date as the next day at 6:59:59 AM. The table uses the Patch Tuesday date, which is the date release-health shows.
  • One oddity: 1511 Enterprise/Education. Its lifecycle page and the 2017 announcement say 2017-10-10, but release-health lists 1511 updates up to 2018-04-10. I used the lifecycle date. Both have long passed.

Changes

  • New Get-OsEolDate -Caption -Build.
    • It is a pure helper next to ConvertTo-BiosDate, testable the same way.
    • It reads the edition family from $os.Caption, tested in this order:
      1. Server;
      2. LTSB/LTSC, split by IoT;
      3. the words Pro, Home or SE;
      4. Enterprise or Education.
    • The order matters. An LTSC caption also says Enterprise, and Pro Education follows Home/Pro; Microsoft's edition lists say so.
    • Enterprise/Education includes IoT Enterprise (GA channel) and Enterprise multi-session. Home/Pro includes Pro for Workstations and SE.
  • A caption it cannot place gets a date only when that date is true for every edition the machine could be. This covers a localized caption, or an edition the build doesn't ship as.
    • It considers the dates on the machine's own side of the client/server line.
    • If they all agree, it uses that date. If they have all passed, it uses the latest.
    • Otherwise os_eol is Unknown, which costs nothing.
    • This is ADR 0009 applied to edition detection: failing to read the edition can never cost points.
  • The engine calls it with $osName and $osBuild. The os_eol strings are byte-for-byte the same three forms, so Battlefield needs no change.
  • New ADR 0010 and a CONTEXT.md entry for "OS End of Life" record the ESU decision below.
  • Version v2026.09.25.003, changed in the same nine places as before, with entries in both changelogs. The diff adds no non-ASCII bytes and the AST parse shows 0 errors.

Decision: ESU-covered Windows 10 is end of life (ADR 0010)

A Windows 10 22H2 device reports END OF LIFE (since 2025-10-14) and takes the -20, whether or not it is enrolled in ESU. This was already how the table treated Windows 7, Server 2008 R2 and Server 2012/R2, which all had ESU. My reasons:

  • It is Microsoft's own position. Windows 10 reached end of support on 2025-10-14. ESU is a paid bridge with a fixed end, and it carries security fixes only.
  • ESU is a licence on one device, not a fact about the OS.
    • Microsoft documents slmgr /dlv with ESU activation IDs for commercial MAK activation.
    • It documents no local check for consumer ESU, and none for the Windows 365 and Azure grants, which need no key.
    • So a probe would score two identical devices differently, depending on how their ESU was bought.
  • An exemption would make the penalty depend on a probe. A device whose licence check failed would lose the 20 points. That is a collection failure moving the score, which ADR 0009 rules out.
  • Timing. Commercial ESU Year 1 ends on 2026-10-13, 18 days from now, so an exemption would expire about when it shipped. Only paid Year 2 and Year 3 licences would benefit.
  • Revisit if ParaTech sells ESU Year 2 to a customer. Then detect the documented activation ID, report it as its own field, and decide the score separately. Tell me if you want ESU treated differently.

Fleet impact: more devices take the -20

I could not count devices. The Battlefield database is only reachable on the server, and I did not use its credentials from here. Below is who flips, and when, followed by a read-only query that gives the per-device answer. The query is checked against the PowerShell; see Tests.

From the first run of this version (the old table said "Supported until"):

Takes the -20 Notes
Windows 10 22H2 (19045), every edition Likely the largest group. Includes ESU devices (ADR 0010).
Windows 11 22H2 (22621), every edition
Windows 11 23H2 (22631) Home/Pro Enterprise/Education stays supported until 2026-11-10.
Windows 11 21H2 (22000), Windows 10 21H2 (19044), GA editions The old table would have flipped these anyway, on 2026-10-14 and 2026-10-13.
Windows 10 1809 (17763) and 1607 (14393), GA editions LTSC 2019, 2016 LTSB and Server 2016/2019 keep their dates.
Windows Server 23H2 (25398) The old table did not know this build, so it was Unknown and never scored.

Then by calendar, with no new release:

Date Newly end of life
2026-10-13 (18 days away) Windows 11 24H2 Home/Pro (26100), and Windows 10 2016 LTSB (14393). The 24H2 group is probably big: every managed Pro box not yet on 25H2. Microsoft only auto-upgrades 24H2 Home/Pro devices that are not managed by IT. The way out is the small 25H2 enablement package (Learn).
2026-11-10 Windows 11 23H2 Enterprise/Education (22631)
2027-01-12 Windows 10 Enterprise LTSC 2021 (19044) and Server 2016 (14393). The old table had the same date for Server 2016.

Relief compared with the old table. On 2026-10-13 the old table would have ended every 19044 device. Enterprise LTSC 2021 now runs to 2027-01-12, and IoT LTSC 2021 to 2032-01-13.

Everything else only changes its date. This includes Server 2016/2019/2022/2025 and all builds that were already end of life.

The -20 is a measurement correction. Nothing changed on the endpoints, but the drop will show on the dashboard trend line, in the D/F attention flag and in any customer scorecard. It lands in the same place as #2's drop, so explain both before a scorecard goes out. As in #2, bf/alerts.py never reads os_eol or the score, so no new alerts or emails.

The impact query (read-only)

  • What it computes. For each device's latest stored run it recomputes os_eol under the old table and the new one. It uses the stored os field, which is "<Caption> (Build <n>)".
  • The change column reads newly EOL (-20), no longer EOL (+20), date changes, verdict same or unchanged.
  • The scores. It applies v2026.09.25.001: engine results reach the payload and the score #2's other two rules, BitLocker and Windows Update, as v2026.09.25.001: engine results reach the payload and the score #2's query did. score_before is the stack without this PR and score_after is with it, each with its grade. v2026.09.25.002: an unknown password length is not scored or reported as 0 #3's password change is not modeled; it can only raise scores.
  • The date. as_of defaults to today. Run it once with the day you expect to ship, and once with date '2026-10-14' to see the 24H2 wave.
  • Check the family column. Every 14393/17763/19044/26100 device should have the family you know it to be.
    • An LTSC or Server box with the wrong family means its caption is not what Get-OsEolDate expects.
    • An empty family means a caption it could not place, such as a localized one.
    • Tell me about either before merging.
  • A count instead of a list: wrap it as SELECT change, family, build, count(*) FROM (...) q GROUP BY 1, 2, 3 ORDER BY 1, 2, 3.
SQL (tables generated from ShellKnight.ps1)
-- ShellKnight v2026.09.25.003: what the edition-aware OS EOL lookup changes,
-- device by device, from each device's latest stored run. Read-only.
-- Set as_of to the day the new version will run (default: today).
-- Both tables are generated from ShellKnight.ps1: old = PR #3's head, new = this PR.
WITH params AS (SELECT current_date AS as_of),
new_eol(build, family, d) AS (VALUES
    ('7601','HomePro','2020-01-14'), ('7601','EntEdu','2020-01-14'), ('7601','Server','2020-01-14'), ('9200','HomePro','2016-01-12'),
    ('9200','EntEdu','2016-01-12'), ('9200','Server','2023-10-10'), ('9600','HomePro','2023-01-10'), ('9600','EntEdu','2023-01-10'),
    ('9600','Server','2023-10-10'), ('10240','HomePro','2017-05-09'), ('10240','EntEdu','2017-05-09'), ('10240','LTSC','2025-10-14'),
    ('10586','HomePro','2017-10-10'), ('10586','EntEdu','2017-10-10'), ('14393','HomePro','2018-04-10'), ('14393','EntEdu','2019-04-09'),
    ('14393','LTSC','2026-10-13'), ('14393','IoTLTSC','2026-10-13'), ('14393','Server','2027-01-12'), ('15063','HomePro','2018-10-09'),
    ('15063','EntEdu','2019-10-08'), ('16299','HomePro','2019-04-09'), ('16299','EntEdu','2020-10-13'), ('17134','HomePro','2019-11-12'),
    ('17134','EntEdu','2021-05-11'), ('17763','HomePro','2020-11-10'), ('17763','EntEdu','2021-05-11'), ('17763','LTSC','2029-01-09'),
    ('17763','IoTLTSC','2029-01-09'), ('17763','Server','2029-01-09'), ('18362','HomePro','2020-12-08'), ('18362','EntEdu','2020-12-08'),
    ('18363','HomePro','2021-05-11'), ('18363','EntEdu','2022-05-10'), ('19041','HomePro','2021-12-14'), ('19041','EntEdu','2021-12-14'),
    ('19042','HomePro','2022-05-10'), ('19042','EntEdu','2023-05-09'), ('19043','HomePro','2022-12-13'), ('19043','EntEdu','2022-12-13'),
    ('19044','HomePro','2023-06-13'), ('19044','EntEdu','2024-06-11'), ('19044','LTSC','2027-01-12'), ('19044','IoTLTSC','2032-01-13'),
    ('19045','HomePro','2025-10-14'), ('19045','EntEdu','2025-10-14'), ('20348','Server','2031-10-14'), ('22000','HomePro','2023-10-10'),
    ('22000','EntEdu','2024-10-08'), ('22621','HomePro','2024-10-08'), ('22621','EntEdu','2025-10-14'), ('22631','HomePro','2025-11-11'),
    ('22631','EntEdu','2026-11-10'), ('25398','Server','2025-10-24'), ('26100','HomePro','2026-10-13'), ('26100','EntEdu','2027-10-12'),
    ('26100','LTSC','2029-10-09'), ('26100','IoTLTSC','2034-10-10'), ('26100','Server','2034-11-14'), ('26200','HomePro','2027-10-12'),
    ('26200','EntEdu','2028-10-10'), ('28000','HomePro','2028-03-14'), ('28000','EntEdu','2029-03-13')
),
old_eol(build, d) AS (VALUES
    ('7601','2020-01-14'), ('9200','2023-10-10'), ('9600','2023-10-10'), ('10240','2025-10-14'), ('10586','2017-10-10'), ('14393','2027-01-12'),
    ('15063','2018-10-09'), ('16299','2019-04-09'), ('17134','2019-11-12'), ('17763','2029-01-09'), ('18362','2020-05-12'), ('18363','2021-05-11'),
    ('19041','2025-10-14'), ('19042','2025-10-14'), ('19043','2025-10-14'), ('19044','2026-10-13'), ('19045','2030-10-14'), ('20348','2031-10-14'),
    ('22000','2026-10-14'), ('22621','2027-10-12'), ('22631','2028-10-10'), ('26100','2029-10-14')
),
latest AS (
  SELECT DISTINCT ON (r.device_ref)
         t.name AS company, d.hostname, r.run_date, r.sk_version, r.security_score AS score, r.report
  FROM runs r
  JOIN devices d ON d.id = r.device_ref
  JOIN tenants t ON t.id = d.tenant_id
  ORDER BY r.device_ref, r.run_date DESC
),
parsed AS (
  SELECT l.*,
         substring(report->>'os' FROM '^(.*) \(Build [0-9]+\)$') AS caption,
         substring(report->>'os' FROM '\(Build ([0-9]+)\)$')     AS build
  FROM latest l
  WHERE report->>'os' IS NOT NULL                  -- engine did not run: no verdict either way
),
classified AS (             -- Get-OsEolDate's edition families, same order
  SELECT p.*,
         CASE WHEN caption ~* 'Server'                   THEN 'Server'
              WHEN caption ~* 'LTS[BC]'                  THEN CASE WHEN caption ~* 'IoT' THEN 'IoTLTSC' ELSE 'LTSC' END
              WHEN caption ~* '\mPro\M|\mHome\M|\mSE\M'  THEN 'HomePro'
              WHEN caption ~* 'Enterprise|Education'     THEN 'EntEdu'
         END AS family,
         coalesce(caption ~* 'Server', false) AS is_server
  FROM parsed p
),
-- Get-OsEolDate's fallback for an edition it cannot place: a date only when
-- every edition the machine could be (its side of client/server) agrees on it,
-- or all of them have ended.
unplaced AS (
  SELECT build, family = 'Server' AS is_server, min(d::date) AS lo, max(d::date) AS hi
  FROM new_eol GROUP BY 1, 2
),
dated AS (
  SELECT c.*, o.d::date AS old_date,
         coalesce(n.d::date, CASE WHEN u.hi <= p.as_of OR u.lo = u.hi THEN u.hi END) AS new_date
  FROM classified c
  CROSS JOIN params p
  LEFT JOIN old_eol  o ON o.build = c.build
  LEFT JOIN new_eol  n ON n.build = c.build AND n.family = c.family
  LEFT JOIN unplaced u ON u.build = c.build AND u.is_server = c.is_server
),
verdict AS (
  SELECT dt.*,
         coalesce(old_date <= as_of, false) AS old_eol,       -- the engine: (Get-Date) -gt the date
         coalesce(new_date <= as_of, false) AS new_eol,
         -- PR #2's other two rules, from the same run (its impact query)
         coalesce(report->>'bitlocker', '') = 'Off' AS bitlocker_off,
         substring(report->>'last_wu_install' FROM '\((\d+) days? ago\)')::int AS wu_days
  FROM dated dt, params
),
scored AS (
  SELECT v.*,
         CASE WHEN new_date IS NULL THEN 'Unknown'
              WHEN new_eol THEN 'END OF LIFE (since ' || new_date || ')'
              ELSE 'Supported until ' || new_date END AS new_os_eol,
         greatest(0, score - CASE WHEN old_eol THEN 20 ELSE 0 END
                           - CASE WHEN bitlocker_off THEN 15 ELSE 0 END
                           - CASE WHEN wu_days > 30 THEN 15 ELSE 0 END) AS score_before,
         greatest(0, score - CASE WHEN new_eol THEN 20 ELSE 0 END
                           - CASE WHEN bitlocker_off THEN 15 ELSE 0 END
                           - CASE WHEN wu_days > 30 THEN 15 ELSE 0 END) AS score_after
  FROM verdict v
  WHERE score IS NOT NULL
),
grades(letter, min_score) AS (VALUES ('A', 90), ('B', 80), ('C', 70), ('D', 60), ('F', 0))
SELECT company, hostname, caption, build, family,
       CASE WHEN new_eol AND NOT old_eol THEN 'newly EOL (-20)'
            WHEN old_eol AND NOT new_eol THEN 'no longer EOL (+20)'
            WHEN old_date IS DISTINCT FROM new_date THEN 'date changes, verdict same'
            ELSE 'unchanged' END AS change,
       report->>'os_eol' AS stored_os_eol, new_os_eol,
       score AS stored_score, score_before, score_after,
       (SELECT letter FROM grades WHERE score_before >= min_score ORDER BY min_score DESC LIMIT 1) AS grade_before,
       (SELECT letter FROM grades WHERE score_after  >= min_score ORDER BY min_score DESC LIMIT 1) AS grade_after
FROM scored
ORDER BY change, company, hostname;

Tests

New tests/Test-OsEol.ps1, in the style of Test-EngineScope.ps1:

  • Dates. 64 caption and build pairs against Microsoft's date. The expected dates are restated from Learn, not read from the script. These cover:
    • every build and edition family, using real captions;
    • the editions whose timeline isn't obvious: Pro Education, Pro for Workstations, SE, IoT Enterprise GA, multi-session, and N editions.
  • Unplaced captions and unknown builds (13 cases, plus a re-check with the clock moved past the last date):
    • localized captions;
    • Windows 7 "Professional" and core Windows 8.1;
    • an empty caption;
    • an edition the build doesn't ship as;
    • a server caption on a client build, and a client caption on a server build;
    • unknown builds.
  • The engine. It runs the engine's os_eol lines and the -20 rule verbatim, under StrictMode 2, with the clock pinned either side of 2026-10-13 and 2026-11-10. It asserts:
    • the exact os_eol string;
    • the score;
    • that END OF LIFE appears exactly when the -20 applies (bf/report.py's test);
    • that the string is one of the three forms Battlefield has always received.
  • The table.
    • All 22 builds of the old table are still known.
    • Each date is a real date and a Patch Tuesday. This catches most typos. Server 23H2's fixed 2025-10-24 is the one documented exception.
  • It does not age. Every expectation uses a pinned date.

Changes to #2's tests:

  • Test-EngineScope.ps1:
    • Its healthy fixture was Windows 11 Pro 23H2, which is really end of life. It is now IoT Enterprise LTSC 2024, supported until 2034, so the fixture does not age into a failure.
    • It adds a same-build pair through the whole engine: 1809 Pro takes the -20 and Enterprise LTSC 2019 does not. The engine must pass the caption, not just the build.
  • Test-EngineScope.ps1 and Test-DeviceIdentity.ps1 load the new function. Without it the engine aborts, and DeviceIdentity caught exactly that before I added it.

Results:

Mutation Test-OsEol Test-EngineScope
Engine passes no caption stops (its engine lines no longer match) 2 fail
Education tested before Pro 1 pass
Pro matched as a substring (so "Professionnel" becomes Pro) 4 pass
IoT LTSC not told apart 3 pass
Unplaced captions ignore the client/server line 2 pass
Unplaced captions always get the latest date (too lenient) 4 pass
Unplaced captions always get the earliest date (too harsh) 6 pass
Server 2025 date a day late 3 pass
Old 19045 date restored 12 pass
Build 26100 dropped 13 pass

The impact query was executed, not just written.

  • I ran it in scratch Postgres 16 and 18 containers loaded with Battlefield's schema.sql and all migrations.
  • The input was 1,107 synthetic devices: every caption in the test against every build in the table plus two unknown builds.
  • Each device was run at six as_of dates. That gave 6,642 verdicts, compared against the real PowerShell: this branch's Get-OsEolDate and engine lines, and v2026.09.25.002: an unknown password length is not scored or reported as 0 #3's head's old table.
  • All 6,642 were identical on both versions.
  • A hand-checked set confirmed that the latest run wins, that the score and grade columns are right, and that engine-aborted runs are excluded.
  • Limits. PSScriptAnalyzer was not run locally; CI runs it. These are mock tests, not a Windows run.

Before merging: one real run

Run this in an elevated Windows PowerShell 5.1. The best box is Windows 10 22H2 Pro or Windows 11 23H2 Pro, which flips. If the fleet has an LTSC or Server 2016/2019 box, run it there as well, to confirm its caption places it correctly. RLG-JANE-PC or RLG-DCFS also cover #1.

$f = "$env:windir\Temp\ShellKnight-test.ps1"
Invoke-RestMethod 'https://raw.githubusercontent.com/cdburgess75/ShellKnight/fix/os-eol-by-edition/ShellKnight.ps1' -OutFile $f
schtasks /create /tn SK-Test /tr "powershell.exe -NoProfile -ExecutionPolicy Bypass -File $f" /sc once /st 23:59 /ru SYSTEM /f
schtasks /run /tn SK-Test

When it finishes, check the newest C:\ProgramData\ShellKnight\Logs\ShellKnight_*.log:

  • It has no Assessment Engine skipped, Device identity skipped or Password policy skipped line.
  • The MACHINE INFORMATION block's OS and OS EOL agree with the table above for that edition. For example, Windows 10 Pro (Build 19045) shows END OF LIFE (since 2025-10-14).
  • SECURITY GRADE includes the -20 exactly when OS EOL says END OF LIFE, and an OS EOL: warning line appears above it.
  • In the newest C:\ProgramData\ShellKnight\JSON\*.json, os_eol matches the log and version is v2026.09.25.003.
  • It has Battlefield push OK - run_id: <n>.

Then remove the test task with schtasks /delete /tn SK-Test /f. Update LATEST_SK_VERSION in battlefield.env when this ships.

Left alone (follow-ups)

  • Battlefield's device page shows a warning pill for every device. templates/machine.html shows OS end of life {{ rep.os_eol }} whenever os_eol is set, including Supported until ... and Unknown. fleet.html prints (EOL Supported until ...) the same way. The pill should key off END OF LIFE, as bf/report.py does. This is outside this repo.
  • ESU detection, if ParaTech sells Year 2 (ADR 0010).
  • OperatingSystemSKU instead of the caption. It is documented and not localized. It is the next step if non-English devices appear; the impact query's family column will show them.
  • New Windows releases need a table row. Until they get one, os_eol is Unknown and there is no penalty.

🤖 Generated with Claude Code

…s dates

The Assessment Engine looked up os_eol by build number only, one date per
build, and several dates were years past Microsoft's: 19045 (Windows 10
22H2) read 2030-10-14 for 2025-10-14; 22621 and 22631 read 2027 and 2028;
26100 read 2029-10-14. One date per build cannot be right either: Home/Pro
and Enterprise/Education end on different days, and 14393, 17763, 19044
and 26100 are also LTSB/LTSC or Windows Server.

New Get-OsEolDate takes the edition family from Win32_OperatingSystem
.Caption (Home/Pro, Enterprise/Education, LTSB/LTSC, IoT LTSC, Server) and
holds every date from Microsoft Learn. A caption it cannot place gets a
date only when it holds for every edition the machine could be; otherwise
'Unknown', which is not scored (ADR 0009). os_eol keeps its three forms.

Windows 10 ESU does not extend end of life (new ADR 0010).

Scoring change: more devices take the OS EOL -20 (Windows 10 22H2,
Windows 11 22H2, 11 23H2 Home/Pro, older GA releases, Server 23H2).

New tests/Test-OsEol.ps1; Test-EngineScope and Test-DeviceIdentity load
the new function, and EngineScope adds a same-build Pro/LTSC pair.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant