Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ jobs:

steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
Expand All @@ -36,6 +38,11 @@ jobs:
python -m pip install --no-deps --no-build-isolation -e .
python -m pip check

- name: Type check critical surfaces and monotonic repository baseline
env:
TRUSTED_BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before }}
run: python scripts/verify_type_gate.py --base "${TRUSTED_BASE_SHA}"

- name: Lint
run: ruff check forge_cli/ tests/

Expand Down
16 changes: 9 additions & 7 deletions forge_cli/incident_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ class QuarantineSourceChangedError(OSError):
class RecoverablePartialStateError(OSError):
"""Indicates recovery state remains after an incomplete operation."""

primary_error: OSError | None

def __init__(
self,
*,
Expand Down Expand Up @@ -1335,22 +1337,22 @@ def publish(self) -> Incident:
primary_error = exc
raise
finally:
cleanup_error: OSError | None = None
final_cleanup_error: OSError | None = None
if temporary_fd is not None:
try:
os.close(temporary_fd)
except OSError as exc:
cleanup_error = exc
final_cleanup_error = exc
if temporary_name is not None:
try:
os.unlink(temporary_name, dir_fd=self._directory_fd)
except OSError as exc:
if cleanup_error is None:
cleanup_error = exc
if cleanup_error is not None:
if final_cleanup_error is None:
final_cleanup_error = exc
if final_cleanup_error is not None:
raise RecoverablePartialStateError(
primary_error=primary_error or cleanup_error
) from cleanup_error
primary_error=primary_error or final_cleanup_error
) from final_cleanup_error


@contextmanager
Expand Down
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ anthropic = ["anthropic>=0.39.0"]
openai = ["openai>=1.0.0"]
mcp = ["mcp>=1.0.0", "uvicorn>=0.30.0"]
dev = [
"mypy>=1.19.1,<1.20",
"pytest>=7.4.0",
"ruff>=0.1.0",
"types-pyyaml>=6.0.12.20241230",
]

