diff --git a/scripts/dev/add_to_project.sh b/scripts/dev/add_to_project.sh
deleted file mode 100755
index e5fc0210161..00000000000
--- a/scripts/dev/add_to_project.sh
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/bin/bash
-
-# call with the PR number as the only command line argument
-
-# get the PR num from the command line argument
-PR_NUM=$1
-
-# the GraphQL Project ID can be retrieved from a given organization's project, where the URL is:
-# https://github.com/orgs/ORGANIZATION/projects/SOME_PROJECT_NUMBER/views/2
-# and the associated call to graphql is:
-#gh api graphql -f query='
-# query{
-# organization(login: "ORGANIZATION"){
-# projectV2(number: SOME_PROJECT_NUMBER) {
-# id
-# }
-# }
-# }'
-# TODO: Just specify the project organization and number and get the graphql ID in here
-PROJ_ID=PVT_kwDOAB0YcM4AEWD7
-echo "Using PR Num as ${PR_NUM} and project ID as: ${PROJ_ID}"
-
-# get the current PR ID based on the this checkout
-CONTENT=$(gh pr view "$PR_NUM" --json 'id' --jq '.id')
-echo "Found PR node ID as: ${CONTENT}"
-
-# use the gh api command line to act on the Projects-v2 API and add the PR as a new card
-# should also add more arguments for the column to use, etc.
-gh api graphql -f query="
- mutation {
- addProjectV2ItemById(input: {projectId: \"${PROJ_ID}\" contentId: \"${CONTENT}\"}) {
- item {
- id
- }
- }
- }"
diff --git a/scripts/dev/build_regression_summary.py b/scripts/dev/build_regression_summary.py
new file mode 100644
index 00000000000..641a228fa3a
--- /dev/null
+++ b/scripts/dev/build_regression_summary.py
@@ -0,0 +1,89 @@
+#!/usr/bin/env python
+# EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University
+# of Illinois, The Regents of the University of California, through Lawrence
+# Berkeley National Laboratory (subject to receipt of any required approvals
+# from the U.S. Dept. of Energy), Oak Ridge National Laboratory, managed by UT-
+# Battelle, Alliance for Sustainable Energy, LLC, and other contributors. All
+# rights reserved.
+#
+# NOTICE: This Software was developed under funding from the U.S. Department of
+# Energy and the U.S. Government consequently retains certain rights. As such,
+# the U.S. Government has been granted for itself and others acting on its
+# behalf a paid-up, nonexclusive, irrevocable, worldwide license in the
+# Software to reproduce, distribute copies to the public, prepare derivative
+# works, and perform publicly and display publicly, and to permit others to do
+# so.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# (1) Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# (2) Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# (3) Neither the name of the University of California, Lawrence Berkeley
+# National Laboratory, the University of Illinois, U.S. Dept. of Energy nor
+# the names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in
+# stand-alone form without changes from the version obtained under this
+# License, or (ii) Licensee makes a reference solely to the software
+# portion of its product, Licensee must refer to the software as
+# "EnergyPlus version X" software, where "X" is the version number Licensee
+# obtained under this License and may not use a different name for the
+# software. Except as specifically required in this Section (4), Licensee
+# shall not use in a company name, a product name, in advertising,
+# publicity, or other promotional activities any name, trade name,
+# trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or
+# confusingly similar designation, without the U.S. Department of Energy's
+# prior written consent.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+from sys import argv
+
+summary_input_md_file = argv[1]
+summary_output_js_file = argv[2]
+matrix_os = argv[3]
+github_sha = argv[4]
+github_run_id = argv[5]
+artifact_url = argv[6]
+
+with open(summary_input_md_file) as md:
+ md_contents = md.read()
+
+fixed_up_contents = f"""
+### :warning: Regressions detected on {matrix_os} for commit {github_sha}
+
+{md_contents}
+
+ - [View Results](https://github.com/NREL/EnergyPlus/actions/runs/{github_run_id})
+ - [Download Regressions]({artifact_url})
+"""
+
+with open(summary_output_js_file, 'w') as js:
+ js_contents = f"""
+module.exports = ({{github, context}}) => {{
+ github.rest.issues.createComment({{
+ issue_number: context.issue.number,
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ body: `{fixed_up_contents}`
+ }})
+}}
+"""
+ js.write(js_contents)
diff --git a/scripts/dev/gha_coverage_summary.py b/scripts/dev/gha_coverage_summary.py
new file mode 100644
index 00000000000..34bb39dcc3c
--- /dev/null
+++ b/scripts/dev/gha_coverage_summary.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python
+# EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University
+# of Illinois, The Regents of the University of California, through Lawrence
+# Berkeley National Laboratory (subject to receipt of any required approvals
+# from the U.S. Dept. of Energy), Oak Ridge National Laboratory, managed by UT-
+# Battelle, Alliance for Sustainable Energy, LLC, and other contributors. All
+# rights reserved.
+#
+# NOTICE: This Software was developed under funding from the U.S. Department of
+# Energy and the U.S. Government consequently retains certain rights. As such,
+# the U.S. Government has been granted for itself and others acting on its
+# behalf a paid-up, nonexclusive, irrevocable, worldwide license in the
+# Software to reproduce, distribute copies to the public, prepare derivative
+# works, and perform publicly and display publicly, and to permit others to do
+# so.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# (1) Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# (2) Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# (3) Neither the name of the University of California, Lawrence Berkeley
+# National Laboratory, the University of Illinois, U.S. Dept. of Energy nor
+# the names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in
+# stand-alone form without changes from the version obtained under this
+# License, or (ii) Licensee makes a reference solely to the software
+# portion of its product, Licensee must refer to the software as
+# "EnergyPlus version X" software, where "X" is the version number Licensee
+# obtained under this License and may not use a different name for the
+# software. Except as specifically required in this Section (4), Licensee
+# shall not use in a company name, a product name, in advertising,
+# publicity, or other promotional activities any name, trade name,
+# trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or
+# confusingly similar designation, without the U.S. Department of Energy's
+# prior written consent.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+# expecting to find a file called cover.txt in cwd
+# need to generate a cover.md file in cwd
+# cover.txt looks like:
+# lines=48 hit=2 functions=2 hit=1
+# Processing file EnergyPlus/SurfaceGeometry.hh
+# lines=44 hit=9 functions=4 hit=2
+# Overall coverage rate:
+# lines......: 7.9% (28765 of 364658 lines)
+# functions......: 19.6% (2224 of 11327 functions)
+
+from pathlib import Path
+cover_input = Path.cwd() / 'cover.txt'
+lines = cover_input.read_text().strip().split('\n')
+line_coverage = lines[-2].strip().split(':')[1].strip()
+line_percent = line_coverage.split(' ')[0]
+function_coverage = lines[-1].strip().split(':')[1].strip()
+cover_output = Path.cwd() / 'cover.md'
+content = f"""
+
+ Coverage Summary - {line_percent} of lines - Download Coverage Artifact for Full Details
+
+ - {line_coverage}
+ - {function_coverage}
+"""
+cover_output.write_text(content)
diff --git a/scripts/dev/gha_regressions.py b/scripts/dev/gha_regressions.py
new file mode 100644
index 00000000000..b3de9964190
--- /dev/null
+++ b/scripts/dev/gha_regressions.py
@@ -0,0 +1,508 @@
+#!/usr/bin/env python
+# EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University
+# of Illinois, The Regents of the University of California, through Lawrence
+# Berkeley National Laboratory (subject to receipt of any required approvals
+# from the U.S. Dept. of Energy), Oak Ridge National Laboratory, managed by UT-
+# Battelle, Alliance for Sustainable Energy, LLC, and other contributors. All
+# rights reserved.
+#
+# NOTICE: This Software was developed under funding from the U.S. Department of
+# Energy and the U.S. Government consequently retains certain rights. As such,
+# the U.S. Government has been granted for itself and others acting on its
+# behalf a paid-up, nonexclusive, irrevocable, worldwide license in the
+# Software to reproduce, distribute copies to the public, prepare derivative
+# works, and perform publicly and display publicly, and to permit others to do
+# so.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# (1) Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# (2) Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# (3) Neither the name of the University of California, Lawrence Berkeley
+# National Laboratory, the University of Illinois, U.S. Dept. of Energy nor
+# the names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in
+# stand-alone form without changes from the version obtained under this
+# License, or (ii) Licensee makes a reference solely to the software
+# portion of its product, Licensee must refer to the software as
+# "EnergyPlus version X" software, where "X" is the version number Licensee
+# obtained under this License and may not use a different name for the
+# software. Except as specifically required in this Section (4), Licensee
+# shall not use in a company name, a product name, in advertising,
+# publicity, or other promotional activities any name, trade name,
+# trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or
+# confusingly similar designation, without the U.S. Department of Energy's
+# prior written consent.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+from collections import defaultdict
+from datetime import datetime, UTC
+import json
+from shutil import copy
+from pathlib import Path
+import sys
+from shutil import rmtree
+from zoneinfo import ZoneInfo
+
+from energyplus_regressions.runtests import SuiteRunner
+from energyplus_regressions.structures import TextDifferences, TestEntry, EndErrSummary
+
+
+class RegressionManager:
+
+ def __init__(self):
+ self.root_index_files_no_diff = []
+ self.root_index_files_diffs = []
+ self.diffs_by_idf = defaultdict(list)
+ self.diffs_by_type = defaultdict(list)
+ self.summary_results = {}
+ self.num_idf_inspected = 0
+ # self.all_files_compared = [] TODO: need to get this from regression runner
+ import energyplus_regressions
+ self.threshold_file = str(Path(energyplus_regressions.__file__).parent / 'diffs' / 'math_diff.config')
+
+ def single_file_regressions(self, baseline: Path, modified: Path) -> [TestEntry, bool]:
+
+ idf = baseline.name
+ self.num_idf_inspected += 1
+ this_file_diffs = []
+
+ entry = TestEntry(idf, "")
+ entry, message = SuiteRunner.process_diffs_for_one_case(
+ entry,
+ {'build_dir': str(baseline)},
+ {'build_dir': str(modified)},
+ "",
+ self.threshold_file,
+ ci_mode=True
+ ) # returns an updated entry
+ self.summary_results[idf] = entry.summary_result
+
+ has_diffs = False
+
+ text_diff_results = {
+ "Audit": entry.aud_diffs,
+ "BND": entry.bnd_diffs,
+ "DELightIn": entry.dl_in_diffs,
+ "DELightOut": entry.dl_out_diffs,
+ "DXF": entry.dxf_diffs,
+ "EIO": entry.eio_diffs,
+ "ERR": entry.err_diffs,
+ "Readvars_Audit": entry.readvars_audit_diffs,
+ "EDD": entry.edd_diffs,
+ "WRL": entry.wrl_diffs,
+ "SLN": entry.sln_diffs,
+ "SCI": entry.sci_diffs,
+ "MAP": entry.map_diffs,
+ "DFS": entry.dfs_diffs,
+ "SCREEN": entry.screen_diffs,
+ "GLHE": entry.glhe_diffs,
+ "MDD": entry.mdd_diffs,
+ "MTD": entry.mtd_diffs,
+ "RDD": entry.rdd_diffs,
+ "SHD": entry.shd_diffs,
+ "PERF_LOG": entry.perf_log_diffs,
+ "IDF": entry.idf_diffs,
+ "StdOut": entry.stdout_diffs,
+ "StdErr": entry.stderr_diffs,
+ }
+ for diff_type, diffs in text_diff_results.items():
+ if diffs is None:
+ continue
+ if diffs.diff_type != TextDifferences.EQUAL:
+ has_diffs = True
+ this_file_diffs.append(diff_type)
+ self.diffs_by_type[diff_type].append(idf)
+ self.diffs_by_idf[idf].append(diff_type)
+
+ numeric_diff_results = {
+ "ESO": entry.eso_diffs,
+ "MTR": entry.mtr_diffs,
+ "SSZ": entry.ssz_diffs,
+ "ZSZ": entry.zsz_diffs,
+ "JSON": entry.json_diffs,
+ }
+ for diff_type, diffs in numeric_diff_results.items():
+ if diffs is None:
+ continue
+ if diffs.diff_type == 'Big Diffs':
+ has_diffs = True
+ this_file_diffs.append(f"{diff_type} Big Diffs")
+ self.diffs_by_type[f"{diff_type} Big Diffs"].append(idf)
+ self.diffs_by_idf[idf].append(f"{diff_type} Big Diffs")
+ elif diffs.diff_type == 'Small Diffs':
+ has_diffs = True
+ this_file_diffs.append(f"{diff_type} Small Diffs")
+ self.diffs_by_type[f"{diff_type} Small Diffs"].append(idf)
+ self.diffs_by_idf[idf].append(f"{diff_type} Small Diffs")
+
+ if entry.table_diffs:
+ if entry.table_diffs.big_diff_count > 0:
+ has_diffs = True
+ this_file_diffs.append("Table Big Diffs")
+ self.diffs_by_type["Table Big Diffs"].append(idf)
+ self.diffs_by_idf[idf].append("Table Big Diffs")
+ elif entry.table_diffs.small_diff_count > 0:
+ has_diffs = True
+ this_file_diffs.append("Table Small Diffs")
+ self.diffs_by_type["Table Small Diffs"].append(idf)
+ self.diffs_by_idf[idf].append("Table Small Diffs")
+ if entry.table_diffs.string_diff_count > 1: # There's always one...the time stamp
+ has_diffs = True
+ this_file_diffs.append("Table String Diffs")
+ self.diffs_by_type["Table String Diffs"].append(idf)
+ self.diffs_by_idf[idf].append("Table String Diffs")
+
+ return entry, has_diffs
+
+ @staticmethod
+ def single_diff_html(contents: str) -> str:
+ return f"""
+
+
+