[dependency-groups]
Expand Down
72 changes: 72 additions & 0 deletions requirements/dev.lock
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,48 @@ jsonschema==4.26.0 \
jsonschema-specifications==2025.9.1 \
--hash=sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe \
--hash=sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d
librt==0.13.0 ; platform_python_implementation != 'PyPy' \
--hash=sha256:0763ca2ab66058174f9dee426dc64f5e0a89c24a7df8d3fe3f1836c04e25de4b \
--hash=sha256:091b60a4d2174fc1ec5c34cdc0b72efb6224753d76b7da61ebeab7a191aec8bd \
--hash=sha256:109b84a9edf69ad89dc1f66358659e14a031baca95e3e5b0060bd903ede8efd6 \
--hash=sha256:1304368a3e7ffc3e9db986796cc5326fdb5943a3567ecc137cff318e4240c0e7 \
--hash=sha256:17221a7569f8f292aa0014226e48aa25b8c2b08da18088cd230953d0ea0f9cd1 \
--hash=sha256:1b5a7bbff495baedbd9b916c367d66854008f8f3b575908ded477c499dc60082 \
--hash=sha256:1d2a610c14ac0d0750ee0a3ab8548e83155258387891caaca04def4bf7289781 \
--hash=sha256:30536798f4504c0fad0885b1d371b0539abb081e4570c9d7c641cb51141b49f0 \
--hash=sha256:32c26893cd085c1efe83219e78d866da23fb20a066101b8f68210004361d224c \
--hash=sha256:34bc7938b9fdf14fe32a406c19c71faf894c5cee7e7474bd0be2f17200b82d14 \
--hash=sha256:3dbb2a31882456cadc7053378e81ad7ed7693db4ac9f98ab5f81ef034aa8ec9f \
--hash=sha256:4000d961ff9598ac6ea603c6c836a5ed49bc205ade5fc378b998dfe1e2c36628 \
--hash=sha256:40ccd13c252d3fe473ffc8a57be7565abc8b64cf1b108344c859d5164f7f3e0c \
--hash=sha256:531b2df3e9fe96b1fcf73a6d165921e4656be5f58d631d384ebce344298368db \
--hash=sha256:54dab44a847d5ad1acd05c8a83fe518ae685516ecf4d3f7cc6e3df2a66767650 \
--hash=sha256:5929da1981a46bcf4b28b1b9499905f0ff58e2419da402a048234e9783acbc4b \
--hash=sha256:66c0e7e6b02a155576df2c77ec933a70b72da726e248c494abf690923e624348 \
--hash=sha256:66cb1138f384a191a6d75f986064841fcfdc0cea98f7bd9c9ab9b38049917588 \
--hash=sha256:70d9c62a4cffd9f23396cd5ef93fc5d11b31596b9b7d6306074abe3d5fcf09bd \
--hash=sha256:79e44cff71750d299d61a678e49995b0d5935a9cda238c2574daeca3ba536927 \
--hash=sha256:7db9a3ff32ef5f7d1703d93831a3316cdf0b537de6a1cc03cc8fdd09b9194e89 \
--hash=sha256:860bd1d8ba48456ce08feaf8d343a8aaeb2fa086f2bcaa2a923fa3f7a3ff9aa3 \
--hash=sha256:93d24ebb82aa4420b1409c389e7857bc35bd0b668007ac8172427d5c73cc8cc5 \
--hash=sha256:94b85d664d777bab6c0d709416cb42938251fda9e221b79e3a2215d85df5f4f9 \
--hash=sha256:9c5d02b89de5acd0379a51ec44a89476fb03df6145442e1c8ecd6bee2f91b176 \
--hash=sha256:9f836c37478f167a81200d8c8b2c920a22224564bed2c23d7aeec760965c367a \
--hash=sha256:a468951af16155824e88bdd8326ebe5bdb371f3ec0ac04642994b98201d914f3 \
--hash=sha256:ac04bcd3328eb91d99dfedf6a60d9c1f15d3434e6f6daf922f0420f7d90b85c7 \
--hash=sha256:ae01d8512cc17079e53425635327dbf3f7ff57a42c00dec348bf79791c56444c \
--hash=sha256:b222493da6e7b6199db9bd79502436cf5a27da3c1f7fa83c7e285444fc93fd03 \
--hash=sha256:c6014e3c80f9c1fe268ef8b0e0ef113bac672cc032f2f93866e7ddad4f3e663d \
--hash=sha256:c718e99a0992127af84385378460db624103b559ab260435abcfe77a4e4ed1c1 \
--hash=sha256:cb8a1adce42d8b75485a5d56a9623a50bcab995b6079f1dac59fc44034dd93d9 \
--hash=sha256:cc99dfb62b23c9207c33d0be8a2e2af7a42e21e6ea388b380a0c948c7b88953b \
--hash=sha256:d4cb6fbfdf874340ab5e51450753c0f817b6958a3621125ee695bbc3de866566 \
--hash=sha256:db327e7271e653c32040b85ae6188059c924b57d7e1e29f935523fa017cd4e82 \
--hash=sha256:e4f9b472e7d308d94b62c801982065661158c6ed02790d6c7ddb4337cea0f9c1 \
--hash=sha256:e54a315caf843c8d77e388cadc56ea9ded569935ee2d2347d7ea94992e5aa6fa \
--hash=sha256:f40e56b61b41be5f7dec938cfeffd660668cf4b5e72c78e7bd671d66b7bc2c79 \
--hash=sha256:fadc63331f4388c3dc90090448f682a7e9feafc11481391c1e94f2f907a3976e \
--hash=sha256:fc67741da44c6eaa90e01eafb586bbba9b51eb5b6ed381ee6f5ae72eb3316d21
markdown-it-py==4.2.0 \
--hash=sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49 \
--hash=sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a
Expand All @@ -127,9 +169,36 @@ mcp==1.28.1 \
mdurl==0.1.2 \
--hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \
--hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba
mypy==1.19.1 \
--hash=sha256:016f2246209095e8eda7538944daa1d60e1e8134d98983b9fc1e92c1fc0cb8dd \
--hash=sha256:19d88bb05303fe63f71dd2c6270daca27cb9401c4ca8255fe50d1d920e0eb9ba \
--hash=sha256:2abb24cf3f17864770d18d673c85235ba52456b36a06b6afc1e07c1fdcd3d0e6 \
--hash=sha256:34c81968774648ab5ac09c29a375fdede03ba253f8f8287847bd480782f73a6a \
--hash=sha256:4b84a7a18f41e167f7995200a1d07a4a6810e89d29859df936f1c3923d263042 \
--hash=sha256:a009ffa5a621762d0c926a078c2d639104becab69e79538a494bcccb62cc0331 \
--hash=sha256:a8174a03289288c1f6c46d55cef02379b478bfbc8e358e02047487cad44c6ca1 \
--hash=sha256:b10e7c2cd7870ba4ad9b2d8a6102eb5ffc1f16ca35e3de6bfa390c1113029d13 \
--hash=sha256:b64d987153888790bcdb03a6473d321820597ab8dd9243b27a92153c4fa50fd2 \
--hash=sha256:bdb12f69bcc02700c2b47e070238f42cb87f18c0bc1fc4cdb4fb2bc5fd7a3b8b \
--hash=sha256:c35d298c2c4bba75feb2195655dfea8124d855dfd7343bf8b8c055421eaf0cf8 \
--hash=sha256:c9a6538e0415310aad77cb94004ca6482330fece18036b5f360b62c45814c4ef \
--hash=sha256:d8dfc6ab58ca7dda47d9237349157500468e404b17213d44fc1cb77bce532288 \
--hash=sha256:da4869fc5e7f62a88f3fe0b5c919d1d9f7ea3cef92d3689de2823fd27e40aa75 \
--hash=sha256:e3157c7594ff2ef1634ee058aafc56a82db665c9438fd41b390f3bde1ab12250 \
--hash=sha256:e3f276d8493c3c97930e354b2595a44a21348b320d859fb4a2b9f66da9ed27ab \
--hash=sha256:f1235f5ea01b7db5468d53ece6aaddf1ad0b88d9e7462b86ef96fe04995d7247 \
--hash=sha256:f7cee03c9a2e2ee26ec07479f38ea9c884e301d42c6d43a19d20fb014e3ba925 \
--hash=sha256:f859fb09d9583a985be9a493d5cfc5515b56b08f7447759a0c5deaf68d80506e \
--hash=sha256:ffcebe56eb09ff0c0885e750036a095e23793ba6c2e894e7e63f6d89ad51f22e
mypy-extensions==1.1.0 \
--hash=sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505 \
--hash=sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558
packaging==26.2 \
--hash=sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e \
--hash=sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661
pathspec==1.1.1 \
--hash=sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a \
--hash=sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189
pluggy==1.6.0 \
--hash=sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3 \
--hash=sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746
Expand Down Expand Up @@ -357,6 +426,9 @@ starlette==1.3.1 \
typer==0.26.8 \
--hash=sha256:3512ca79ac5c11113414b36e80281b872884477722440691c89d1112e321a49c \
--hash=sha256:c244a6bd558886fe3f8780efb6bdd28bb9aff005a94eedebaa5cb32926fe2f7e
types-pyyaml==6.0.12.20260518 \
--hash=sha256:d2150f75a231c9fe9c7463bd29487d93e60bac90400287351384bc2284eba7cd \
--hash=sha256:d917f83fb38462550338c1297faedd860b3ec83912b96b1e3d73255f7473e466
typing-extensions==4.16.0 \
--hash=sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8 \
--hash=sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5
Expand Down
Loading