From 360e5737ab364061584381ecf4cec92ba0311741 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Thu, 12 Feb 2026 16:34:02 -0700 Subject: [PATCH 01/44] Fix command --- docs/source/dev/advanced_plugin_development.rst | 7 +------ docs/source/dev/plugin_development.rst | 5 +---- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/docs/source/dev/advanced_plugin_development.rst b/docs/source/dev/advanced_plugin_development.rst index d65e920c..2d9828f9 100644 --- a/docs/source/dev/advanced_plugin_development.rst +++ b/docs/source/dev/advanced_plugin_development.rst @@ -913,13 +913,8 @@ about your internal implementation choices: .. code-block:: bash export OPENAI_API_KEY="your-key" - export AZURE_OPENAI_ENDPOINT="your-endpoint" - export AZURE_OPENAI_API_KEY="your-azure-key" - compass process \ - --tech data_center_custom \ - --jurisdiction "Loudoun County, VA" \ - --config my_config.yaml + compass process --config my_config.yaml Users select your plugin through the identifier you specify (``data_center_custom`` in this example). The remaining implementation diff --git a/docs/source/dev/plugin_development.rst b/docs/source/dev/plugin_development.rst index df01143a..96851eab 100644 --- a/docs/source/dev/plugin_development.rst +++ b/docs/source/dev/plugin_development.rst @@ -285,10 +285,7 @@ story you just built. export OPENAI_API_KEY="your-key" - compass process \ - --tech battery_storage \ - --jurisdiction "Boulder County, CO" \ - --config my_config.yaml + compass process --config my_config.yaml Where to go next ---------------- From 1487cc3a25018cf1595f662bffcb4c5dace59b9d Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Wed, 25 Feb 2026 13:06:56 -0700 Subject: [PATCH 02/44] Bump elm version --- pixi.lock | 72 +++++++++++++++++++++++++------------------------- pyproject.toml | 2 +- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/pixi.lock b/pixi.lock index cf1d43a2..2b68b4cf 100644 --- a/pixi.lock +++ b/pixi.lock @@ -264,7 +264,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/75/97/a471f1c3eb1fd6f6c24a31a5858f443891d5127e63a7788678d14e249aea/matplotlib-3.10.8-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - pypi: https://files.pythonhosted.org/packages/df/e6/a170e6ae3492d8e334a6ce9e39668f2b8d0cb0a158804460b5d851315230/maxminddb-3.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/70/cb/e7cd2f6161e30a4009cf38dd00024b1303197afcd4297081b0ccd21016a8/patchright-1.51.3-py3-none-manylinux1_x86_64.whl @@ -598,7 +598,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl - pypi: https://files.pythonhosted.org/packages/01/be/cd478f4b66f48256f42927d0acbcd63a26a893136456cd079c0cc24fbabf/matplotlib-3.10.8-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl - pypi: https://files.pythonhosted.org/packages/ec/3d/c22a117c1c6ca42a62be9473f12d113e2eab72ac28c032a290d0fbbd488e/maxminddb-3.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/81/09/e6126d32175f96ea963616debbb8e380e7c987ca913efeb59bf7e7f39438/patchright-1.51.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl @@ -883,7 +883,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl - pypi: https://files.pythonhosted.org/packages/3d/b9/15fd5541ef4f5b9a17eefd379356cf12175fe577424e7b1d80676516031a/matplotlib-3.10.8-cp313-cp313-macosx_10_13_x86_64.whl - pypi: https://files.pythonhosted.org/packages/d6/c8/76b3c0ea1f180209496cb401892a4ad197ee23ac1f370da578fffa466418/maxminddb-3.0.0-cp313-cp313-macosx_10_13_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1a/55/d62c85fff36e9e9e515ee92407b02acb556e6832d4fbcc8624b638cf70bb/patchright-1.51.3-py3-none-macosx_11_0_universal2.whl @@ -1170,7 +1170,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/8d/a0/2ba3473c1b66b9c74dc7107c67e9008cb1782edbe896d4c899d39ae9cf78/matplotlib-3.10.8-cp313-cp313-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/b6/96/b2d5ab37458ec892d7d52b6a9e6aa9992354d61df20b9978bae60e35d17a/maxminddb-3.0.0-cp313-cp313-macosx_11_0_arm64.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/55/20/4df3f817c28938e22ee7c7c4b28d8b3a212e5a111c3bd9633bc410267daa/patchright-1.51.3-py3-none-macosx_11_0_arm64.whl @@ -1449,7 +1449,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/64/40/37612487cc8a437d4dd261b32ca21fe2d79510fe74af74e1f42becb1bdb8/matplotlib-3.10.8-cp313-cp313-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/4b/19/a498bf14a86e98475d4ca994988e8f072dccfd407d026403ad95725321de/maxminddb-3.0.0-cp313-cp313-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/6e/fd/97e3e26893904bdeff36d54e6ea5fe5f81a245a96c1b73ebe37e956ce11d/patchright-1.51.3-py3-none-win_amd64.whl @@ -1775,7 +1775,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/74/0f/5312b944208efeec5dcbf8e0ed956f8f7c430b0c6458301d206380c90b56/litellm-1.81.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/df/e6/a170e6ae3492d8e334a6ce9e39668f2b8d0cb0a158804460b5d851315230/maxminddb-3.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/70/cb/e7cd2f6161e30a4009cf38dd00024b1303197afcd4297081b0ccd21016a8/patchright-1.51.3-py3-none-manylinux1_x86_64.whl @@ -2121,7 +2121,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/74/0f/5312b944208efeec5dcbf8e0ed956f8f7c430b0c6458301d206380c90b56/litellm-1.81.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ec/3d/c22a117c1c6ca42a62be9473f12d113e2eab72ac28c032a290d0fbbd488e/maxminddb-3.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/81/09/e6126d32175f96ea963616debbb8e380e7c987ca913efeb59bf7e7f39438/patchright-1.51.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl @@ -2421,7 +2421,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/74/0f/5312b944208efeec5dcbf8e0ed956f8f7c430b0c6458301d206380c90b56/litellm-1.81.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d6/c8/76b3c0ea1f180209496cb401892a4ad197ee23ac1f370da578fffa466418/maxminddb-3.0.0-cp313-cp313-macosx_10_13_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1a/55/d62c85fff36e9e9e515ee92407b02acb556e6832d4fbcc8624b638cf70bb/patchright-1.51.3-py3-none-macosx_11_0_universal2.whl @@ -2721,7 +2721,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/74/0f/5312b944208efeec5dcbf8e0ed956f8f7c430b0c6458301d206380c90b56/litellm-1.81.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b6/96/b2d5ab37458ec892d7d52b6a9e6aa9992354d61df20b9978bae60e35d17a/maxminddb-3.0.0-cp313-cp313-macosx_11_0_arm64.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/55/20/4df3f817c28938e22ee7c7c4b28d8b3a212e5a111c3bd9633bc410267daa/patchright-1.51.3-py3-none-macosx_11_0_arm64.whl @@ -3011,7 +3011,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/74/0f/5312b944208efeec5dcbf8e0ed956f8f7c430b0c6458301d206380c90b56/litellm-1.81.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/4b/19/a498bf14a86e98475d4ca994988e8f072dccfd407d026403ad95725321de/maxminddb-3.0.0-cp313-cp313-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/6e/fd/97e3e26893904bdeff36d54e6ea5fe5f81a245a96c1b73ebe37e956ce11d/patchright-1.51.3-py3-none-win_amd64.whl @@ -3472,7 +3472,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/74/0f/5312b944208efeec5dcbf8e0ed956f8f7c430b0c6458301d206380c90b56/litellm-1.81.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/df/e6/a170e6ae3492d8e334a6ce9e39668f2b8d0cb0a158804460b5d851315230/maxminddb-3.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/70/cb/e7cd2f6161e30a4009cf38dd00024b1303197afcd4297081b0ccd21016a8/patchright-1.51.3-py3-none-manylinux1_x86_64.whl @@ -3964,7 +3964,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/74/0f/5312b944208efeec5dcbf8e0ed956f8f7c430b0c6458301d206380c90b56/litellm-1.81.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ec/3d/c22a117c1c6ca42a62be9473f12d113e2eab72ac28c032a290d0fbbd488e/maxminddb-3.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/81/09/e6126d32175f96ea963616debbb8e380e7c987ca913efeb59bf7e7f39438/patchright-1.51.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl @@ -4410,7 +4410,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/74/0f/5312b944208efeec5dcbf8e0ed956f8f7c430b0c6458301d206380c90b56/litellm-1.81.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d6/c8/76b3c0ea1f180209496cb401892a4ad197ee23ac1f370da578fffa466418/maxminddb-3.0.0-cp313-cp313-macosx_10_13_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1a/55/d62c85fff36e9e9e515ee92407b02acb556e6832d4fbcc8624b638cf70bb/patchright-1.51.3-py3-none-macosx_11_0_universal2.whl @@ -4856,7 +4856,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/74/0f/5312b944208efeec5dcbf8e0ed956f8f7c430b0c6458301d206380c90b56/litellm-1.81.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b6/96/b2d5ab37458ec892d7d52b6a9e6aa9992354d61df20b9978bae60e35d17a/maxminddb-3.0.0-cp313-cp313-macosx_11_0_arm64.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/55/20/4df3f817c28938e22ee7c7c4b28d8b3a212e5a111c3bd9633bc410267daa/patchright-1.51.3-py3-none-macosx_11_0_arm64.whl @@ -5293,7 +5293,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/74/0f/5312b944208efeec5dcbf8e0ed956f8f7c430b0c6458301d206380c90b56/litellm-1.81.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/4b/19/a498bf14a86e98475d4ca994988e8f072dccfd407d026403ad95725321de/maxminddb-3.0.0-cp313-cp313-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/6e/fd/97e3e26893904bdeff36d54e6ea5fe5f81a245a96c1b73ebe37e956ce11d/patchright-1.51.3-py3-none-win_amd64.whl @@ -5623,7 +5623,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/74/0f/5312b944208efeec5dcbf8e0ed956f8f7c430b0c6458301d206380c90b56/litellm-1.81.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/df/e6/a170e6ae3492d8e334a6ce9e39668f2b8d0cb0a158804460b5d851315230/maxminddb-3.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/70/cb/e7cd2f6161e30a4009cf38dd00024b1303197afcd4297081b0ccd21016a8/patchright-1.51.3-py3-none-manylinux1_x86_64.whl @@ -5985,7 +5985,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/74/0f/5312b944208efeec5dcbf8e0ed956f8f7c430b0c6458301d206380c90b56/litellm-1.81.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ec/3d/c22a117c1c6ca42a62be9473f12d113e2eab72ac28c032a290d0fbbd488e/maxminddb-3.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/81/09/e6126d32175f96ea963616debbb8e380e7c987ca913efeb59bf7e7f39438/patchright-1.51.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl @@ -6300,7 +6300,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/74/0f/5312b944208efeec5dcbf8e0ed956f8f7c430b0c6458301d206380c90b56/litellm-1.81.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d6/c8/76b3c0ea1f180209496cb401892a4ad197ee23ac1f370da578fffa466418/maxminddb-3.0.0-cp313-cp313-macosx_10_13_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1a/55/d62c85fff36e9e9e515ee92407b02acb556e6832d4fbcc8624b638cf70bb/patchright-1.51.3-py3-none-macosx_11_0_universal2.whl @@ -6615,7 +6615,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/74/0f/5312b944208efeec5dcbf8e0ed956f8f7c430b0c6458301d206380c90b56/litellm-1.81.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b6/96/b2d5ab37458ec892d7d52b6a9e6aa9992354d61df20b9978bae60e35d17a/maxminddb-3.0.0-cp313-cp313-macosx_11_0_arm64.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/55/20/4df3f817c28938e22ee7c7c4b28d8b3a212e5a111c3bd9633bc410267daa/patchright-1.51.3-py3-none-macosx_11_0_arm64.whl @@ -6920,7 +6920,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/74/0f/5312b944208efeec5dcbf8e0ed956f8f7c430b0c6458301d206380c90b56/litellm-1.81.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/4b/19/a498bf14a86e98475d4ca994988e8f072dccfd407d026403ad95725321de/maxminddb-3.0.0-cp313-cp313-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/6e/fd/97e3e26893904bdeff36d54e6ea5fe5f81a245a96c1b73ebe37e956ce11d/patchright-1.51.3-py3-none-win_amd64.whl @@ -7253,7 +7253,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/74/0f/5312b944208efeec5dcbf8e0ed956f8f7c430b0c6458301d206380c90b56/litellm-1.81.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/df/e6/a170e6ae3492d8e334a6ce9e39668f2b8d0cb0a158804460b5d851315230/maxminddb-3.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/70/cb/e7cd2f6161e30a4009cf38dd00024b1303197afcd4297081b0ccd21016a8/patchright-1.51.3-py3-none-manylinux1_x86_64.whl @@ -7617,7 +7617,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/74/0f/5312b944208efeec5dcbf8e0ed956f8f7c430b0c6458301d206380c90b56/litellm-1.81.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ec/3d/c22a117c1c6ca42a62be9473f12d113e2eab72ac28c032a290d0fbbd488e/maxminddb-3.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/81/09/e6126d32175f96ea963616debbb8e380e7c987ca913efeb59bf7e7f39438/patchright-1.51.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl @@ -7935,7 +7935,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/74/0f/5312b944208efeec5dcbf8e0ed956f8f7c430b0c6458301d206380c90b56/litellm-1.81.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d6/c8/76b3c0ea1f180209496cb401892a4ad197ee23ac1f370da578fffa466418/maxminddb-3.0.0-cp313-cp313-macosx_10_13_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1a/55/d62c85fff36e9e9e515ee92407b02acb556e6832d4fbcc8624b638cf70bb/patchright-1.51.3-py3-none-macosx_11_0_universal2.whl @@ -8253,7 +8253,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/74/0f/5312b944208efeec5dcbf8e0ed956f8f7c430b0c6458301d206380c90b56/litellm-1.81.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b6/96/b2d5ab37458ec892d7d52b6a9e6aa9992354d61df20b9978bae60e35d17a/maxminddb-3.0.0-cp313-cp313-macosx_11_0_arm64.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/55/20/4df3f817c28938e22ee7c7c4b28d8b3a212e5a111c3bd9633bc410267daa/patchright-1.51.3-py3-none-macosx_11_0_arm64.whl @@ -8561,7 +8561,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/74/0f/5312b944208efeec5dcbf8e0ed956f8f7c430b0c6458301d206380c90b56/litellm-1.81.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/4b/19/a498bf14a86e98475d4ca994988e8f072dccfd407d026403ad95725321de/maxminddb-3.0.0-cp313-cp313-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/6e/fd/97e3e26893904bdeff36d54e6ea5fe5f81a245a96c1b73ebe37e956ce11d/patchright-1.51.3-py3-none-win_amd64.whl @@ -8816,7 +8816,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b0/73/6e1b01cbeb458807aa0831742232dbdd1fa92bfa33f52a3f176b4ff3dc11/multidict-6.7.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/60/90/81ac364ef94209c100e12579629dc92bf7a709a84af32f8c551b02c07e94/nltk-3.9.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ba/87/d341e519956273b39d8d47969dd1eaa1af740615394fe67d06f1efa68773/numpy-2.4.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl @@ -9152,7 +9152,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f6/32/befed7f74c458b4a525e60519fe8d87eef72bb1e99924fa2b0f9d97a221e/multidict-6.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl - pypi: https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/60/90/81ac364ef94209c100e12579629dc92bf7a709a84af32f8c551b02c07e94/nltk-3.9.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8c/a4/77333f4d1e4dac4395385482557aeecf4826e6ff517e32ca48e1dafbe42a/numpy-2.4.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl @@ -9429,7 +9429,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/75/bc704ae15fee974f8fccd871305e254754167dce5f9e42d88a2def741a1d/multidict-6.7.1-cp313-cp313-macosx_10_13_x86_64.whl - pypi: https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/60/90/81ac364ef94209c100e12579629dc92bf7a709a84af32f8c551b02c07e94/nltk-3.9.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/04/68/732d4b7811c00775f3bd522a21e8dd5a23f77eb11acdeb663e4a4ebf0ef4/numpy-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl @@ -9708,7 +9708,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/60/90/81ac364ef94209c100e12579629dc92bf7a709a84af32f8c551b02c07e94/nltk-3.9.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/20/ca/857722353421a27f1465652b2c66813eeeccea9d76d5f7b74b99f298e60e/numpy-2.4.1-cp313-cp313-macosx_11_0_arm64.whl @@ -9984,7 +9984,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b2/35/e994121b0e90e46134673422dd564623f93304614f5d11886b1b3e06f503/multidict-6.7.1-cp313-cp313-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/08/b83b94a2b10ee7d27dddff4812a188e6669e520dafccb590613a90fa9d76/nlr_rex-0.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/60/90/81ac364ef94209c100e12579629dc92bf7a709a84af32f8c551b02c07e94/nltk-3.9.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/da/a6/cf32198b0b6e18d4fbfa9a21a992a7fca535b9bb2b0cdd217d4a3445b5ca/numpy-2.4.1-cp313-cp313-win_amd64.whl @@ -16692,8 +16692,8 @@ packages: timestamp: 1736252433366 - pypi: ./ name: infra-compass - version: 0.13.2.dev5+g2a2cf74.d20260210 - sha256: 14c80efebd7b5a7937d34c6e5de47a023a4ffc6e29953d0d7267c4c258816d68 + version: 0.14.3.dev1+g360e5737.d20260225 + sha256: 9bbb41f6f8c7ce45a34bf0e5c6928e2cd43839673aaf7afb4def56e81d769235 requires_dist: - beautifulsoup4>=4.12.3,<5 - click>=8.1.7,<9 @@ -16701,7 +16701,7 @@ packages: - langchain-text-splitters>=1.0.0,<2 - networkx>=3.4.2,<4 - nltk>=3.9.1,<4 - - nlr-elm>=0.0.36,<1 + - nlr-elm>=0.0.37,<1 - numpy>=2.2.4,<3 - openai>=1.1.0 - pandas>=2.2.3,<3 @@ -24013,10 +24013,10 @@ packages: - pkg:pypi/networkx?source=compressed-mapping size: 1587439 timestamp: 1765215107045 -- pypi: https://files.pythonhosted.org/packages/1a/8d/4835465b88ff6aabfffe7993a72d2407423cb62ebfda4ee5cccc0963b10e/nlr_elm-0.0.36-py3-none-any.whl +- pypi: https://files.pythonhosted.org/packages/e9/67/96ed125a5cb01f0f759529a067083037fd1145be7e6ddf43510b9bf39fac/nlr_elm-0.0.37-py3-none-any.whl name: nlr-elm - version: 0.0.36 - sha256: 98838225203b55bfb59ea8bf73b7d9ad983cb743338c7fc976bd01af73f23c7b + version: 0.0.37 + sha256: 4410a9631384f06c9ec96eb8f26d83d829b32b9c67840a64a72f818715f24f6b requires_dist: - openai>=1.1.0 - aiohttp diff --git a/pyproject.toml b/pyproject.toml index 1aa80168..69a4953a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,7 +38,7 @@ dependencies = [ "langchain-text-splitters>=1.0.0,<2", "networkx>=3.4.2,<4", "nltk>=3.9.1,<4", - "nlr-elm>=0.0.36,<1", + "nlr-elm>=0.0.37,<1", "numpy>=2.2.4,<3", "openai>=1.1.0", "pandas>=2.2.3,<3", From 874561b78ba71a3382a71dc96ecea9cbc77bc622 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Mon, 9 Mar 2026 12:10:42 -0600 Subject: [PATCH 03/44] Minor prompt update --- compass/common/base.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compass/common/base.py b/compass/common/base.py index c284c091..308e816f 100644 --- a/compass/common/base.py +++ b/compass/common/base.py @@ -737,9 +737,9 @@ def _add_value_and_units_clarification_nodes(G): # noqa: N803 "1) Extract only the explicit numerical value provided for " "the restriction. Do not infer values from related " "restrictions.\n" - "2) If multiple values are given, select the most restrictive " - "one (i.e., the smallest allowable limit, the lowest maximum, " - "etc.).\n" + "2) If multiple **applicable** values are given, select the most " + "restrictive one (i.e., the smallest allowable limit, the lowest " + "maximum, etc.).\n" "3) Please focus only on {restriction} that would apply for " "{system_size_reminder}\n" "4) Pay close attention to clarifying details in parentheses, " @@ -775,9 +775,9 @@ def _add_value_and_units_clarification_nodes(G): # noqa: N803 "2) The unit is expressed using standard, conventional unit " "names (e.g., 'feet', 'meters', 'acres', 'dBA', etc.). " "{unit_clarification}\n" - "3) If multiple values are mentioned, return only the units " - "for the most restrictive value that directly pertains to the " - "restriction.\n" + "3) If multiple **applicable** values are mentioned, return only " + "the units for the most restrictive value that directly pertains " + "to the restriction.\n" "\nExample Inputs and Outputs:\n" "Text: 'For all WES there is a limitation of overall height " "of 200 feet (including blades).'\n" From 0b0ea61724dfd8b625b480056788d9ddec3d6db7 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Tue, 10 Mar 2026 14:59:32 -0600 Subject: [PATCH 04/44] Update lockfile --- pixi.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pixi.lock b/pixi.lock index 7706bf88..6b38a270 100644 --- a/pixi.lock +++ b/pixi.lock @@ -16692,8 +16692,8 @@ packages: timestamp: 1736252433366 - pypi: ./ name: infra-compass - version: 0.14.3.dev20+gbb9a53e6.d20260309 - sha256: cef76fd52eb2f0853ed265397d062b290dfc3c508bfccc8d19c5e0bd95574e34 + version: 0.15.1.dev4+g6fe3c864 + sha256: 8510ce98ab5a11f50a1cd3d5d5f797788a2d3005f54f27b6707b68eef772c014 requires_dist: - beautifulsoup4>=4.12.3,<5 - click>=8.1.7,<9 From 7ceef99ba4ace2f09936a3337993575ba741832d Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Tue, 10 Mar 2026 15:01:01 -0600 Subject: [PATCH 05/44] Fix linter --- crates/compass/src/scraper/ordinance/qualitative.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/compass/src/scraper/ordinance/qualitative.rs b/crates/compass/src/scraper/ordinance/qualitative.rs index 006b8694..9020a3b8 100644 --- a/crates/compass/src/scraper/ordinance/qualitative.rs +++ b/crates/compass/src/scraper/ordinance/qualitative.rs @@ -140,7 +140,9 @@ pub(crate) mod sample { pub(crate) fn basic() -> String { let mut output = String::new(); - output.push_str("county,state,subdivison,jurisdiction_type,FIPS,feature,summary,year,section,source\n"); + output.push_str( + "county,state,subdivison,jurisdiction_type,FIPS,feature,summary,year,section,source\n" + ); output.push_str( "county-1,state-1,,jurisdiction_type-1,11111,feature-1,summary-1,2001,section-1,source-1\n", ); From 8f86ab76b7c5bf899b179fb5c6c3d97a8df49a97 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Wed, 11 Mar 2026 16:12:33 -0600 Subject: [PATCH 06/44] Documentation updates --- compass/scripts/process.py | 2 +- examples/execution_basics/README.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compass/scripts/process.py b/compass/scripts/process.py index a71a1ecb..518cc53e 100644 --- a/compass/scripts/process.py +++ b/compass/scripts/process.py @@ -188,7 +188,7 @@ async def process_jurisdictions_with_openai( # noqa: PLR0917, PLR0913 name ``"gpt-4o-mini-2025-04-11"``, you would want to set ``"model": "gpt-4o-mini-2025-04-11"``. - By default, ``"gpt-4o"``. + By default, ``"gpt-4o-mini"``. num_urls_to_check_per_jurisdiction : int, optional Number of unique Google search result URLs to check for each jurisdiction when attempting to locate ordinance documents. diff --git a/examples/execution_basics/README.rst b/examples/execution_basics/README.rst index cae42ee3..a95de654 100644 --- a/examples/execution_basics/README.rst +++ b/examples/execution_basics/README.rst @@ -56,12 +56,12 @@ Your LLM credentials and endpoints should be configured as environment variables **LLM Model Defaults** -This minimal setup uses the default LLM model for INFRA-COMPASS — ``gpt-4o`` as of April 11, 2025. +This minimal setup uses the default LLM model for INFRA-COMPASS — ``gpt-4o-mini`` as of March 11, 2026. To override this default, add a ``model`` key to your config: .. code-block:: json - "model": "gpt-4o-mini" + "model": "gpt-4o" .. IMPORTANT:: From 4ae511b23631c06f98714ab58501ad95bc1ba045 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Wed, 11 Mar 2026 17:24:08 -0600 Subject: [PATCH 07/44] First pass of GHP schema --- .../ghp/geothermal_heat_pump_schema.json5 | 262 ++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100644 compass/extraction/ghp/geothermal_heat_pump_schema.json5 diff --git a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 new file mode 100644 index 00000000..ba478edd --- /dev/null +++ b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 @@ -0,0 +1,262 @@ +{ + "title": "Geothermal Heat Pump Ordinance Extraction Schema", + "description": "Single-shot structured extraction schema for geothermal heat pump (GHP) and ground source heat pump ordinances. This schema guides an LLM to extract all relevant features in one call and returns an outputs array where each object represents one row in the extracted long-form table.", + "version": "1.0.0", + "type": "object", + "required": ["outputs"], + "additionalProperties": false, + "properties": { + "outputs": { + "type": "array", + "items": { + "type": "object", + "required": ["feature", "value", "units", "section", "summary"], + "additionalProperties": false, + "properties": { + "feature": { + "type": "string", + "description": "The ordinance feature being extracted. Must be one of the enumerated feature IDs.", + "enum": [ + "driveways", + "private water", + "public water", + "building foundation", + "wastewater", + "water line", + "sewer line", + "animal enclosures", + "roads", + "row", + "above ground fuel", + "below ground fuel", + "subsurface drains", + "wetlands", + "pools", + "hmat", + "noise", + "minimum well depth", + "maximum well depth", + "well definition", + "geothermal definition", + "ghp definition", + "licensed driller", + "screening", + "permit", + "inspection", + "decommissioning", + "prohibitions cl", + "prohibitions ol", + "prohibitions other" + ] + }, + "value": { + "description": "The extracted ordinance value. For numerical setbacks/limits, use a number. For categorical outcomes, use a string. For fields that list multiple named items, use an array of strings. For any feature listed in $qualitative_features, set value to null and rely on summary for the ordinance excerpt.", + "anyOf": [ + {"type": "number"}, + {"type": "string"}, + {"type": "array", "items": {"type": "string"}, "additionalProperties": false}, + {"type": "null"} + ] + }, + "units": { + "type": ["string", "null"], + "description": "Units for the extracted value. Use standard unit names whenever possible while accurately reflecting the ordinance text. For setbacks/depth, use linear units such as 'feet' or 'meters'. For noise, use 'dBA' unless the ordinance clearly specifies another unit. Use null for qualitative fields without measurable units." + }, + "section": { + "type": ["string", "null"], + "description": "The section title or number where the requirement appears (e.g., 'SECTION 1308 – Performance / Construction Standards'). Include labels/numbers if available. Null if no section identifier is available." + }, + "summary": { + "type": "string", + "description": "A short summary with direct ordinance excerpts/quotes whenever possible. For qualitative features (definitions, permitting, screening, inspection, decommissioning, prohibitions), this is the primary output field and should contain a direct ordinance excerpt." + } + } + } + } + }, + "$definitions": { + "scope_context": { + "description": "CRITICAL: Only extract requirements that apply to geothermal heat pump / ground source heat pump systems, including closed-loop and open-loop systems where relevant. Do NOT consider unrelated geothermal electricity generation rules unless the text clearly governs heat pump exchange wells/loops." + }, + "setback_features": { + "description": "Setback features for GHP-related components. Treat each setback feature independently; do NOT cross-apply a setback unless the ordinance text **explicitly** states that it applies to multiple feature types. If a single feature has multiple setback values, choose the most restrictive value, but **only** when the ordinance clearly shows that each value applies to GHP systems **for that same feature**.", + "properties": { + "driveways": { + "description": "Minimum required separation from driveways or drive areas. IGNORE: Do not respond based on setbacks from other kinds of right-of-way such as roads or utility easements, etc." + }, + "private water": { + "description": "Minimum required separation from private water supplies, such as drinking water wells or private water supplies. IGNORE: Do not respond based on setbacks from **public** water supply wells, water lines, sewer lines, pools, wetlands, etc." + }, + "public water": { + "description": "Minimum required separation from public water supply wells, intakes, or related infrastructure. IGNORE: Do not respond based on setbacks from **private** water supply wells, water lines, sewer lines, pools, wetlands, etc." + }, + "building foundation": { + "description": "Minimum required separation from building or structure foundations." + }, + "wastewater": { + "description": "Minimum required separation from onsite wastewater systems, septic tanks, leach fields, cesspools, or related infrastructure." + }, + "water line": { + "description": "Minimum required separation from water service lines and related service piping." + }, + "sewer line": { + "description": "Minimum required separation from sanitary/storm sewer lines." + }, + "animal enclosures": { + "description": "Minimum required separation from animal enclosures, barns, pens, or similar livestock areas." + }, + "roads": { + "description": "Minimum required separation from public road rights-of-way. IGNORE: Do not respond based on setbacks from other kinds of right-of-way such as utility easements, etc." + }, + "row": { + "description": "Minimum required separation from any right-of-way or utility/drainage/access easements not already captured under road right-of-way. IGNORE: Do not respond based on setbacks from roads or driveways." + }, + "above ground fuel": { + "description": "Minimum required separation from above-ground fuel tanks or storage areas. IGNORE: Do not respond based on setbacks from **underground** fuel tanks or storage areas." + }, + "below ground fuel": { + "description": "Minimum required separation from underground fuel tanks or storage areas. IGNORE: Do not respond based on setbacks from **above-ground** fuel tanks or storage areas." + }, + "subsurface drains": { + "description": "Minimum required separation from subsurface drains, tile drains, or underdrain systems." + }, + "wetlands": { + "description": "Minimum required separation from streams, lakes, ponds, rivers, floodplains, wetlands, or other surface waters. IGNORE: Do not respond based on setbacks from water lines, sewer lines, private/public water supplies, swimming pools, etc." + }, + "pools": { + "description": "Minimum required separation from swimming pools, spas, or similar water recreation structures. IGNORE: Do not respond based on setbacks from water lines, sewer lines, private/public water supplies, wetlands, etc." + }, + "hmat": { + "description": "Minimum required separation from hazardous materials storage, chemical storage, or fertilizer storage/handling areas." + } + } + }, + "numerical_features": { + "description": "Non-setback numerical restriction features. Only extract if numerical values are explicitly given in the text.", + "properties": { + "noise": { + "description": "Extract maximum allowable operational noise for GHP systems, if explicitly stated. Use most restrictive value when multiple limits are present." + }, + "minimum well depth": { + "description": "Extract **minimum** depth requirements for boreholes/wells, including conditional limits by geology or aquifer protection zones." + }, + "maximum well depth": { + "description": "Extract **maximum** depth limits or depth-related requirements for boreholes/wells, including conditional limits by geology or aquifer protection zones." + } + } + }, + "definition_features": { + "description": "Definitions of certain terms, preferably as direct excerpts from ordinance definitions sections (non-numerical)", + "properties": { + "well definition": { + "description": "Extract the ordinance definition text for 'Geothermal Well' (or equivalent term)." + }, + "geothermal definition": { + "description": "Extract the ordinance definition text for 'Geothermal'." + }, + "ghp definition": { + "description": "Extract the ordinance definition text for 'ground source heat pump system', 'geothermal heat pump system', or equivalent term." + } + } + }, + "operational_features": { + "description": "Operational, licensing, permitting, inspection, and abandonment requirements. These are non-numerical restriction features that require text extraction", + "properties": { + "licensed driller": { + "description": "Extract requirements that drilling be performed by a licensed/certified driller, contractor, or installer, including credential details when provided." + }, + "screening": { + "description": "Extract requirements for visual or physical screening (fencing, landscaping, enclosures) of above-ground geothermal equipment." + }, + "permit": { + "description": "Extract permit requirements (building, mechanical, environmental, well, zoning, health department approvals), including triggering conditions." + }, + "inspection": { + "description": "Extract required inspections (pre-drilling, during installation, final inspection, pressure testing, health/environmental inspections) and responsible authority." + }, + "decommissioning": { + "description": "Extract requirements for abandonment, plugging, sealing, removal, and site restoration when systems are retired or wells are abandoned." + } + } + }, + "prohibition_features": { + "description": "Prohibitions, bans, or moratoria", + "properties": { + "prohibitions cl": { + "description": "Extract whether **closed-loop** geothermal systems are explicitly prohibited or under moratorium. CRITICAL: Only extract prohibitions that are **unconditional** and **currently in effect** (not proposed). Moratoria may be temporary; if a moratorium has a stated end date, include that date explicitly in the output summary. If the jurisdiction allows closed-loop geothermal systems in any capacity (with permits, conditions, etc.), this is NOT a prohibition." + }, + "prohibitions ol": { + "description": "Extract whether **open-loop** geothermal systems are explicitly prohibited or under moratorium. CRITICAL: Only extract prohibitions that are **unconditional** and **currently in effect** (not proposed). Moratoria may be temporary; if a moratorium has a stated end date, include that date explicitly in the output summary. If the jurisdiction allows open-loop geothermal systems in any capacity (with permits, conditions, etc.), this is NOT a prohibition." + }, + "prohibitions other": { + "description": "Extract any other geothermal-related prohibitions or moratoria not captured above (for example: standing-column wells, discharge methods, antifreeze restrictions, district-specific bans)." + } + } + } + }, + "$examples": [ + { + "outputs": [ + { + "feature": "private water", + "value": 100, + "units": "feet", + "section": "Section 8.3 - Well Siting Standards", + "summary": "'No geothermal borehole shall be located within one hundred (100) feet of any private drinking water well.'" + }, + { + "feature": "licensed driller", + "value": null, + "units": null, + "section": "Section 6.1 - Contractor Qualifications", + "summary": "'All geothermal wells shall be drilled by a state-licensed well driller in good standing.'" + }, + { + "feature": "prohibitions ol", + "value": null, + "units": null, + "section": "Section 12.4 - GEOTHERMAL ENERGY SYSTEM STANDARDS", + "summary": "'Only closed loop ground source heat pump systems utilizing heat transfer fluids as defined in this Zoning Code are permitted. Open loop ground source heat pump systems are not permitted.'" + } + ] + } + ], + "$instructions": { + "general": [ + "Extract **only enacted ordinance requirements** for **geothermal heat pump / ground source heat pump systems**.", + "Use direct text excerpts and quotes in summary whenever possible.", + "For each numerical feature, capture the most restrictive applicable value when multiple values are provided and explain alternatives in summary.", + "If no requirement is found for a feature, omit that feature from outputs.", + "The outputs array is a sparse long-form extraction table and does not need to contain every enumerated feature.", + "Do not infer regulatory restrictions for non-definition features from definitions alone unless the text clearly creates an enforceable rule." + ], + "setbacks": [ + "Setbacks should be extracted as minimum separation distances.", + "Prefer numeric values with units ('feet', 'meters').", + "If both general and condition-specific setbacks are provided, select the controlling value for the scenario and describe conditions in summary.", + "Do not conflate road right-of-way with general right-of-way/easement unless ordinance text makes them equivalent." + ], + "definitions": [ + "Definitions are qualitative text extractions; the value field should be null with definition text placed directly in the summary.", + "Preserve legal phrasing and term boundaries from ordinance language." + ], + "prohibitions": [ + "Classify prohibitions as currently effective bans/moratoria/restrictions based on the text.", + "If no active prohibition is found for a prohibition feature, omit that feature from outputs instead of using placeholder values.", + "Distinguish between complete prohibition and conditional permitting. Conditional permitting is not a ban." + ] + }, + "$qualitative_features": [ + "well definition", + "geothermal definition", + "ghp definition", + "licensed driller", + "screening", + "permit", + "inspection", + "decommissioning", + "prohibitions cl", + "prohibitions ol", + "prohibitions other" + ] +} From c8a0a8c58839367d5ae27fe0d8f8ffdb61f59f09 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Wed, 11 Mar 2026 18:04:45 -0600 Subject: [PATCH 08/44] Add basic plugin config --- compass/extraction/ghp/plugin_config.yaml | 97 +++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 compass/extraction/ghp/plugin_config.yaml diff --git a/compass/extraction/ghp/plugin_config.yaml b/compass/extraction/ghp/plugin_config.yaml new file mode 100644 index 00000000..9967d80b --- /dev/null +++ b/compass/extraction/ghp/plugin_config.yaml @@ -0,0 +1,97 @@ +schema: ./geothermal_heat_pump_schema.json5 + +data_type_short_desc: geothermal ground source heat pump ordinance + +query_templates: + - "{jurisdiction} geothermal ground source heat pump code" + - "filetype:pdf {jurisdiction} geothermal heat pump ordinance" + - "{jurisdiction} geothermal energy system ordinance" + - "Where can I find the legal text for geothermal heat pump zoning ordinances in {jurisdiction}?" + - "What is the specific legal information regarding zoning ordinances for geothermal heat pumps in {jurisdiction}?" + +website_keywords: + # These still need massaging + # - e.g. include something about open loop or closed loop? + pdf: 92160 + pump: 46080 + geothermal: 23040 + ordinance: 11520 + zoning: 5760 + regulation: 2880 + code: 1440 + heating: 1440 + planning: 720 + government: 180 + +heuristic_keywords: + good_tech_acronyms: + - "ghp" + - "gshp" + good_tech_keywords: + - "geoexchange" + - "geo-exchange" + - "wellfield" + - "direct-use" + - "closed-loop" + good_tech_phrases: + - "well field" + - "geothermal resource" + - "geothermal drilling" + - "geothermal well" + - "geothermal reservoir" + - "geothermal permit" + - "geothermal ordinance" + - "geothermal zoning" + - "closed loop" + - "open loop" + - "vertical loop" + - "horizontal loop" + - "heating and cooling" + - "space heating" + - "direct use" + - "district heating" + - "greenhouse heating" + - "residential geothermal" + - "heat pump" + - "geothermal heat pump" + - "ground source heat pump" + - "ground-source heat pump" + - "ground heat pump" + - "ground-coupled heat pump" + - "ground coupled heat pump" + - "earth-coupled heat pump" + - "earth-source heat pump" + - "closed loop ground source" + - "open loop ground source" + not_tech_words: + - "production well" + - "geothermal exploration" + - "geothermal generating" + - "geothermal generation" + - "geothermal power" + - "geothermal production" + - "geothermal project" + - "geothermal overlay zone" + - "geothermal power plant" + - "geothermal facility" + - "geothermal electric" + - "geothermal energy facility" + - "geothermal lease" + - "geothermal development" + - "steam turbine" + - "binary cycle" + - "flash steam" + - "dry steam" + - "enhanced geothermal" + - "reservoir temperature" + - "reinjection well" + - "production zone" + - "geothermal production project" + - "exploratory well" + - "injection well" + +collection_prompts: True + +extraction_system_prompt: |- + You are a legal scholar extracting structured data from geothermal ground source heat pump ordinances. + Follow all instructions in the schema descriptions carefully. From 0cee1ea3d55d3c578eafa781533739135e36d86c Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Wed, 11 Mar 2026 18:04:53 -0600 Subject: [PATCH 09/44] Wire up GHP plugin --- compass/__init__.py | 5 +++-- compass/extraction/__init__.py | 5 +++-- compass/extraction/ghp/__init__.py | 13 +++++++++++++ 3 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 compass/extraction/ghp/__init__.py diff --git a/compass/__init__.py b/compass/__init__.py index c048d1a7..52435a92 100644 --- a/compass/__init__.py +++ b/compass/__init__.py @@ -6,9 +6,10 @@ # Temporarily import to register plugins # Can drop once plugins register themselves from .extraction import ( - COMPASSWindExtractor, - COMPASSSolarExtractor, + COMPASSGeoHeatPumpExtractor, COMPASSSmallWindExtractor, + COMPASSSolarExtractor, + COMPASSWindExtractor, TexasWaterRightsExtractor, ) diff --git a/compass/extraction/__init__.py b/compass/extraction/__init__.py index 2ee97718..fed7f61f 100644 --- a/compass/extraction/__init__.py +++ b/compass/extraction/__init__.py @@ -10,7 +10,8 @@ # Temporarily import to register plugins # Can drop once plugins register themselves -from .wind import COMPASSWindExtractor -from .solar import COMPASSSolarExtractor +from .ghp import COMPASSGeoHeatPumpExtractor from .small_wind import COMPASSSmallWindExtractor +from .solar import COMPASSSolarExtractor from .water import TexasWaterRightsExtractor +from .wind import COMPASSWindExtractor diff --git a/compass/extraction/ghp/__init__.py b/compass/extraction/ghp/__init__.py new file mode 100644 index 00000000..a66f25ac --- /dev/null +++ b/compass/extraction/ghp/__init__.py @@ -0,0 +1,13 @@ +"""COMPASS Geothermal ground source heat pump plugin""" + +import importlib.resources + +from compass.plugin import create_schema_based_one_shot_extraction_plugin + + +COMPASSGeoHeatPumpExtractor = create_schema_based_one_shot_extraction_plugin( + importlib.resources.files("compass.extraction.ghp") + # / "ghp" + / "plugin_config.yaml", + tech="ghp", +) From 1e1139e9f253a251109b9cae57911e484bef9b77 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Wed, 11 Mar 2026 18:05:07 -0600 Subject: [PATCH 10/44] Have function return created class --- compass/plugin/one_shot/base.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/compass/plugin/one_shot/base.py b/compass/plugin/one_shot/base.py index 5570f182..e5254a73 100644 --- a/compass/plugin/one_shot/base.py +++ b/compass/plugin/one_shot/base.py @@ -133,6 +133,12 @@ def create_schema_based_one_shot_extraction_plugin(config, tech): # noqa: C901 Technology identifier to use for the plugin (e.g., "wind", "solar"). Must be unique from the identifiers of any existing plugins. + + Returns + ------- + callable + A `SchemaBasedExtractionPlugin` subclass configured according to + the input configuration. """ if not isinstance(config, dict): config = load_config(config) @@ -401,6 +407,7 @@ def _validate_website_keywords(self): """ register_plugin(SchemaBasedExtractionPlugin) + return SchemaBasedExtractionPlugin def _collectors_from_config(config): From c9baf2ee028755ed64bd2b54f063a35227a69b49 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Thu, 12 Mar 2026 12:24:37 -0600 Subject: [PATCH 11/44] Clarification for noise --- compass/extraction/ghp/geothermal_heat_pump_schema.json5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 index ba478edd..107f61cd 100644 --- a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 +++ b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 @@ -135,7 +135,7 @@ "description": "Non-setback numerical restriction features. Only extract if numerical values are explicitly given in the text.", "properties": { "noise": { - "description": "Extract maximum allowable operational noise for GHP systems, if explicitly stated. Use most restrictive value when multiple limits are present." + "description": "Extract maximum allowable operational noise for GHP systems only when an explicit numeric limit is stated (for example, a dBA threshold). If the ordinance only references compliance with other standards or provides no numeric noise limit, omit this feature. Use most restrictive value when multiple limits are present." }, "minimum well depth": { "description": "Extract **minimum** depth requirements for boreholes/wells, including conditional limits by geology or aquifer protection zones." From d38d6c387c52ce232b5f1b3182039aede03f691a Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Thu, 12 Mar 2026 12:25:52 -0600 Subject: [PATCH 12/44] Clarification for setbacks --- compass/extraction/ghp/geothermal_heat_pump_schema.json5 | 1 + 1 file changed, 1 insertion(+) diff --git a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 index 107f61cd..38f4e84e 100644 --- a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 +++ b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 @@ -233,6 +233,7 @@ "setbacks": [ "Setbacks should be extracted as minimum separation distances.", "Prefer numeric values with units ('feet', 'meters').", + "If a statement does not provide a numeric distance for a setback feature (for example, 'shall not encroach'), omit that setback feature from outputs.", "If both general and condition-specific setbacks are provided, select the controlling value for the scenario and describe conditions in summary.", "Do not conflate road right-of-way with general right-of-way/easement unless ordinance text makes them equivalent." ], From 3a2f80a8f93d6116de574c7c4ee28d008f7fb441 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Thu, 12 Mar 2026 12:26:20 -0600 Subject: [PATCH 13/44] Clarification --- compass/extraction/ghp/geothermal_heat_pump_schema.json5 | 1 + 1 file changed, 1 insertion(+) diff --git a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 index 38f4e84e..d02fd7d1 100644 --- a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 +++ b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 @@ -227,6 +227,7 @@ "Use direct text excerpts and quotes in summary whenever possible.", "For each numerical feature, capture the most restrictive applicable value when multiple values are provided and explain alternatives in summary.", "If no requirement is found for a feature, omit that feature from outputs.", + "Never emit 'not found', 'no explicit requirement', 'none', or similar absence text in any field. Omit these features instead.", "The outputs array is a sparse long-form extraction table and does not need to contain every enumerated feature.", "Do not infer regulatory restrictions for non-definition features from definitions alone unless the text clearly creates an enforceable rule." ], From fdab6859fe51c688053513d83ec428a4ce7b0d10 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Thu, 12 Mar 2026 12:27:12 -0600 Subject: [PATCH 14/44] Use general guidance instead --- compass/extraction/ghp/geothermal_heat_pump_schema.json5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 index d02fd7d1..b0230e37 100644 --- a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 +++ b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 @@ -226,6 +226,7 @@ "Extract **only enacted ordinance requirements** for **geothermal heat pump / ground source heat pump systems**.", "Use direct text excerpts and quotes in summary whenever possible.", "For each numerical feature, capture the most restrictive applicable value when multiple values are provided and explain alternatives in summary.", + "For any numerical feature (including setback features such as roads and non-setback features such as noise), if no explicit numeric threshold is stated, omit that feature instead of returning null, empty, or qualitative-only values.", "If no requirement is found for a feature, omit that feature from outputs.", "Never emit 'not found', 'no explicit requirement', 'none', or similar absence text in any field. Omit these features instead.", "The outputs array is a sparse long-form extraction table and does not need to contain every enumerated feature.", @@ -234,7 +235,6 @@ "setbacks": [ "Setbacks should be extracted as minimum separation distances.", "Prefer numeric values with units ('feet', 'meters').", - "If a statement does not provide a numeric distance for a setback feature (for example, 'shall not encroach'), omit that setback feature from outputs.", "If both general and condition-specific setbacks are provided, select the controlling value for the scenario and describe conditions in summary.", "Do not conflate road right-of-way with general right-of-way/easement unless ordinance text makes them equivalent." ], From 3a995c95dddaa31d17c802caf945d6342601cfc9 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Thu, 12 Mar 2026 12:27:26 -0600 Subject: [PATCH 15/44] Add clarification to definitions --- compass/extraction/ghp/geothermal_heat_pump_schema.json5 | 1 + 1 file changed, 1 insertion(+) diff --git a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 index b0230e37..b6383ead 100644 --- a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 +++ b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 @@ -240,6 +240,7 @@ ], "definitions": [ "Definitions are qualitative text extractions; the value field should be null with definition text placed directly in the summary.", + "If a requested definition is not present, omit that feature entirely; do not emit placeholder text.", "Preserve legal phrasing and term boundaries from ordinance language." ], "prohibitions": [ From 405c4b35d7b88147eee309e96151e3846d45a9be Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Thu, 12 Mar 2026 12:27:50 -0600 Subject: [PATCH 16/44] Single row instruction --- compass/extraction/ghp/geothermal_heat_pump_schema.json5 | 1 + 1 file changed, 1 insertion(+) diff --git a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 index b6383ead..7c451ad4 100644 --- a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 +++ b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 @@ -225,6 +225,7 @@ "general": [ "Extract **only enacted ordinance requirements** for **geothermal heat pump / ground source heat pump systems**.", "Use direct text excerpts and quotes in summary whenever possible.", + "Each feature may appear **at most once** in outputs; do not emit multiple rows for the same feature. If multiple ordinance lines map to one feature, consolidate into one row and keep the controlling most restrictive value in value while listing alternatives in summary.", "For each numerical feature, capture the most restrictive applicable value when multiple values are provided and explain alternatives in summary.", "For any numerical feature (including setback features such as roads and non-setback features such as noise), if no explicit numeric threshold is stated, omit that feature instead of returning null, empty, or qualitative-only values.", "If no requirement is found for a feature, omit that feature from outputs.", From 7d7cc1916337f53cdeb2d4c5ac43d9b34cfab814 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Thu, 12 Mar 2026 12:28:01 -0600 Subject: [PATCH 17/44] Add clarification --- compass/extraction/ghp/geothermal_heat_pump_schema.json5 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 index 7c451ad4..bc57c290 100644 --- a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 +++ b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 @@ -244,6 +244,10 @@ "If a requested definition is not present, omit that feature entirely; do not emit placeholder text.", "Preserve legal phrasing and term boundaries from ordinance language." ], + "operational": [ + "For qualitative features: output only when an explicit enforceable requirement is present.", + "If no explicit requirement exists for one of these features, omit it from outputs instead of writing an absence statement." + ], "prohibitions": [ "Classify prohibitions as currently effective bans/moratoria/restrictions based on the text.", "If no active prohibition is found for a prohibition feature, omit that feature from outputs instead of using placeholder values.", From 60527cd0e6fd4aa429dc76d4df9e166827df9d57 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Thu, 12 Mar 2026 12:28:08 -0600 Subject: [PATCH 18/44] Allow nulls --- compass/extraction/ghp/geothermal_heat_pump_schema.json5 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 index bc57c290..e8294cc6 100644 --- a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 +++ b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 @@ -67,8 +67,8 @@ "description": "The section title or number where the requirement appears (e.g., 'SECTION 1308 – Performance / Construction Standards'). Include labels/numbers if available. Null if no section identifier is available." }, "summary": { - "type": "string", - "description": "A short summary with direct ordinance excerpts/quotes whenever possible. For qualitative features (definitions, permitting, screening, inspection, decommissioning, prohibitions), this is the primary output field and should contain a direct ordinance excerpt." + "type": ["string", "null"], + "description": "A short summary with direct ordinance excerpts/quotes whenever possible. For qualitative features (definitions, permitting, screening, inspection, decommissioning, prohibitions), this is the primary output field and should contain a direct ordinance excerpt. Do not output absence placeholders (for example, 'No explicit ... found'); omit the feature instead when no requirement is present." } } } From 980b7c63e71e3867c0de31525985bddbef76a758 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Thu, 12 Mar 2026 12:29:08 -0600 Subject: [PATCH 19/44] Add instruction --- compass/extraction/ghp/geothermal_heat_pump_schema.json5 | 1 + 1 file changed, 1 insertion(+) diff --git a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 index e8294cc6..a1e471bf 100644 --- a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 +++ b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 @@ -8,6 +8,7 @@ "properties": { "outputs": { "type": "array", + "description": "Sparse long-form extraction table. Include only features with an enacted, explicit requirement and emit **at most one row per feature**.", "items": { "type": "object", "required": ["feature", "value", "units", "section", "summary"], From 96d68a696f0b6115258a86484d61abb5a559a7ab Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Thu, 12 Mar 2026 12:29:30 -0600 Subject: [PATCH 20/44] update instructions --- compass/extraction/ghp/geothermal_heat_pump_schema.json5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 index a1e471bf..a99e5e09 100644 --- a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 +++ b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 @@ -51,7 +51,7 @@ ] }, "value": { - "description": "The extracted ordinance value. For numerical setbacks/limits, use a number. For categorical outcomes, use a string. For fields that list multiple named items, use an array of strings. For any feature listed in $qualitative_features, set value to null and rely on summary for the ordinance excerpt.", + "description": "The extracted ordinance value. For numerical setbacks/limits, use a number. For categorical outcomes, use a string. For fields that list multiple named items, use an array of strings. For any feature listed in $qualitative_features that is explicitly present in the ordinance, set value to null and rely on summary for the ordinance excerpt. If a feature is not explicitly present, omit that feature from outputs.", "anyOf": [ {"type": "number"}, {"type": "string"}, From ab80874c5d739b7c66494fba3b0624d2e1ee053c Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Thu, 12 Mar 2026 12:31:35 -0600 Subject: [PATCH 21/44] Update instructions around null --- compass/extraction/ghp/geothermal_heat_pump_schema.json5 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 index a99e5e09..ce2a8b15 100644 --- a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 +++ b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 @@ -51,7 +51,7 @@ ] }, "value": { - "description": "The extracted ordinance value. For numerical setbacks/limits, use a number. For categorical outcomes, use a string. For fields that list multiple named items, use an array of strings. For any feature listed in $qualitative_features that is explicitly present in the ordinance, set value to null and rely on summary for the ordinance excerpt. If a feature is not explicitly present, omit that feature from outputs.", + "description": "The extracted ordinance value. For numerical setbacks/limits, use a number. For categorical outcomes, use a string. For fields that list multiple named items, use an array of strings. Use null only for features listed in $qualitative_features, and only when an enacted, explicit, enforceable ordinance requirement for that feature is present. Null must never be used to indicate absence. If a feature has no enacted, explicit requirement in the ordinance text, omit that feature from outputs.", "anyOf": [ {"type": "number"}, {"type": "string"}, @@ -227,6 +227,7 @@ "Extract **only enacted ordinance requirements** for **geothermal heat pump / ground source heat pump systems**.", "Use direct text excerpts and quotes in summary whenever possible.", "Each feature may appear **at most once** in outputs; do not emit multiple rows for the same feature. If multiple ordinance lines map to one feature, consolidate into one row and keep the controlling most restrictive value in value while listing alternatives in summary.", + "Null is permitted only for features listed in $qualitative_features when an enacted, explicit requirement is present. Never use null to indicate that a feature was not found.", "For each numerical feature, capture the most restrictive applicable value when multiple values are provided and explain alternatives in summary.", "For any numerical feature (including setback features such as roads and non-setback features such as noise), if no explicit numeric threshold is stated, omit that feature instead of returning null, empty, or qualitative-only values.", "If no requirement is found for a feature, omit that feature from outputs.", From a70c03093ad1483bc7e3571531c31eba7959ead4 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Thu, 12 Mar 2026 12:42:15 -0600 Subject: [PATCH 22/44] Tighten schema --- .../ghp/geothermal_heat_pump_schema.json5 | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 index ce2a8b15..7071ac61 100644 --- a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 +++ b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 @@ -61,7 +61,7 @@ }, "units": { "type": ["string", "null"], - "description": "Units for the extracted value. Use standard unit names whenever possible while accurately reflecting the ordinance text. For setbacks/depth, use linear units such as 'feet' or 'meters'. For noise, use 'dBA' unless the ordinance clearly specifies another unit. Use null for qualitative fields without measurable units." + "description": "Units for the extracted value. Preserve the ordinance unit wording exactly whenever possible. For setbacks/depth, use linear units such as 'feet' or 'meters' as stated in text. For noise, use 'dBA' only if the ordinance says 'dBA' or 'dB(A)'; if it says 'dB' without A-weighting, keep 'dB'. Use null for qualitative fields without measurable units." }, "section": { "type": ["string", "null"], @@ -77,10 +77,10 @@ }, "$definitions": { "scope_context": { - "description": "CRITICAL: Only extract requirements that apply to geothermal heat pump / ground source heat pump systems, including closed-loop and open-loop systems where relevant. Do NOT consider unrelated geothermal electricity generation rules unless the text clearly governs heat pump exchange wells/loops." + "description": "CRITICAL: Only extract requirements that apply to geothermal heat pump / ground source heat pump systems, including closed-loop and open-loop systems where relevant. If text uses generic terms like 'geothermal well' or 'geothermal system', treat it as GHP only when section context clearly indicates heating/cooling or heat-pump exchange wells/loops. Do NOT consider unrelated geothermal electricity generation rules unless the text explicitly governs heat pump exchange wells/loops." }, "setback_features": { - "description": "Setback features for GHP-related components. Treat each setback feature independently; do NOT cross-apply a setback unless the ordinance text **explicitly** states that it applies to multiple feature types. If a single feature has multiple setback values, choose the most restrictive value, but **only** when the ordinance clearly shows that each value applies to GHP systems **for that same feature**.", + "description": "Setback features for GHP-related components. Treat each setback feature independently; do NOT cross-apply a setback unless the ordinance text **explicitly** states that it applies to multiple feature types. Mapping defaults: if text says 'right-of-way' without a qualifier, map to 'row'; if text says road/street right-of-way, map to 'roads'; if text says utility/drainage/access easement or utility right-of-way, map to 'row'. For water supplies, map generic 'water well(s)' or 'water supply well(s)' without a public/private qualifier to 'public water'; map to 'private water' only when private supply is explicit. If a single feature has multiple setback values, choose the most restrictive value, but **only** when the ordinance clearly shows that each value applies to GHP systems **for that same feature**.", "properties": { "driveways": { "description": "Minimum required separation from driveways or drive areas. IGNORE: Do not respond based on setbacks from other kinds of right-of-way such as roads or utility easements, etc." @@ -95,7 +95,7 @@ "description": "Minimum required separation from building or structure foundations." }, "wastewater": { - "description": "Minimum required separation from onsite wastewater systems, septic tanks, leach fields, cesspools, or related infrastructure." + "description": "Minimum required separation from onsite wastewater systems, septic tanks, leach fields, cesspools, or related sanitary wastewater infrastructure. Do not treat stormwater-only facilities as wastewater unless ordinance text explicitly does so." }, "water line": { "description": "Minimum required separation from water service lines and related service piping." @@ -104,7 +104,7 @@ "description": "Minimum required separation from sanitary/storm sewer lines." }, "animal enclosures": { - "description": "Minimum required separation from animal enclosures, barns, pens, or similar livestock areas." + "description": "Minimum required separation from animal enclosures, barns, pens, corrals, stables, or similar livestock areas explicitly named in ordinance text. Do not infer coverage for facilities not mentioned." }, "roads": { "description": "Minimum required separation from public road rights-of-way. IGNORE: Do not respond based on setbacks from other kinds of right-of-way such as utility easements, etc." @@ -122,7 +122,7 @@ "description": "Minimum required separation from subsurface drains, tile drains, or underdrain systems." }, "wetlands": { - "description": "Minimum required separation from streams, lakes, ponds, rivers, floodplains, wetlands, or other surface waters. IGNORE: Do not respond based on setbacks from water lines, sewer lines, private/public water supplies, swimming pools, etc." + "description": "Minimum required separation from streams, lakes, ponds, rivers, floodplains, wetlands, or other surface waters. Follow ordinance inclusions/exclusions for ditches, canals, detention basins, or constructed channels. IGNORE: Do not respond based on setbacks from water lines, sewer lines, private/public water supplies, swimming pools, etc." }, "pools": { "description": "Minimum required separation from swimming pools, spas, or similar water recreation structures. IGNORE: Do not respond based on setbacks from water lines, sewer lines, private/public water supplies, wetlands, etc." @@ -136,13 +136,13 @@ "description": "Non-setback numerical restriction features. Only extract if numerical values are explicitly given in the text.", "properties": { "noise": { - "description": "Extract maximum allowable operational noise for GHP systems only when an explicit numeric limit is stated (for example, a dBA threshold). If the ordinance only references compliance with other standards or provides no numeric noise limit, omit this feature. Use most restrictive value when multiple limits are present." + "description": "Extract maximum allowable operational noise for GHP systems only when an explicit numeric limit is stated. Keep units exactly as written in text ('dBA' only when text says 'dBA' or 'dB(A)'; keep 'dB' if unweighted). If the ordinance only references compliance with other standards or provides no numeric noise limit, omit this feature. When multiple limits are present (for example day/night or zoning classes), extract the most restrictive numeric value and list all variants in summary." }, "minimum well depth": { - "description": "Extract **minimum** depth requirements for boreholes/wells, including conditional limits by geology or aquifer protection zones." + "description": "Extract **minimum** depth requirements for boreholes/wells, including conditional limits by geology or aquifer protection zones. Most restrictive means the highest minimum depth value. If multiple conditional minimums exist, keep one row, store the controlling highest minimum in value, and list all condition-specific alternatives in summary." }, "maximum well depth": { - "description": "Extract **maximum** depth limits or depth-related requirements for boreholes/wells, including conditional limits by geology or aquifer protection zones." + "description": "Extract **maximum** depth limits or depth-related requirements for boreholes/wells, including conditional limits by geology or aquifer protection zones. Most restrictive means the lowest maximum depth value. If multiple conditional maximums exist, keep one row, store the controlling lowest maximum in value, and list all condition-specific alternatives in summary." } } }, @@ -164,19 +164,19 @@ "description": "Operational, licensing, permitting, inspection, and abandonment requirements. These are non-numerical restriction features that require text extraction", "properties": { "licensed driller": { - "description": "Extract requirements that drilling be performed by a licensed/certified driller, contractor, or installer, including credential details when provided." + "description": "Extract requirements that drilling be performed by a licensed/certified driller, contractor, or installer. Capture credential type and material qualification details when explicitly stated." }, "screening": { "description": "Extract requirements for visual or physical screening (fencing, landscaping, enclosures) of above-ground geothermal equipment." }, "permit": { - "description": "Extract permit requirements (building, mechanical, environmental, well, zoning, health department approvals), including triggering conditions." + "description": "Extract permit requirements that explicitly govern GHP installation, drilling, or operation (for example mechanical, geothermal well, environmental, zoning, or health approvals), including triggering conditions. Do not extract generic non-GHP permits unless the ordinance explicitly ties them to geothermal systems." }, "inspection": { - "description": "Extract required inspections (pre-drilling, during installation, final inspection, pressure testing, health/environmental inspections) and responsible authority." + "description": "Extract required inspections (pre-drilling, during installation, final inspection, pressure/flow testing, health/environmental inspections). Put inspection type(s) in value (string or array), and place responsible authority details in summary when stated." }, "decommissioning": { - "description": "Extract requirements for abandonment, plugging, sealing, removal, and site restoration when systems are retired or wells are abandoned." + "description": "Extract requirements for abandonment, plugging, sealing, removal, and site restoration when systems are retired, fail, or wells are abandoned, including responsible party and timeline details when explicitly stated." } } }, @@ -184,10 +184,10 @@ "description": "Prohibitions, bans, or moratoria", "properties": { "prohibitions cl": { - "description": "Extract whether **closed-loop** geothermal systems are explicitly prohibited or under moratorium. CRITICAL: Only extract prohibitions that are **unconditional** and **currently in effect** (not proposed). Moratoria may be temporary; if a moratorium has a stated end date, include that date explicitly in the output summary. If the jurisdiction allows closed-loop geothermal systems in any capacity (with permits, conditions, etc.), this is NOT a prohibition." + "description": "Extract whether **closed-loop** geothermal systems are explicitly prohibited or under moratorium. CRITICAL: Extract only when the text states an unconditional prohibition/moratorium that applies as written (not proposed). If there are carve-outs, exceptions, or conditional permitting in any capacity, this is NOT a prohibition feature. For moratoria, include start/end timing details in summary; if the ordinance states an end date that has already passed, omit this feature." }, "prohibitions ol": { - "description": "Extract whether **open-loop** geothermal systems are explicitly prohibited or under moratorium. CRITICAL: Only extract prohibitions that are **unconditional** and **currently in effect** (not proposed). Moratoria may be temporary; if a moratorium has a stated end date, include that date explicitly in the output summary. If the jurisdiction allows open-loop geothermal systems in any capacity (with permits, conditions, etc.), this is NOT a prohibition." + "description": "Extract whether **open-loop** geothermal systems are explicitly prohibited or under moratorium. CRITICAL: Extract only when the text states an unconditional prohibition/moratorium that applies as written (not proposed). If there are carve-outs, exceptions, or conditional permitting in any capacity, this is NOT a prohibition feature. For moratoria, include start/end timing details in summary; if the ordinance states an end date that has already passed, omit this feature." }, "prohibitions other": { "description": "Extract any other geothermal-related prohibitions or moratoria not captured above (for example: standing-column wells, discharge methods, antifreeze restrictions, district-specific bans)." @@ -228,23 +228,26 @@ "Use direct text excerpts and quotes in summary whenever possible.", "Each feature may appear **at most once** in outputs; do not emit multiple rows for the same feature. If multiple ordinance lines map to one feature, consolidate into one row and keep the controlling most restrictive value in value while listing alternatives in summary.", "Null is permitted only for features listed in $qualitative_features when an enacted, explicit requirement is present. Never use null to indicate that a feature was not found.", - "For each numerical feature, capture the most restrictive applicable value when multiple values are provided and explain alternatives in summary.", + "For each numerical feature, capture the most restrictive applicable value when multiple values are provided and explain alternatives in summary. Restrictiveness direction: larger distance is more restrictive for setbacks; higher value is more restrictive for minimum depth; lower value is more restrictive for maximum depth.", "For any numerical feature (including setback features such as roads and non-setback features such as noise), if no explicit numeric threshold is stated, omit that feature instead of returning null, empty, or qualitative-only values.", "If no requirement is found for a feature, omit that feature from outputs.", "Never emit 'not found', 'no explicit requirement', 'none', or similar absence text in any field. Omit these features instead.", "The outputs array is a sparse long-form extraction table and does not need to contain every enumerated feature.", - "Do not infer regulatory restrictions for non-definition features from definitions alone unless the text clearly creates an enforceable rule." + "Do not infer regulatory restrictions for non-definition features from definitions alone unless the text clearly creates an enforceable rule.", + "Treat 'explicit requirement' as directly stated ordinance language (for example: shall/must/required, numeric threshold, or clear trigger condition). Do not infer enforceable limits from broad policy statements or undefined external references." ], "setbacks": [ "Setbacks should be extracted as minimum separation distances.", "Prefer numeric values with units ('feet', 'meters').", "If both general and condition-specific setbacks are provided, select the controlling value for the scenario and describe conditions in summary.", - "Do not conflate road right-of-way with general right-of-way/easement unless ordinance text makes them equivalent." + "Do not conflate road right-of-way with general right-of-way/easement unless ordinance text makes them equivalent.", + "Mapping defaults: generic 'right-of-way' with no qualifier maps to 'row'; generic 'water well(s)' with no public/private qualifier maps to 'public water'." ], "definitions": [ "Definitions are qualitative text extractions; the value field should be null with definition text placed directly in the summary.", "If a requested definition is not present, omit that feature entirely; do not emit placeholder text.", - "Preserve legal phrasing and term boundaries from ordinance language." + "Preserve legal phrasing and term boundaries from ordinance language.", + "Standalone definitions should be extracted when present, even if not followed by an enforceable rule in the same sentence." ], "operational": [ "For qualitative features: output only when an explicit enforceable requirement is present.", @@ -253,7 +256,8 @@ "prohibitions": [ "Classify prohibitions as currently effective bans/moratoria/restrictions based on the text.", "If no active prohibition is found for a prohibition feature, omit that feature from outputs instead of using placeholder values.", - "Distinguish between complete prohibition and conditional permitting. Conditional permitting is not a ban." + "Distinguish between complete prohibition and conditional permitting. Conditional permitting is not a ban.", + "If a moratorium includes an explicit end date that has passed, omit that prohibition feature." ] }, "$qualitative_features": [ From 02f01d8f32fabd74a099b10506afb0c00c53673d Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Thu, 12 Mar 2026 16:20:37 -0600 Subject: [PATCH 23/44] Updates to schema --- .../ghp/geothermal_heat_pump_schema.json5 | 92 +++++++++++++------ 1 file changed, 66 insertions(+), 26 deletions(-) diff --git a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 index 7071ac61..e7b6c68f 100644 --- a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 +++ b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 @@ -8,10 +8,17 @@ "properties": { "outputs": { "type": "array", - "description": "Sparse long-form extraction table. Include only features with an enacted, explicit requirement and emit **at most one row per feature**.", + "description": "Sparse long-form extraction table. Include only features with an enacted, explicit requirement and emit **at most one row per feature**. Never infer, imply, or guess a requirement from related context.", "items": { "type": "object", - "required": ["feature", "value", "units", "section", "summary"], + "required": [ + "feature", + "value", + "units", + "section", + "summary", + "explanation" + ], "additionalProperties": false, "properties": { "feature": { @@ -41,6 +48,7 @@ "geothermal definition", "ghp definition", "licensed driller", + "certification", "screening", "permit", "inspection", @@ -51,7 +59,7 @@ ] }, "value": { - "description": "The extracted ordinance value. For numerical setbacks/limits, use a number. For categorical outcomes, use a string. For fields that list multiple named items, use an array of strings. Use null only for features listed in $qualitative_features, and only when an enacted, explicit, enforceable ordinance requirement for that feature is present. Null must never be used to indicate absence. If a feature has no enacted, explicit requirement in the ordinance text, omit that feature from outputs.", + "description": "The extracted ordinance value. For numerical setbacks/limits, use a number. For categorical outcomes, use a string. For fields that list multiple named items, use an array of strings. Use null only for qualitative features, and only when an enacted, explicit, enforceable ordinance requirement for that feature is present. Null must never be used to indicate absence. If a feature has no enacted, explicit requirement in the ordinance text, omit that feature from outputs.", "anyOf": [ {"type": "number"}, {"type": "string"}, @@ -68,8 +76,12 @@ "description": "The section title or number where the requirement appears (e.g., 'SECTION 1308 – Performance / Construction Standards'). Include labels/numbers if available. Null if no section identifier is available." }, "summary": { - "type": ["string", "null"], - "description": "A short summary with direct ordinance excerpts/quotes whenever possible. For qualitative features (definitions, permitting, screening, inspection, decommissioning, prohibitions), this is the primary output field and should contain a direct ordinance excerpt. Do not output absence placeholders (for example, 'No explicit ... found'); omit the feature instead when no requirement is present." + "type": "string", + "description": "A short summary with direct ordinance excerpts/quotes whenever possible. For qualitative features (definitions, permitting, screening, inspection, decommissioning, prohibitions), this is the primary output field and should contain a direct ordinance excerpt. For numeric features, summary must support the same requirement used to extract value and units. Must be a non-null, non-empty string. Do not output absence placeholders (for example, 'No explicit ... found'); omit the feature instead when no requirement is present." + }, + "explanation": { + "type": "string", + "description": "Brief rationale explaining why this row matches the selected feature under this schema. Reference the specific evidence in summary and how it supports the extracted value and units (or, for qualitative features, the inclusion criteria) while avoiding excluded cases. Must be a non-null, non-empty string and must not use absence placeholders." } } } @@ -95,7 +107,7 @@ "description": "Minimum required separation from building or structure foundations." }, "wastewater": { - "description": "Minimum required separation from onsite wastewater systems, septic tanks, leach fields, cesspools, or related sanitary wastewater infrastructure. Do not treat stormwater-only facilities as wastewater unless ordinance text explicitly does so." + "description": "Minimum required separation from **any** wastewater-related infrastructure, including: (a) traditional onsite systems such as septic tanks, aerobic/holding tanks, leach fields, subsurface sewage disposal systems, elevated sand mounds, sewage seepage pits, and cesspools; and (b) land-application wastewater such as spray irrigation sites, sewage sludge disposal sites, and septage disposal sites. All such setbacks belong to this single 'wastewater' feature — consolidate every wastewater-related clause into one row with the most restrictive (largest) value and list all variants in summary. Do not treat stormwater-only facilities as wastewater unless ordinance text explicitly does so." }, "water line": { "description": "Minimum required separation from water service lines and related service piping." @@ -110,7 +122,7 @@ "description": "Minimum required separation from public road rights-of-way. IGNORE: Do not respond based on setbacks from other kinds of right-of-way such as utility easements, etc." }, "row": { - "description": "Minimum required separation from any right-of-way or utility/drainage/access easements not already captured under road right-of-way. IGNORE: Do not respond based on setbacks from roads or driveways." + "description": "Minimum required separation from any right-of-way or utility/drainage/access easements **not already captured under road right-of-way**. Non-negotiable: emit 'row' only when an explicit numeric separation distance is stated for the same ROW/easement requirement, with value as a number and units as a non-null distance unit. If text is qualitative only (for example, 'shall not encroach' or 'must remain outside easement') with no numeric threshold, omit this feature entirely. IGNORE: Do not respond based on setbacks from roads or driveways." }, "above ground fuel": { "description": "Minimum required separation from above-ground fuel tanks or storage areas. IGNORE: Do not respond based on setbacks from **underground** fuel tanks or storage areas." @@ -136,7 +148,7 @@ "description": "Non-setback numerical restriction features. Only extract if numerical values are explicitly given in the text.", "properties": { "noise": { - "description": "Extract maximum allowable operational noise for GHP systems only when an explicit numeric limit is stated. Keep units exactly as written in text ('dBA' only when text says 'dBA' or 'dB(A)'; keep 'dB' if unweighted). If the ordinance only references compliance with other standards or provides no numeric noise limit, omit this feature. When multiple limits are present (for example day/night or zoning classes), extract the most restrictive numeric value and list all variants in summary." + "description": "Extract maximum allowable operational noise for GHP systems only when an explicit numeric limit is stated. Keep units exactly as written in text ('dBA' only when text says 'dBA' or 'dB(A)'; keep 'dB' if unweighted). If the ordinance only references compliance with other standards or provides no numeric noise limit, omit this feature entirely - Never emit summary-only, null-valued, or blank-valued noise rows. When multiple limits are present (for example day/night or zoning classes), extract the most restrictive numeric value and list all variants in summary." }, "minimum well depth": { "description": "Extract **minimum** depth requirements for boreholes/wells, including conditional limits by geology or aquifer protection zones. Most restrictive means the highest minimum depth value. If multiple conditional minimums exist, keep one row, store the controlling highest minimum in value, and list all condition-specific alternatives in summary." @@ -147,33 +159,36 @@ } }, "definition_features": { - "description": "Definitions of certain terms, preferably as direct excerpts from ordinance definitions sections (non-numerical)", + "description": "Definitions of certain terms as direct excerpts whose primary purpose is to state term meaning. Do not treat clauses as definitions when their primary purpose is to impose standards, applicability, permitting, or compliance requirements.", "properties": { "well definition": { - "description": "Extract the ordinance definition text for 'Geothermal Well' (or equivalent term)." + "description": "Extract the ordinance definition text for 'Geothermal Well' (or equivalent term) only when the excerpt's primary purpose is to define the term's meaning." }, "geothermal definition": { - "description": "Extract the ordinance definition text for 'Geothermal'." + "description": "Extract the ordinance definition text for 'Geothermal' only when the excerpt's primary purpose is to define the term's meaning." }, "ghp definition": { - "description": "Extract the ordinance definition text for 'ground source heat pump system', 'geothermal heat pump system', or equivalent term." + "description": "Extract the ordinance definition text for 'ground source heat pump system', 'geothermal heat pump system', or equivalent term only when the excerpt's primary purpose is to define the term's meaning." } } }, "operational_features": { - "description": "Operational, licensing, permitting, inspection, and abandonment requirements. These are non-numerical restriction features that require text extraction", + "description": "Operational, licensing, permitting, inspection, and abandonment requirements. These features require text extraction only.", "properties": { "licensed driller": { - "description": "Extract requirements that drilling be performed by a licensed/certified driller, contractor, or installer. Capture credential type and material qualification details when explicitly stated." + "description": "Extract requirements that the GHP **drilling** activity specifically must be performed by a licensed well driller. The credential must attach directly to the act of drilling or boring the well or borehole. Require explicit licensing language tied to drilling (for example: 'shall be drilled by a licensed well driller', 'licensed driller is required'). Do NOT infer from setback, construction, permitting, or generic contractor language. Do NOT use this feature for installer/contractor certifications, equipment certifications, or professional credentials that apply beyond the drilling activity itself — those belong to 'certification'." + }, + "certification": { + "description": "Extract any certification, accreditation, or professional credential requirement that is **not** a drilling license captured under 'licensed driller'. This includes trade or industry certification programs for GHP installers or contractors, professional engineer or licensed design professional requirements, and equipment or system certification standards. Capture the credential type, issuing body, and qualifying conditions when explicitly stated." }, "screening": { - "description": "Extract requirements for visual or physical screening (fencing, landscaping, enclosures) of above-ground geothermal equipment." + "description": "Extract only explicit requirements for visual or physical concealment of above-ground geothermal equipment. Valid concealment mechanisms include barriers or treatments such as screening, fences, walls, landscaping, berms, opaque enclosures, parapets, louvers, or screening panels. A screening row is valid only when the ordinance excerpt itself explicitly states at least one concealment mechanism. Exclude pure siting/location/setback/front-yard/side-yard/rear-yard placement rules, visibility assumptions, or indirect inference from location constraints unless the same requirement explicitly adds a concealment mechanism." }, "permit": { "description": "Extract permit requirements that explicitly govern GHP installation, drilling, or operation (for example mechanical, geothermal well, environmental, zoning, or health approvals), including triggering conditions. Do not extract generic non-GHP permits unless the ordinance explicitly ties them to geothermal systems." }, "inspection": { - "description": "Extract required inspections (pre-drilling, during installation, final inspection, pressure/flow testing, health/environmental inspections). Put inspection type(s) in value (string or array), and place responsible authority details in summary when stated." + "description": "Extract required inspections (pre-drilling, during installation, final inspection, pressure/flow testing, health/environmental inspections). Include inspection type(s) and responsible authority details in summary when stated." }, "decommissioning": { "description": "Extract requirements for abandonment, plugging, sealing, removal, and site restoration when systems are retired, fail, or wells are abandoned, including responsible party and timeline details when explicitly stated." @@ -181,7 +196,7 @@ } }, "prohibition_features": { - "description": "Prohibitions, bans, or moratoria", + "description": "Prohibitions, bans, or moratoria.", "properties": { "prohibitions cl": { "description": "Extract whether **closed-loop** geothermal systems are explicitly prohibited or under moratorium. CRITICAL: Extract only when the text states an unconditional prohibition/moratorium that applies as written (not proposed). If there are carve-outs, exceptions, or conditional permitting in any capacity, this is NOT a prohibition feature. For moratoria, include start/end timing details in summary; if the ordinance states an end date that has already passed, omit this feature." @@ -203,21 +218,24 @@ "value": 100, "units": "feet", "section": "Section 8.3 - Well Siting Standards", - "summary": "'No geothermal borehole shall be located within one hundred (100) feet of any private drinking water well.'" + "summary": "'No geothermal borehole shall be located within one hundred (100) feet of any private drinking water well.'", + "explanation": "The excerpt states an explicit numeric minimum separation from private drinking water wells, so it maps directly to 'private water' with value 100 feet." }, { "feature": "licensed driller", "value": null, "units": null, "section": "Section 6.1 - Contractor Qualifications", - "summary": "'All geothermal wells shall be drilled by a state-licensed well driller in good standing.'" + "summary": "'All geothermal wells shall be drilled by a state-licensed well driller in good standing.'", + "explanation": "The clause explicitly ties a licensing credential to the drilling activity itself, which matches 'licensed driller'." }, { "feature": "prohibitions ol", "value": null, "units": null, "section": "Section 12.4 - GEOTHERMAL ENERGY SYSTEM STANDARDS", - "summary": "'Only closed loop ground source heat pump systems utilizing heat transfer fluids as defined in this Zoning Code are permitted. Open loop ground source heat pump systems are not permitted.'" + "summary": "'Only closed loop ground source heat pump systems utilizing heat transfer fluids as defined in this Zoning Code are permitted. Open loop ground source heat pump systems are not permitted.'", + "explanation": "The text states an explicit current ban on open-loop systems, so it matches 'prohibitions ol'." } ] } @@ -226,31 +244,52 @@ "general": [ "Extract **only enacted ordinance requirements** for **geothermal heat pump / ground source heat pump systems**.", "Use direct text excerpts and quotes in summary whenever possible.", - "Each feature may appear **at most once** in outputs; do not emit multiple rows for the same feature. If multiple ordinance lines map to one feature, consolidate into one row and keep the controlling most restrictive value in value while listing alternatives in summary.", - "Null is permitted only for features listed in $qualitative_features when an enacted, explicit requirement is present. Never use null to indicate that a feature was not found.", + "For every feature, apply a strict evidence gate: only extract when ordinance text explicitly states the requirement for that same feature.", + "Never infer, assume, extrapolate, or guess requirements from context, implications, related standards, or nearby provisions.", + "Each feature may appear **at most once** in outputs; do not emit multiple rows for the same feature. If multiple ordinance lines map to one feature, build a temporary map keyed by feature, aggregate all evidence clauses under that feature key, consolidate into one row, and keep the controlling most restrictive value in value while listing alternatives in summary.", + "For any numeric feature, the summary must support the same requirement that produced value and units for that row. If both an explicit numeric threshold and related qualitative language are present, emit one consolidated row using the numeric threshold for value/units and include the qualitative language only as supplemental context in summary. Never pair a numeric value from one clause with qualitative-only language from another clause that has no numeric threshold.", + "Numeric features in this schema are all setback features (driveways, private water, public water, building foundation, wastewater, water line, sewer line, animal enclosures, roads, row, above ground fuel, below ground fuel, subsurface drains, wetlands, pools, hmat) plus noise, minimum well depth, and maximum well depth.", + "Never use null to indicate that a feature was not found.", "For each numerical feature, capture the most restrictive applicable value when multiple values are provided and explain alternatives in summary. Restrictiveness direction: larger distance is more restrictive for setbacks; higher value is more restrictive for minimum depth; lower value is more restrictive for maximum depth.", - "For any numerical feature (including setback features such as roads and non-setback features such as noise), if no explicit numeric threshold is stated, omit that feature instead of returning null, empty, or qualitative-only values.", + "For any numerical feature (including all setback features and noise, minimum well depth, maximum well depth), if no explicit numeric threshold is stated, omit that feature instead of returning null, empty, or qualitative-only values.", + "Summary is the primary data carrier for all features in this schema; every row must have a non-null, non-empty string for summary.", + "Every row must include an explanation that briefly justifies why the cited summary evidence matches the selected feature under this schema's rules.", + "Emit only positively matched features. Never emit a row to explain why a feature does not apply.", "If no requirement is found for a feature, omit that feature from outputs.", "Never emit 'not found', 'no explicit requirement', 'none', or similar absence text in any field. Omit these features instead.", "The outputs array is a sparse long-form extraction table and does not need to contain every enumerated feature.", - "Do not infer regulatory restrictions for non-definition features from definitions alone unless the text clearly creates an enforceable rule.", - "Treat 'explicit requirement' as directly stated ordinance language (for example: shall/must/required, numeric threshold, or clear trigger condition). Do not infer enforceable limits from broad policy statements or undefined external references." + "Do not infer regulatory restrictions from definitions alone unless the text clearly creates an enforceable rule.", + "If text is suggestive but not explicit for the target feature, omit the feature.", + "For 'screening', require at least one explicit concealment term in the ordinance excerpt (for example: screen, screening, fence, wall, enclosure, landscape buffer, berm, opaque). If no concealment mechanism is explicitly stated, omit 'screening'.", + "Do not treat placement, orientation, setback, or frontage restrictions as screening on their own, even if they could reduce visibility in practice.", + "Treat 'explicit requirement' as directly stated ordinance language (for example: shall/must/required, numeric threshold, or clear trigger condition). Do not infer enforceable limits from broad policy statements or undefined external references.", + "Standalone definitions should be extracted when present, even if not followed by an enforceable rule in the same sentence.", + "Mandatory final QA pass before returning outputs: (1) enforce uniqueness by feature with len(outputs) == len(unique(feature values)); if duplicates exist, merge or drop invalid rows until equality is true; (2) every row must have non-null, non-empty strings for summary and explanation; (3) explanation must explicitly tie summary evidence to the selected feature and not contradict feature inclusion/exclusion criteria; (4) for every numeric feature row, require numeric value and non-null units; (5) remove any numeric-feature row derived only from qualitative language (for example 'shall not encroach' or 'comply with standards') when no numeric threshold is quoted; (6) for qualitative features, set value and units to null; (7) if summary or explanation indicates the feature is not applicable, omit the row; (8) if a feature fails any check, omit it rather than returning a partial row." ], "setbacks": [ "Setbacks should be extracted as minimum separation distances.", "Prefer numeric values with units ('feet', 'meters').", + "Setback rows must contain numeric value and non-null units; never emit qualitative-only setback rows.", "If both general and condition-specific setbacks are provided, select the controlling value for the scenario and describe conditions in summary.", "Do not conflate road right-of-way with general right-of-way/easement unless ordinance text makes them equivalent.", "Mapping defaults: generic 'right-of-way' with no qualifier maps to 'row'; generic 'water well(s)' with no public/private qualifier maps to 'public water'." ], "definitions": [ - "Definitions are qualitative text extractions; the value field should be null with definition text placed directly in the summary.", + "Definitions are qualitative text extractions; set value and units to null and place definition text directly in summary.", "If a requested definition is not present, omit that feature entirely; do not emit placeholder text.", + "Apply a primary-purpose test for definition features: include a row only when the excerpt's main function is to state what the term means. If the excerpt's main function is to impose or qualify a requirement (for example standards, applicability, permitting, or compliance), do not classify it as a definition even if it references or renames the term.", + "When a clause both references a term label and imposes a requirement, classify it under the relevant operational/prohibition feature if applicable; do not classify it as a definition.", + "Counterexample for definition features: a sentence like 'X, referred to as Y, shall be subject to development standards' is not a definition because its primary purpose is obligation, not term meaning.", "Preserve legal phrasing and term boundaries from ordinance language.", "Standalone definitions should be extracted when present, even if not followed by an enforceable rule in the same sentence." ], "operational": [ "For qualitative features: output only when an explicit enforceable requirement is present.", + "Do not map generalized construction or design standards to operational features unless the ordinance explicitly names that operational requirement.", + "Do not classify setback, yard placement, lot location, dimensional, or zoning placement constraints as 'screening' unless ordinance text explicitly requires concealment (for example: fence, landscape buffer, enclosure, screen wall/panel).", + "If a provision combines placement and concealment, 'screening' may be extracted only from the concealment language and should quote that concealment requirement directly in summary.", + "For screening, explanation must cite explicit concealment language present in summary; explanations based on implied reduced visibility from siting/location restrictions are invalid.", + "For screening, if summary is only placement/setback/frontage language and does not include explicit concealment language, omit the screening row entirely.", "If no explicit requirement exists for one of these features, omit it from outputs instead of writing an absence statement." ], "prohibitions": [ @@ -265,6 +304,7 @@ "geothermal definition", "ghp definition", "licensed driller", + "certification", "screening", "permit", "inspection", From d6501767b388bac64717aecdb66feefeb2dd7de3 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Thu, 12 Mar 2026 16:24:22 -0600 Subject: [PATCH 24/44] Add debug statements --- compass/plugin/one_shot/components.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compass/plugin/one_shot/components.py b/compass/plugin/one_shot/components.py index 3edefaa8..4f42fedb 100644 --- a/compass/plugin/one_shot/components.py +++ b/compass/plugin/one_shot/components.py @@ -191,7 +191,7 @@ async def _check_chunk_with_prompt(self, key, text_chunk): }, usage_sub_label=LLMUsageCategory.DOCUMENT_CONTENT_VALIDATION, ) - logger.debug("LLM response: %s", content) + logger.debug("LLM response:\n%s", json.dumps(content, indent=4)) return content.get(key, False) def _store_chunk(self, parser, chunk_ind): @@ -343,6 +343,7 @@ async def parse(self, text): }, usage_sub_label=LLMUsageCategory.ORDINANCE_VALUE_EXTRACTION, ) + logger.debug("LLM response:\n%s", json.dumps(extraction, indent=4)) data = extraction["outputs"] if not data: logger.debug( From 4b223495eee2f977b416406f887e3fa4c0ac2154 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Thu, 12 Mar 2026 16:28:08 -0600 Subject: [PATCH 25/44] Update prompt --- compass/plugin/one_shot/components.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/compass/plugin/one_shot/components.py b/compass/plugin/one_shot/components.py index 4f42fedb..28fd460e 100644 --- a/compass/plugin/one_shot/components.py +++ b/compass/plugin/one_shot/components.py @@ -91,7 +91,7 @@ """ _DATA_PARSER_MAIN_PROMPT = """\ -Extract all {desc}features from the following text: +Extract all applicable {desc}features explicitly supported by following text: {text} @@ -99,7 +99,14 @@ """ _DATA_PARSER_SYSTEM_PROMPT = """\ You are a legal scholar extracting structured data from {desc}documents. \ -Follow all instructions in the schema descriptions carefully.\ +Follow all instructions in the following schema carefully: + +{schema} + +# ADDITIONAL CONTEXT # +Today's date is {todays_date}. If a moratorium or temporary restriction \ +includes an explicit end date that has already passed as of today, treat it \ +as expired and omit that prohibition feature.\ """ From 135e49fc3ca60e48b745cbfc7e115b1f9db33bd8 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Thu, 12 Mar 2026 16:28:42 -0600 Subject: [PATCH 26/44] Add logging --- compass/plugin/one_shot/components.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/compass/plugin/one_shot/components.py b/compass/plugin/one_shot/components.py index 28fd460e..0204cd30 100644 --- a/compass/plugin/one_shot/components.py +++ b/compass/plugin/one_shot/components.py @@ -1,7 +1,9 @@ """COMPASS extraction schema-based plugin component implementations""" +import json import asyncio import logging +from datetime import datetime from abc import ABC, abstractmethod import pandas as pd @@ -193,9 +195,7 @@ async def _check_chunk_with_prompt(self, key, text_chunk): "json_schema": { "name": "chunk_validation", "strict": True, - "schema": self.OUTPUT_SCHEMA, - }, - }, + content=main_prompt, usage_sub_label=LLMUsageCategory.DOCUMENT_CONTENT_VALIDATION, ) logger.debug("LLM response:\n%s", json.dumps(content, indent=4)) @@ -337,9 +337,19 @@ async def parse(self, text): else "" ) + todays_date = datetime.now().strftime("%B %d, %Y") + sys_prompt = self.SYSTEM_PROMPT.format( + desc=desc, schema=self.SCHEMA, todays_date=todays_date + ) + + main_prompt = _DATA_PARSER_MAIN_PROMPT.format(desc=desc, text=text) + logger.debug("Extracting ordinances with LLM") + logger.debug_to_file("\t- System Message:\n%s", sys_prompt) + logger.debug_to_file("\t- Main prompt:\n%s", main_prompt) + extraction = await self.call( - sys_msg=self.SYSTEM_PROMPT.format(desc=desc), - content=_DATA_PARSER_MAIN_PROMPT.format(desc=desc, text=text), + sys_msg=sys_prompt, + content=main_prompt, response_format={ "type": "json_schema", "json_schema": { From d655335e0db76cd3ddcf6bb2a8fd7e98344ee7c4 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Thu, 12 Mar 2026 16:29:03 -0600 Subject: [PATCH 27/44] More logging --- compass/plugin/one_shot/components.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/compass/plugin/one_shot/components.py b/compass/plugin/one_shot/components.py index 0204cd30..cc968e06 100644 --- a/compass/plugin/one_shot/components.py +++ b/compass/plugin/one_shot/components.py @@ -185,17 +185,25 @@ async def check_chunk(self, chunk_parser, ind): async def _check_chunk_with_prompt(self, key, text_chunk): """Call LLM on a chunk of text to check for ordinance""" + main_prompt = _TEXT_COLLECTION_MAIN_PROMPT.format( + schema=self.SCHEMA, text=text_chunk + ) + logger.debug("Checking text chunk with LLM: %s", text_chunk) + logger.debug_to_file( + "\t- System Message:\n%s", _TEXT_COLLECTION_SYSTEM_PROMPT + ) + logger.debug_to_file("\t- Main prompt:\n%s", main_prompt) content = await self.call( sys_msg=_TEXT_COLLECTION_SYSTEM_PROMPT, - content=_TEXT_COLLECTION_MAIN_PROMPT.format( - schema=self.SCHEMA, text=text_chunk - ), + content=main_prompt, response_format={ "type": "json_schema", "json_schema": { "name": "chunk_validation", "strict": True, - content=main_prompt, + "schema": self.OUTPUT_SCHEMA, + }, + }, usage_sub_label=LLMUsageCategory.DOCUMENT_CONTENT_VALIDATION, ) logger.debug("LLM response:\n%s", json.dumps(content, indent=4)) From 3f2fb7e2554bb7b295c80b01e20d49c6d644947e Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Fri, 13 Mar 2026 13:37:51 -0600 Subject: [PATCH 28/44] Update descriptions --- compass/extraction/ghp/geothermal_heat_pump_schema.json5 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 index e7b6c68f..906d4601 100644 --- a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 +++ b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 @@ -107,13 +107,13 @@ "description": "Minimum required separation from building or structure foundations." }, "wastewater": { - "description": "Minimum required separation from **any** wastewater-related infrastructure, including: (a) traditional onsite systems such as septic tanks, aerobic/holding tanks, leach fields, subsurface sewage disposal systems, elevated sand mounds, sewage seepage pits, and cesspools; and (b) land-application wastewater such as spray irrigation sites, sewage sludge disposal sites, and septage disposal sites. All such setbacks belong to this single 'wastewater' feature — consolidate every wastewater-related clause into one row with the most restrictive (largest) value and list all variants in summary. Do not treat stormwater-only facilities as wastewater unless ordinance text explicitly does so." + "description": "Minimum required separation from **any** wastewater-related infrastructure, including: (a) traditional onsite systems such as septic tanks, aerobic/holding tanks, leach fields, subsurface sewage disposal systems, elevated sand mounds, sewage seepage pits, and cesspools; and (b) land-application wastewater such as spray irrigation sites, sewage sludge disposal sites, and septage disposal sites. All such setbacks belong to this single 'wastewater' feature — consolidate every wastewater-related clause into one row with the most restrictive (largest) value and list all variants in summary. Do not treat stormwater-only facilities as wastewater unless ordinance text explicitly does so. Do not map line infrastructure (for example sanitary sewer lines or water service lines) to this feature; line infrastructure belongs under 'sewer line' or 'water line'." }, "water line": { - "description": "Minimum required separation from water service lines and related service piping." + "description": "Minimum required separation from water service lines and related service piping. Extract only when water line/service piping is explicitly named. If a single clause explicitly names both water line/service piping and sewer/sewage line wording with one shared numeric distance, emit both 'water line' and 'sewer line' rows using that same distance. Do not map sanitary/sewer/sewage lines or wastewater disposal structures to this feature." }, "sewer line": { - "description": "Minimum required separation from sanitary/storm sewer lines." + "description": "Minimum required separation from sanitary/storm sewer lines. Map explicit 'sewer line', 'sanitary sewer line', or 'sewage line' wording to this feature. If a single clause explicitly names both sewer/sewage line wording and water line/service piping with one shared numeric distance, emit both 'sewer line' and 'water line' rows using that same distance. Do not map wastewater disposal structures (for example septic tanks, cesspools, leach fields, seepage pits) to this feature; those belong to 'wastewater'." }, "animal enclosures": { "description": "Minimum required separation from animal enclosures, barns, pens, corrals, stables, or similar livestock areas explicitly named in ordinance text. Do not infer coverage for facilities not mentioned." From 4e24cb11f9466c703fde0b81c299ccecd82af912 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Fri, 13 Mar 2026 13:38:06 -0600 Subject: [PATCH 29/44] Update instructions --- compass/extraction/ghp/geothermal_heat_pump_schema.json5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 index 906d4601..0a754472 100644 --- a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 +++ b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 @@ -92,7 +92,7 @@ "description": "CRITICAL: Only extract requirements that apply to geothermal heat pump / ground source heat pump systems, including closed-loop and open-loop systems where relevant. If text uses generic terms like 'geothermal well' or 'geothermal system', treat it as GHP only when section context clearly indicates heating/cooling or heat-pump exchange wells/loops. Do NOT consider unrelated geothermal electricity generation rules unless the text explicitly governs heat pump exchange wells/loops." }, "setback_features": { - "description": "Setback features for GHP-related components. Treat each setback feature independently; do NOT cross-apply a setback unless the ordinance text **explicitly** states that it applies to multiple feature types. Mapping defaults: if text says 'right-of-way' without a qualifier, map to 'row'; if text says road/street right-of-way, map to 'roads'; if text says utility/drainage/access easement or utility right-of-way, map to 'row'. For water supplies, map generic 'water well(s)' or 'water supply well(s)' without a public/private qualifier to 'public water'; map to 'private water' only when private supply is explicit. If a single feature has multiple setback values, choose the most restrictive value, but **only** when the ordinance clearly shows that each value applies to GHP systems **for that same feature**.", + "description": "Setback features for GHP-related components. Treat each setback feature independently; do NOT cross-apply a setback unless the ordinance text **explicitly** states that it applies to multiple feature types. When a single clause explicitly lists multiple target types and one shared numeric setback (for example, 'water and sewer lines'), emit one row per explicitly listed feature using the same numeric value/units and cite the same clause in summary. Mapping defaults: if text says 'right-of-way' without a qualifier, map to 'row'; if text says road/street right-of-way, map to 'roads'; if text says utility/drainage/access easement or utility right-of-way, map to 'row'. For water supplies, map generic 'water well(s)' or 'water supply well(s)' without a public/private qualifier to 'public water'; map to 'private water' only when private supply is explicit. If a single feature has multiple setback values, choose the most restrictive value, but **only** when the ordinance clearly shows that each value applies to GHP systems **for that same feature**.", "properties": { "driveways": { "description": "Minimum required separation from driveways or drive areas. IGNORE: Do not respond based on setbacks from other kinds of right-of-way such as roads or utility easements, etc." From 71eaf7098f7f5d6fdc482ee2e1f3f876a25b099f Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Fri, 13 Mar 2026 13:38:28 -0600 Subject: [PATCH 30/44] Add clarification --- compass/extraction/ghp/geothermal_heat_pump_schema.json5 | 1 + 1 file changed, 1 insertion(+) diff --git a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 index 0a754472..c25b419a 100644 --- a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 +++ b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 @@ -248,6 +248,7 @@ "Never infer, assume, extrapolate, or guess requirements from context, implications, related standards, or nearby provisions.", "Each feature may appear **at most once** in outputs; do not emit multiple rows for the same feature. If multiple ordinance lines map to one feature, build a temporary map keyed by feature, aggregate all evidence clauses under that feature key, consolidate into one row, and keep the controlling most restrictive value in value while listing alternatives in summary.", "For any numeric feature, the summary must support the same requirement that produced value and units for that row. If both an explicit numeric threshold and related qualitative language are present, emit one consolidated row using the numeric threshold for value/units and include the qualitative language only as supplemental context in summary. Never pair a numeric value from one clause with qualitative-only language from another clause that has no numeric threshold.", + "Feature disambiguation for wastewater vs line infrastructure: sewage/wastewater disposal structures (for example septic tanks, cesspools, leach fields, seepage pits, sludge/septage sites) map only to 'wastewater'; explicit sewer or sewage line wording maps only to 'sewer line'; explicit water service line wording maps only to 'water line'. If one clause explicitly names both sewer/sewage line and water line/service piping with a shared numeric setback, emit both line features with that same value and units.", "Numeric features in this schema are all setback features (driveways, private water, public water, building foundation, wastewater, water line, sewer line, animal enclosures, roads, row, above ground fuel, below ground fuel, subsurface drains, wetlands, pools, hmat) plus noise, minimum well depth, and maximum well depth.", "Never use null to indicate that a feature was not found.", "For each numerical feature, capture the most restrictive applicable value when multiple values are provided and explain alternatives in summary. Restrictiveness direction: larger distance is more restrictive for setbacks; higher value is more restrictive for minimum depth; lower value is more restrictive for maximum depth.", From f939b81721405dee7c61d38f7a9270d4ece1220f Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Fri, 13 Mar 2026 13:57:11 -0600 Subject: [PATCH 31/44] Add info --- compass/extraction/ghp/geothermal_heat_pump_schema.json5 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 index c25b419a..fef2c7d2 100644 --- a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 +++ b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 @@ -273,7 +273,8 @@ "Setback rows must contain numeric value and non-null units; never emit qualitative-only setback rows.", "If both general and condition-specific setbacks are provided, select the controlling value for the scenario and describe conditions in summary.", "Do not conflate road right-of-way with general right-of-way/easement unless ordinance text makes them equivalent.", - "Mapping defaults: generic 'right-of-way' with no qualifier maps to 'row'; generic 'water well(s)' with no public/private qualifier maps to 'public water'." + "Mapping defaults: generic 'right-of-way' with no qualifier maps to 'row'; generic 'water well(s)' with no public/private qualifier maps to 'public water'.", + "When one setback clause explicitly names multiple target features and provides one shared numeric threshold, emit one row per explicitly named feature using the same threshold and units." ], "definitions": [ "Definitions are qualitative text extractions; set value and units to null and place definition text directly in summary.", From 8e9e1e89052a61454533f0c9134e250525acede6 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Fri, 13 Mar 2026 14:19:55 -0600 Subject: [PATCH 32/44] Add more info to logger --- compass/plugin/one_shot/components.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compass/plugin/one_shot/components.py b/compass/plugin/one_shot/components.py index cc968e06..f29b7877 100644 --- a/compass/plugin/one_shot/components.py +++ b/compass/plugin/one_shot/components.py @@ -351,7 +351,9 @@ async def parse(self, text): ) main_prompt = _DATA_PARSER_MAIN_PROMPT.format(desc=desc, text=text) - logger.debug("Extracting ordinances with LLM") + logger.debug( + "Extracting ordinances with LLM: %r", self.llm_service.model_name + ) logger.debug_to_file("\t- System Message:\n%s", sys_prompt) logger.debug_to_file("\t- Main prompt:\n%s", main_prompt) From 51284c1e1995a893f7ae96f7b4a81c3179ac2cde Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Fri, 13 Mar 2026 14:33:18 -0600 Subject: [PATCH 33/44] Add task ids --- compass/extraction/small_wind/parse.py | 6 ++++++ compass/extraction/solar/parse.py | 6 ++++++ compass/extraction/wind/parse.py | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/compass/extraction/small_wind/parse.py b/compass/extraction/small_wind/parse.py index 5b9c9019..417fd81b 100644 --- a/compass/extraction/small_wind/parse.py +++ b/compass/extraction/small_wind/parse.py @@ -253,6 +253,9 @@ class StructuredSmallWindOrdinanceParser(StructuredSmallWindParser): OUT_LABEL = "ordinance_values" """Identifier for structured ordinance data output by this class""" + TASK_ID = LLMUsageCategory.ORDINANCE_VALUE_EXTRACTION + """Identifier for this parser's specific LLM task category""" + async def parse(self, text): """Parse text and extract structure ordinance data @@ -569,6 +572,9 @@ class StructuredSmallWindPermittedUseDistrictsParser( OUT_LABEL = "permitted_district_values" """Identifier for structured ordinance data output by this class""" + TASK_ID = LLMUsageCategory.PERMITTED_USE_VALUE_EXTRACTION + """Identifier for this parser's specific LLM task category""" + _SMALL_WES_CLARIFICATION = ( "Small wind energy systems (AWES) may also be referred to as " "non-commercial wind energy systems, on-site wind energy systems, " diff --git a/compass/extraction/solar/parse.py b/compass/extraction/solar/parse.py index 290aebc1..ac1cbd58 100644 --- a/compass/extraction/solar/parse.py +++ b/compass/extraction/solar/parse.py @@ -200,6 +200,9 @@ class StructuredSolarOrdinanceParser(StructuredSolarParser): OUT_LABEL = "ordinance_values" """Identifier for structured ordinance data output by this class""" + TASK_ID = LLMUsageCategory.ORDINANCE_VALUE_EXTRACTION + """Identifier for this parser's specific LLM task category""" + async def parse(self, text): """Parse text and extract structure ordinance data @@ -505,6 +508,9 @@ class StructuredSolarPermittedUseDistrictsParser(StructuredSolarParser): OUT_LABEL = "permitted_district_values" """Identifier for structured ordinance data output by this class""" + TASK_ID = LLMUsageCategory.PERMITTED_USE_VALUE_EXTRACTION + """Identifier for this parser's specific LLM task category""" + _LARGE_SEF_CLARIFICATION = ( "Large solar energy systems (SES) may also be referred to as solar " "panels, solar energy conversion systems (SECS), solar energy " diff --git a/compass/extraction/wind/parse.py b/compass/extraction/wind/parse.py index bb54b11c..05b9a924 100644 --- a/compass/extraction/wind/parse.py +++ b/compass/extraction/wind/parse.py @@ -190,6 +190,9 @@ class StructuredWindOrdinanceParser(StructuredWindParser): OUT_LABEL = "ordinance_values" """Identifier for structured ordinance data output by this class""" + TASK_ID = LLMUsageCategory.ORDINANCE_VALUE_EXTRACTION + """Identifier for this parser's specific LLM task category""" + async def parse(self, text): """Parse text and extract structure ordinance data @@ -508,6 +511,9 @@ class StructuredWindPermittedUseDistrictsParser(StructuredWindParser): OUT_LABEL = "permitted_district_values" """Identifier for structured ordinance data output by this class""" + TASK_ID = LLMUsageCategory.PERMITTED_USE_VALUE_EXTRACTION + """Identifier for this parser's specific LLM task category""" + _LARGE_WES_CLARIFICATION = ( "Large wind energy systems (WES) may also be referred to as wind " "turbines, wind energy conversion systems (WECS), wind energy " From b18d8055a6780b11ad505c79070328ee00de5ffb Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Fri, 13 Mar 2026 14:38:36 -0600 Subject: [PATCH 34/44] Trimmed --- .../ghp/geothermal_heat_pump_schema.json5 | 73 +++++++++++-------- 1 file changed, 43 insertions(+), 30 deletions(-) diff --git a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 index fef2c7d2..40826b96 100644 --- a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 +++ b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 @@ -87,12 +87,26 @@ } } }, - "$definitions": { + "$core_principles": { "scope_context": { - "description": "CRITICAL: Only extract requirements that apply to geothermal heat pump / ground source heat pump systems, including closed-loop and open-loop systems where relevant. If text uses generic terms like 'geothermal well' or 'geothermal system', treat it as GHP only when section context clearly indicates heating/cooling or heat-pump exchange wells/loops. Do NOT consider unrelated geothermal electricity generation rules unless the text explicitly governs heat pump exchange wells/loops." + "description": "Only extract requirements that apply to geothermal heat pump / ground source heat pump systems, including closed-loop and open-loop systems where relevant. If text uses generic terms like 'geothermal well' or 'geothermal system', treat it as GHP only when section context clearly indicates heating/cooling or heat-pump exchange wells/loops. Do NOT consider unrelated geothermal electricity generation rules unless the text explicitly governs heat pump exchange wells/loops. Do not extract proposed, future, draft, or contingent requirements that are not currently effective as written." + }, + "strict_evidence_gate": { + "description": "Extract a feature only when the ordinance text explicitly states a requirement, definition, or prohibition for that same feature. Never infer, assume, extrapolate, or guess from related context, implications, headings, or nearby provisions. If the ordinance points to an outside document or standard without restating the controlling requirement in the ordinance text itself, do not import missing values from that outside source." + }, + "data_omission": { + "description": "Emit only positively matched features. If a feature is not explicitly present, omit it entirely rather than returning placeholder text. For qualitative features, use value=null and units=null only when an enacted, explicit requirement or definition for that same feature is present. For numeric features, extract only when an explicit numeric threshold is stated in the ordinance text; otherwise omit the feature instead of returning null, empty, or qualitative-only values. Never emit absence placeholders such as 'not found', 'no explicit requirement', 'none', or similar text in any field." + }, + "numeric_prioritization": { + "description": "When multiple numeric values apply to the same feature, keep one row and select the controlling most restrictive value for that feature. Restrictiveness rules: setbacks -> choose the largest minimum separation distance; minimum well depth -> choose the highest minimum depth; maximum well depth -> choose the lowest maximum depth; noise -> choose the lowest allowed noise limit. Keep condition-specific alternatives in summary only when the ordinance text explicitly shows they all apply to the same feature for GHP systems." }, + "definition_v_rule_test": { + "description": "Apply a primary-purpose routing test before classifying a clause as a definition. If the excerpt's main function is to state what a term means and it does not impose an enforceable obligation, extract it as a definition feature with value=null and units=null. If the excerpt imposes standards, applicability limits, permitting conditions, performance requirements, or prohibitions, classify it under the relevant operational or prohibition feature instead, even if the clause also names or restates a term." + } + }, + "$definitions": { "setback_features": { - "description": "Setback features for GHP-related components. Treat each setback feature independently; do NOT cross-apply a setback unless the ordinance text **explicitly** states that it applies to multiple feature types. When a single clause explicitly lists multiple target types and one shared numeric setback (for example, 'water and sewer lines'), emit one row per explicitly listed feature using the same numeric value/units and cite the same clause in summary. Mapping defaults: if text says 'right-of-way' without a qualifier, map to 'row'; if text says road/street right-of-way, map to 'roads'; if text says utility/drainage/access easement or utility right-of-way, map to 'row'. For water supplies, map generic 'water well(s)' or 'water supply well(s)' without a public/private qualifier to 'public water'; map to 'private water' only when private supply is explicit. If a single feature has multiple setback values, choose the most restrictive value, but **only** when the ordinance clearly shows that each value applies to GHP systems **for that same feature**.", + "description": "Setback features for GHP-related components. Treat each setback feature independently; do NOT cross-apply a setback unless the ordinance text **explicitly** states that it applies to multiple feature types. When a single clause explicitly lists multiple target types and one shared numeric setback (for example, 'water and sewer lines' or 'sewage and water line'), emit one row per explicitly listed feature using the same numeric value/units and cite the same clause in summary. Never infer a road or right-of-way setback from a property-line setback unless the ordinance text explicitly equates the property line with a road right-of-way or other right-of-way/easement boundary for that same requirement. Mapping defaults: if text says 'right-of-way' without a qualifier, map to 'row'; if text says road/street right-of-way, map to 'roads'; if text says utility/drainage/access easement or utility right-of-way, map to 'row'. For water supplies, map generic 'water well(s)' or 'water supply well(s)' without a public/private qualifier to 'public water'; map to 'private water' only when private supply is explicit. Apply the shared numeric prioritization rules in $core_principles when multiple numeric values explicitly apply to the same feature for GHP systems.", "properties": { "driveways": { "description": "Minimum required separation from driveways or drive areas. IGNORE: Do not respond based on setbacks from other kinds of right-of-way such as roads or utility easements, etc." @@ -110,19 +124,19 @@ "description": "Minimum required separation from **any** wastewater-related infrastructure, including: (a) traditional onsite systems such as septic tanks, aerobic/holding tanks, leach fields, subsurface sewage disposal systems, elevated sand mounds, sewage seepage pits, and cesspools; and (b) land-application wastewater such as spray irrigation sites, sewage sludge disposal sites, and septage disposal sites. All such setbacks belong to this single 'wastewater' feature — consolidate every wastewater-related clause into one row with the most restrictive (largest) value and list all variants in summary. Do not treat stormwater-only facilities as wastewater unless ordinance text explicitly does so. Do not map line infrastructure (for example sanitary sewer lines or water service lines) to this feature; line infrastructure belongs under 'sewer line' or 'water line'." }, "water line": { - "description": "Minimum required separation from water service lines and related service piping. Extract only when water line/service piping is explicitly named. If a single clause explicitly names both water line/service piping and sewer/sewage line wording with one shared numeric distance, emit both 'water line' and 'sewer line' rows using that same distance. Do not map sanitary/sewer/sewage lines or wastewater disposal structures to this feature." + "description": "Minimum required separation from water service lines and related service piping. Extract only when water line/service piping is explicitly named. If a single clause explicitly names both water line/service piping and sewer/sewage line wording with one shared numeric distance, emit both 'water line' and 'sewer line' rows using that same distance. Treat combined phrases such as 'water and sewer lines' or 'sewage and water line' as explicitly naming both line features when the shared noun 'line' or 'lines' applies to both utilities. Do not map sanitary/sewer/sewage lines or wastewater disposal structures to this feature." }, "sewer line": { - "description": "Minimum required separation from sanitary/storm sewer lines. Map explicit 'sewer line', 'sanitary sewer line', or 'sewage line' wording to this feature. If a single clause explicitly names both sewer/sewage line wording and water line/service piping with one shared numeric distance, emit both 'sewer line' and 'water line' rows using that same distance. Do not map wastewater disposal structures (for example septic tanks, cesspools, leach fields, seepage pits) to this feature; those belong to 'wastewater'." + "description": "Minimum required separation from sanitary/storm sewer lines. Map explicit 'sewer line', 'sanitary sewer line', or 'sewage line' wording to this feature. If a single clause explicitly names both sewer/sewage line wording and water line/service piping with one shared numeric distance, emit both 'sewer line' and 'water line' rows using that same distance. Treat combined phrases such as 'water and sewer lines' or 'sewage and water line' as explicit sewer-line evidence when the shared noun 'line' or 'lines' applies to both utilities. Do not map wastewater disposal structures (for example septic tanks, cesspools, leach fields, seepage pits) to this feature; those belong to 'wastewater'." }, "animal enclosures": { "description": "Minimum required separation from animal enclosures, barns, pens, corrals, stables, or similar livestock areas explicitly named in ordinance text. Do not infer coverage for facilities not mentioned." }, "roads": { - "description": "Minimum required separation from public road rights-of-way. IGNORE: Do not respond based on setbacks from other kinds of right-of-way such as utility easements, etc." + "description": "Minimum required separation from public road rights-of-way. Property-line setbacks do NOT count for this feature unless the ordinance text explicitly states that the property line is the road right-of-way or otherwise makes them the same boundary for that requirement. IGNORE: Do not respond based on setbacks from other kinds of right-of-way such as utility easements, etc." }, "row": { - "description": "Minimum required separation from any right-of-way or utility/drainage/access easements **not already captured under road right-of-way**. Non-negotiable: emit 'row' only when an explicit numeric separation distance is stated for the same ROW/easement requirement, with value as a number and units as a non-null distance unit. If text is qualitative only (for example, 'shall not encroach' or 'must remain outside easement') with no numeric threshold, omit this feature entirely. IGNORE: Do not respond based on setbacks from roads or driveways." + "description": "Minimum required separation from any right-of-way or utility/drainage/access easements **not already captured under road right-of-way**. Non-negotiable: emit 'row' only when an explicit numeric separation distance is stated for the same ROW/easement requirement, with value as a number and units as a non-null distance unit. Property-line setbacks do NOT count for this feature unless the ordinance text explicitly states that the property line is the relevant right-of-way or easement boundary for that same requirement. If text is qualitative only (for example, 'shall not encroach' or 'must remain outside easement') with no numeric threshold, omit this feature entirely. IGNORE: Do not respond based on setbacks from roads or driveways." }, "above ground fuel": { "description": "Minimum required separation from above-ground fuel tanks or storage areas. IGNORE: Do not respond based on setbacks from **underground** fuel tanks or storage areas." @@ -148,7 +162,7 @@ "description": "Non-setback numerical restriction features. Only extract if numerical values are explicitly given in the text.", "properties": { "noise": { - "description": "Extract maximum allowable operational noise for GHP systems only when an explicit numeric limit is stated. Keep units exactly as written in text ('dBA' only when text says 'dBA' or 'dB(A)'; keep 'dB' if unweighted). If the ordinance only references compliance with other standards or provides no numeric noise limit, omit this feature entirely - Never emit summary-only, null-valued, or blank-valued noise rows. When multiple limits are present (for example day/night or zoning classes), extract the most restrictive numeric value and list all variants in summary." + "description": "Extract maximum allowable operational noise for GHP systems only when an explicit numeric limit is stated. Keep units exactly as written in text ('dBA' only when text says 'dBA' or 'dB(A)'; keep 'dB' if unweighted). If the ordinance only references compliance with other standards or provides no numeric noise limit, omit this feature entirely. When multiple limits are present (for example day/night or zoning classes), keep the lowest allowed numeric limit and list all variants in summary only when the ordinance text explicitly shows they apply to GHP systems." }, "minimum well depth": { "description": "Extract **minimum** depth requirements for boreholes/wells, including conditional limits by geology or aquifer protection zones. Most restrictive means the highest minimum depth value. If multiple conditional minimums exist, keep one row, store the controlling highest minimum in value, and list all condition-specific alternatives in summary." @@ -159,7 +173,7 @@ } }, "definition_features": { - "description": "Definitions of certain terms as direct excerpts whose primary purpose is to state term meaning. Do not treat clauses as definitions when their primary purpose is to impose standards, applicability, permitting, or compliance requirements.", + "description": "Definitions of certain terms as direct excerpts whose primary purpose is to state term meaning. Apply the definition-vs-rule routing test in $core_principles before classifying a clause as a definition.", "properties": { "well definition": { "description": "Extract the ordinance definition text for 'Geothermal Well' (or equivalent term) only when the excerpt's primary purpose is to define the term's meaning." @@ -176,7 +190,7 @@ "description": "Operational, licensing, permitting, inspection, and abandonment requirements. These features require text extraction only.", "properties": { "licensed driller": { - "description": "Extract requirements that the GHP **drilling** activity specifically must be performed by a licensed well driller. The credential must attach directly to the act of drilling or boring the well or borehole. Require explicit licensing language tied to drilling (for example: 'shall be drilled by a licensed well driller', 'licensed driller is required'). Do NOT infer from setback, construction, permitting, or generic contractor language. Do NOT use this feature for installer/contractor certifications, equipment certifications, or professional credentials that apply beyond the drilling activity itself — those belong to 'certification'." + "description": "Extract requirements that the GHP **drilling** activity specifically must be performed by a licensed well driller. The credential must attach directly to the act of drilling or boring the well or borehole. Require explicit licensing language tied to drilling (for example: 'shall be drilled by a licensed well driller', 'licensed driller is required'). Do NOT infer this feature from setback, construction, permitting, or generic contractor language. Do NOT use this feature for installer certifications, contractor accreditations, professional engineer requirements, equipment certifications, or other credentials that apply beyond the drilling activity itself — those belong to 'certification'." }, "certification": { "description": "Extract any certification, accreditation, or professional credential requirement that is **not** a drilling license captured under 'licensed driller'. This includes trade or industry certification programs for GHP installers or contractors, professional engineer or licensed design professional requirements, and equipment or system certification standards. Capture the credential type, issuing body, and qualifying conditions when explicitly stated." @@ -242,52 +256,41 @@ ], "$instructions": { "general": [ - "Extract **only enacted ordinance requirements** for **geothermal heat pump / ground source heat pump systems**.", "Use direct text excerpts and quotes in summary whenever possible.", - "For every feature, apply a strict evidence gate: only extract when ordinance text explicitly states the requirement for that same feature.", - "Never infer, assume, extrapolate, or guess requirements from context, implications, related standards, or nearby provisions.", "Each feature may appear **at most once** in outputs; do not emit multiple rows for the same feature. If multiple ordinance lines map to one feature, build a temporary map keyed by feature, aggregate all evidence clauses under that feature key, consolidate into one row, and keep the controlling most restrictive value in value while listing alternatives in summary.", "For any numeric feature, the summary must support the same requirement that produced value and units for that row. If both an explicit numeric threshold and related qualitative language are present, emit one consolidated row using the numeric threshold for value/units and include the qualitative language only as supplemental context in summary. Never pair a numeric value from one clause with qualitative-only language from another clause that has no numeric threshold.", - "Feature disambiguation for wastewater vs line infrastructure: sewage/wastewater disposal structures (for example septic tanks, cesspools, leach fields, seepage pits, sludge/septage sites) map only to 'wastewater'; explicit sewer or sewage line wording maps only to 'sewer line'; explicit water service line wording maps only to 'water line'. If one clause explicitly names both sewer/sewage line and water line/service piping with a shared numeric setback, emit both line features with that same value and units.", + "Feature disambiguation for wastewater vs line infrastructure: sewage/wastewater disposal structures (for example septic tanks, cesspools, leach fields, seepage pits, sludge/septage sites) map only to 'wastewater'; explicit sewer or sewage line wording maps only to 'sewer line'; explicit water service line wording maps only to 'water line'. If one clause explicitly names both sewer/sewage line and water line/service piping with a shared numeric setback, emit both line features with that same value and units. Phrases such as 'water and sewer lines' or 'sewage and water line' count as explicitly naming both line features when the shared noun 'line' or 'lines' applies to both utilities.", "Numeric features in this schema are all setback features (driveways, private water, public water, building foundation, wastewater, water line, sewer line, animal enclosures, roads, row, above ground fuel, below ground fuel, subsurface drains, wetlands, pools, hmat) plus noise, minimum well depth, and maximum well depth.", - "Never use null to indicate that a feature was not found.", - "For each numerical feature, capture the most restrictive applicable value when multiple values are provided and explain alternatives in summary. Restrictiveness direction: larger distance is more restrictive for setbacks; higher value is more restrictive for minimum depth; lower value is more restrictive for maximum depth.", - "For any numerical feature (including all setback features and noise, minimum well depth, maximum well depth), if no explicit numeric threshold is stated, omit that feature instead of returning null, empty, or qualitative-only values.", "Summary is the primary data carrier for all features in this schema; every row must have a non-null, non-empty string for summary.", "Every row must include an explanation that briefly justifies why the cited summary evidence matches the selected feature under this schema's rules.", "Emit only positively matched features. Never emit a row to explain why a feature does not apply.", - "If no requirement is found for a feature, omit that feature from outputs.", - "Never emit 'not found', 'no explicit requirement', 'none', or similar absence text in any field. Omit these features instead.", "The outputs array is a sparse long-form extraction table and does not need to contain every enumerated feature.", - "Do not infer regulatory restrictions from definitions alone unless the text clearly creates an enforceable rule.", - "If text is suggestive but not explicit for the target feature, omit the feature.", - "For 'screening', require at least one explicit concealment term in the ordinance excerpt (for example: screen, screening, fence, wall, enclosure, landscape buffer, berm, opaque). If no concealment mechanism is explicitly stated, omit 'screening'.", - "Do not treat placement, orientation, setback, or frontage restrictions as screening on their own, even if they could reduce visibility in practice.", - "Treat 'explicit requirement' as directly stated ordinance language (for example: shall/must/required, numeric threshold, or clear trigger condition). Do not infer enforceable limits from broad policy statements or undefined external references.", - "Standalone definitions should be extracted when present, even if not followed by an enforceable rule in the same sentence.", - "Mandatory final QA pass before returning outputs: (1) enforce uniqueness by feature with len(outputs) == len(unique(feature values)); if duplicates exist, merge or drop invalid rows until equality is true; (2) every row must have non-null, non-empty strings for summary and explanation; (3) explanation must explicitly tie summary evidence to the selected feature and not contradict feature inclusion/exclusion criteria; (4) for every numeric feature row, require numeric value and non-null units; (5) remove any numeric-feature row derived only from qualitative language (for example 'shall not encroach' or 'comply with standards') when no numeric threshold is quoted; (6) for qualitative features, set value and units to null; (7) if summary or explanation indicates the feature is not applicable, omit the row; (8) if a feature fails any check, omit it rather than returning a partial row." + "Tables, table footnotes, and labeled graphics count as valid ordinance evidence when they state the controlling requirement; preserve the relevant table cell or footnote context in summary.", + "If ordinance text shows an amended or superseding requirement, extract the current operative requirement as written rather than a superseded historical value unless the ordinance text clearly keeps both rules active.", + "If text is suggestive but not explicit for the target feature, omit the feature." ], "setbacks": [ "Setbacks should be extracted as minimum separation distances.", "Prefer numeric values with units ('feet', 'meters').", "Setback rows must contain numeric value and non-null units; never emit qualitative-only setback rows.", - "If both general and condition-specific setbacks are provided, select the controlling value for the scenario and describe conditions in summary.", + "If both general and condition-specific setbacks are provided, select the controlling most restrictive value for the GHP scenario and describe conditions in summary.", "Do not conflate road right-of-way with general right-of-way/easement unless ordinance text makes them equivalent.", + "Do not infer road or right-of-way/easement setbacks from property-line setbacks unless the ordinance text explicitly makes the boundaries equivalent for that same requirement.", "Mapping defaults: generic 'right-of-way' with no qualifier maps to 'row'; generic 'water well(s)' with no public/private qualifier maps to 'public water'.", "When one setback clause explicitly names multiple target features and provides one shared numeric threshold, emit one row per explicitly named feature using the same threshold and units." ], "definitions": [ "Definitions are qualitative text extractions; set value and units to null and place definition text directly in summary.", "If a requested definition is not present, omit that feature entirely; do not emit placeholder text.", - "Apply a primary-purpose test for definition features: include a row only when the excerpt's main function is to state what the term means. If the excerpt's main function is to impose or qualify a requirement (for example standards, applicability, permitting, or compliance), do not classify it as a definition even if it references or renames the term.", + "Apply the definition-vs-rule routing test in $core_principles before classifying a row as a definition feature.", "When a clause both references a term label and imposes a requirement, classify it under the relevant operational/prohibition feature if applicable; do not classify it as a definition.", "Counterexample for definition features: a sentence like 'X, referred to as Y, shall be subject to development standards' is not a definition because its primary purpose is obligation, not term meaning.", - "Preserve legal phrasing and term boundaries from ordinance language.", - "Standalone definitions should be extracted when present, even if not followed by an enforceable rule in the same sentence." + "Preserve legal phrasing and term boundaries from ordinance language." ], "operational": [ "For qualitative features: output only when an explicit enforceable requirement is present.", "Do not map generalized construction or design standards to operational features unless the ordinance explicitly names that operational requirement.", + "For 'licensed driller', require explicit drilling-license language tied to boring or drilling the geothermal well or borehole itself; do not infer this feature from installer credentials, PE requirements, permit prerequisites, or equipment certifications.", "Do not classify setback, yard placement, lot location, dimensional, or zoning placement constraints as 'screening' unless ordinance text explicitly requires concealment (for example: fence, landscape buffer, enclosure, screen wall/panel).", "If a provision combines placement and concealment, 'screening' may be extracted only from the concealment language and should quote that concealment requirement directly in summary.", "For screening, explanation must cite explicit concealment language present in summary; explanations based on implied reduced visibility from siting/location restrictions are invalid.", @@ -301,6 +304,16 @@ "If a moratorium includes an explicit end date that has passed, omit that prohibition feature." ] }, + "$qa_checklist": [ + "Enforce uniqueness by feature with len(outputs) == len(unique(feature values)); if duplicates exist, merge or drop invalid rows until equality is true.", + "Every row must have non-null, non-empty strings for summary and explanation.", + "Explanation must explicitly tie summary evidence to the selected feature and must not contradict feature inclusion/exclusion criteria.", + "For every numeric feature row, require numeric value and non-null units.", + "Remove any numeric-feature row derived only from qualitative language (for example 'shall not encroach' or 'comply with standards') when no numeric threshold is quoted.", + "For qualitative features, set value and units to null.", + "If summary or explanation indicates the feature is not applicable, omit the row.", + "If a feature fails any check, omit it rather than returning a partial row." + ], "$qualitative_features": [ "well definition", "geothermal definition", From 5cb0c7526b45e8d80f17a10e4b4bffe550873694 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Fri, 13 Mar 2026 15:41:44 -0600 Subject: [PATCH 35/44] Update schema --- .../ghp/geothermal_heat_pump_schema.json5 | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 index 40826b96..4e90c4ee 100644 --- a/compass/extraction/ghp/geothermal_heat_pump_schema.json5 +++ b/compass/extraction/ghp/geothermal_heat_pump_schema.json5 @@ -26,6 +26,8 @@ "description": "The ordinance feature being extracted. Must be one of the enumerated feature IDs.", "enum": [ "driveways", + "property lines", + "yards", "private water", "public water", "building foundation", @@ -106,11 +108,17 @@ }, "$definitions": { "setback_features": { - "description": "Setback features for GHP-related components. Treat each setback feature independently; do NOT cross-apply a setback unless the ordinance text **explicitly** states that it applies to multiple feature types. When a single clause explicitly lists multiple target types and one shared numeric setback (for example, 'water and sewer lines' or 'sewage and water line'), emit one row per explicitly listed feature using the same numeric value/units and cite the same clause in summary. Never infer a road or right-of-way setback from a property-line setback unless the ordinance text explicitly equates the property line with a road right-of-way or other right-of-way/easement boundary for that same requirement. Mapping defaults: if text says 'right-of-way' without a qualifier, map to 'row'; if text says road/street right-of-way, map to 'roads'; if text says utility/drainage/access easement or utility right-of-way, map to 'row'. For water supplies, map generic 'water well(s)' or 'water supply well(s)' without a public/private qualifier to 'public water'; map to 'private water' only when private supply is explicit. Apply the shared numeric prioritization rules in $core_principles when multiple numeric values explicitly apply to the same feature for GHP systems.", + "description": "Setback features for GHP-related components. Treat each setback feature independently; do NOT cross-apply a setback unless the ordinance text **explicitly** states that it applies to multiple feature types. When a single clause explicitly lists multiple target types and one shared numeric setback (for example, 'water and sewer lines' or 'sewage and water line'), emit one row per explicitly listed feature using the same numeric value/units and cite the same clause in summary. Never infer a road or right-of-way setback from a property-line setback unless the ordinance text explicitly equates the property line with a road right-of-way or other right-of-way/easement boundary for that same requirement. Mapping defaults: if text says 'right-of-way' without a qualifier, map to 'row'; if text says road/street right-of-way, map to 'roads'; if text says utility/drainage/access easement or utility right-of-way, map to 'row'. For water supplies, map generic 'water well(s)' or 'water supply well(s)' without a public/private qualifier to 'public water'; map to 'private water' only when private supply is explicit. For fuel tanks, map generic unqualified 'fuel tank(s)' or 'fuel storage' to 'above ground fuel'; map to 'below ground fuel' only when underground or below-ground storage is explicit. Apply the shared numeric prioritization rules in $core_principles when multiple numeric values explicitly apply to the same feature for GHP systems.", "properties": { "driveways": { "description": "Minimum required separation from driveways or drive areas. IGNORE: Do not respond based on setbacks from other kinds of right-of-way such as roads or utility easements, etc." }, + "property lines": { + "description": "Minimum required separation from property lines, lot lines, or parcel boundaries when the ordinance text explicitly states the setback is measured from that boundary. Do not remap property-line setbacks to 'roads' or 'row' unless the ordinance text explicitly makes the same boundary a road right-of-way or other right-of-way/easement for that requirement. IGNORE: Do not respond based on setbacks from roads, general rights-of-way, easements, or front/side/rear yard boundaries unless the text explicitly states the boundary is the property line." + }, + "yards": { + "description": "Minimum required separation from explicit front yard, side yard, rear yard, or similar yard-based setback areas. Extract this feature only when the ordinance states the geothermal system must meet a yard setback or be located within/outside a named yard area. Do not remap yard setbacks to 'property lines' unless the ordinance explicitly measures the requirement from the property line itself rather than from a yard classification. IGNORE: Do not respond based on generic property-line, road, or right-of-way setbacks unless the ordinance explicitly frames the requirement as a yard setback." + }, "private water": { "description": "Minimum required separation from private water supplies, such as drinking water wells or private water supplies. IGNORE: Do not respond based on setbacks from **public** water supply wells, water lines, sewer lines, pools, wetlands, etc." }, @@ -139,10 +147,10 @@ "description": "Minimum required separation from any right-of-way or utility/drainage/access easements **not already captured under road right-of-way**. Non-negotiable: emit 'row' only when an explicit numeric separation distance is stated for the same ROW/easement requirement, with value as a number and units as a non-null distance unit. Property-line setbacks do NOT count for this feature unless the ordinance text explicitly states that the property line is the relevant right-of-way or easement boundary for that same requirement. If text is qualitative only (for example, 'shall not encroach' or 'must remain outside easement') with no numeric threshold, omit this feature entirely. IGNORE: Do not respond based on setbacks from roads or driveways." }, "above ground fuel": { - "description": "Minimum required separation from above-ground fuel tanks or storage areas. IGNORE: Do not respond based on setbacks from **underground** fuel tanks or storage areas." + "description": "Minimum required separation from above-ground fuel tanks or storage areas. Treat unqualified generic 'fuel tank(s)' or 'fuel storage' references as this feature unless the ordinance text explicitly says underground or below-ground. IGNORE: Do not respond based on setbacks from **underground** fuel tanks or storage areas." }, "below ground fuel": { - "description": "Minimum required separation from underground fuel tanks or storage areas. IGNORE: Do not respond based on setbacks from **above-ground** fuel tanks or storage areas." + "description": "Minimum required separation from underground fuel tanks or storage areas. Extract this feature only when underground or below-ground fuel storage is explicit. IGNORE: Do not respond based on generic unqualified fuel tanks or setbacks from **above-ground** fuel tanks or storage areas." }, "subsurface drains": { "description": "Minimum required separation from subsurface drains, tile drains, or underdrain systems." @@ -210,16 +218,16 @@ } }, "prohibition_features": { - "description": "Prohibitions, bans, or moratoria.", + "description": "Prohibitions, bans, or moratoria on building, installing, siting, or otherwise deploying geothermal systems or geothermal system types.", "properties": { "prohibitions cl": { - "description": "Extract whether **closed-loop** geothermal systems are explicitly prohibited or under moratorium. CRITICAL: Extract only when the text states an unconditional prohibition/moratorium that applies as written (not proposed). If there are carve-outs, exceptions, or conditional permitting in any capacity, this is NOT a prohibition feature. For moratoria, include start/end timing details in summary; if the ordinance states an end date that has already passed, omit this feature." + "description": "Extract whether **closed-loop** geothermal systems are explicitly prohibited or under moratorium for construction, installation, siting, or deployment. CRITICAL: Extract only when the text states an unconditional prohibition/moratorium that applies as written (not proposed). If there are carve-outs, exceptions, or conditional permitting in any capacity, this is NOT a prohibition feature. Do NOT use this feature for operating conditions, material restrictions, fluid restrictions, design standards, or performance limits that still allow closed-loop systems to be built or installed. For moratoria, include start/end timing details in summary; if the ordinance states an end date that has already passed, omit this feature." }, "prohibitions ol": { - "description": "Extract whether **open-loop** geothermal systems are explicitly prohibited or under moratorium. CRITICAL: Extract only when the text states an unconditional prohibition/moratorium that applies as written (not proposed). If there are carve-outs, exceptions, or conditional permitting in any capacity, this is NOT a prohibition feature. For moratoria, include start/end timing details in summary; if the ordinance states an end date that has already passed, omit this feature." + "description": "Extract whether **open-loop** geothermal systems are explicitly prohibited or under moratorium for construction, installation, siting, or deployment. CRITICAL: Extract only when the text states an unconditional prohibition/moratorium that applies as written (not proposed). If there are carve-outs, exceptions, or conditional permitting in any capacity, this is NOT a prohibition feature. Do NOT use this feature for operating conditions, discharge standards, water-quality limits, design standards, or performance limits that still allow open-loop systems to be built or installed. For moratoria, include start/end timing details in summary; if the ordinance states an end date that has already passed, omit this feature." }, "prohibitions other": { - "description": "Extract any other geothermal-related prohibitions or moratoria not captured above (for example: standing-column wells, discharge methods, antifreeze restrictions, district-specific bans)." + "description": "Extract any other geothermal-related prohibitions or moratoria on construction, installation, siting, or deployment not captured above (for example: standing-column wells, vertical borefields, district-specific bans, or explicit bans on a geothermal installation method). Do NOT extract operating conditions, allowed-material lists, fluid restrictions, discharge standards, maintenance rules, or performance requirements that regulate how an otherwise permitted system must be designed or operated. If the text allows the system type to be built subject to conditions, omit this feature." } } } @@ -260,7 +268,7 @@ "Each feature may appear **at most once** in outputs; do not emit multiple rows for the same feature. If multiple ordinance lines map to one feature, build a temporary map keyed by feature, aggregate all evidence clauses under that feature key, consolidate into one row, and keep the controlling most restrictive value in value while listing alternatives in summary.", "For any numeric feature, the summary must support the same requirement that produced value and units for that row. If both an explicit numeric threshold and related qualitative language are present, emit one consolidated row using the numeric threshold for value/units and include the qualitative language only as supplemental context in summary. Never pair a numeric value from one clause with qualitative-only language from another clause that has no numeric threshold.", "Feature disambiguation for wastewater vs line infrastructure: sewage/wastewater disposal structures (for example septic tanks, cesspools, leach fields, seepage pits, sludge/septage sites) map only to 'wastewater'; explicit sewer or sewage line wording maps only to 'sewer line'; explicit water service line wording maps only to 'water line'. If one clause explicitly names both sewer/sewage line and water line/service piping with a shared numeric setback, emit both line features with that same value and units. Phrases such as 'water and sewer lines' or 'sewage and water line' count as explicitly naming both line features when the shared noun 'line' or 'lines' applies to both utilities.", - "Numeric features in this schema are all setback features (driveways, private water, public water, building foundation, wastewater, water line, sewer line, animal enclosures, roads, row, above ground fuel, below ground fuel, subsurface drains, wetlands, pools, hmat) plus noise, minimum well depth, and maximum well depth.", + "Numeric features in this schema are all setback features (driveways, property lines, yards, private water, public water, building foundation, wastewater, water line, sewer line, animal enclosures, roads, row, above ground fuel, below ground fuel, subsurface drains, wetlands, pools, hmat) plus noise, minimum well depth, and maximum well depth.", "Summary is the primary data carrier for all features in this schema; every row must have a non-null, non-empty string for summary.", "Every row must include an explanation that briefly justifies why the cited summary evidence matches the selected feature under this schema's rules.", "Emit only positively matched features. Never emit a row to explain why a feature does not apply.", @@ -274,9 +282,12 @@ "Prefer numeric values with units ('feet', 'meters').", "Setback rows must contain numeric value and non-null units; never emit qualitative-only setback rows.", "If both general and condition-specific setbacks are provided, select the controlling most restrictive value for the GHP scenario and describe conditions in summary.", + "Treat property-line, lot-line, and parcel-boundary setbacks as 'property lines' when the ordinance measures the setback from that boundary.", + "Treat explicit front-yard, side-yard, rear-yard, and similar yard-based setbacks as 'yards'.", "Do not conflate road right-of-way with general right-of-way/easement unless ordinance text makes them equivalent.", "Do not infer road or right-of-way/easement setbacks from property-line setbacks unless the ordinance text explicitly makes the boundaries equivalent for that same requirement.", - "Mapping defaults: generic 'right-of-way' with no qualifier maps to 'row'; generic 'water well(s)' with no public/private qualifier maps to 'public water'.", + "Do not infer a yard setback from a property-line setback, or a property-line setback from a yard setback, unless the ordinance text explicitly equates them for that same requirement.", + "Mapping defaults: generic 'right-of-way' with no qualifier maps to 'row'; generic 'water well(s)' with no public/private qualifier maps to 'public water'; generic unqualified 'fuel tank(s)' or 'fuel storage' maps to 'above ground fuel'.", "When one setback clause explicitly names multiple target features and provides one shared numeric threshold, emit one row per explicitly named feature using the same threshold and units." ], "definitions": [ @@ -298,9 +309,11 @@ "If no explicit requirement exists for one of these features, omit it from outputs instead of writing an absence statement." ], "prohibitions": [ - "Classify prohibitions as currently effective bans/moratoria/restrictions based on the text.", + "Classify prohibitions as currently effective bans or moratoria on building, installing, siting, or deploying a geothermal system or geothermal system type.", "If no active prohibition is found for a prohibition feature, omit that feature from outputs instead of using placeholder values.", "Distinguish between complete prohibition and conditional permitting. Conditional permitting is not a ban.", + "Do not treat operational, design, material, fluid, discharge, maintenance, or performance restrictions as prohibitions when the ordinance still allows the system to be built or installed subject to those conditions.", + "If the text says a system or component is permitted only with specified materials, fluids, methods, or standards, classify it as a non-prohibition rule or omit it if no other feature fits; do not force it into a prohibition feature.", "If a moratorium includes an explicit end date that has passed, omit that prohibition feature." ] }, From ab4ac12f1669792040f18c6817f3611c7f32bcb6 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Fri, 13 Mar 2026 15:41:57 -0600 Subject: [PATCH 36/44] Update prompt --- compass/extraction/ghp/plugin_config.yaml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/compass/extraction/ghp/plugin_config.yaml b/compass/extraction/ghp/plugin_config.yaml index 9967d80b..fae2ac67 100644 --- a/compass/extraction/ghp/plugin_config.yaml +++ b/compass/extraction/ghp/plugin_config.yaml @@ -94,4 +94,10 @@ collection_prompts: True extraction_system_prompt: |- You are a legal scholar extracting structured data from geothermal ground source heat pump ordinances. - Follow all instructions in the schema descriptions carefully. + Be focused and literal: extract only enacted, explicit, in-scope requirements. + Be thorough and complete: review all relevant sections, including tables and + lists, so no explicitly stated feature is missed. + Before finalizing, perform a feature-coverage check against the schema enum and + ensure each explicitly supported feature is captured exactly once. + Pay extra attention to any descriptions, instructions, examples, and definitions in the schema, + and be sure to follow all schema instructions carefully. From a9e29ca719a41f29b5342a20a6572bfc40c03d52 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Fri, 13 Mar 2026 15:42:21 -0600 Subject: [PATCH 37/44] Generalize implementation of `_get_model_config` and use it --- compass/plugin/ordinance.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/compass/plugin/ordinance.py b/compass/plugin/ordinance.py index 3980e5ab..591fe54b 100644 --- a/compass/plugin/ordinance.py +++ b/compass/plugin/ordinance.py @@ -839,8 +839,9 @@ async def _try_extract_ordinances(self, doc_for_extraction, parser_class): await self._run_text_extractors(doc_for_extraction, parser_class) model_config = self._get_model_config( - primary_key=parser_class.TASK_ID, - secondary_key=LLMTasks.DATA_EXTRACTION, + parser_class.TASK_ID, + LLMTasks.ORDINANCE_VALUE_EXTRACTION, + LLMTasks.DATA_EXTRACTION, ) await self.extract_ordinances_from_text( doc_for_extraction, @@ -867,8 +868,9 @@ async def _run_text_extractors(self, doc_for_extraction, parser_class): te = te[0] model_config = self._get_model_config( - primary_key=te.TASK_ID, - secondary_key=LLMTasks.TEXT_EXTRACTION, + parser_class.TASK_ID, + LLMTasks.ORDINANCE_TEXT_EXTRACTION, + LLMTasks.TEXT_EXTRACTION, ) logger.debug( "Condensing text for extraction using %r for doc from %s", @@ -899,13 +901,12 @@ def _concat_scrape_results(self, source): return data[0] if len(data) == 1 else pd.concat(data) - def _get_model_config(self, primary_key, secondary_key): - """Get model config: primary_key -> secondary_key -> default""" - if primary_key in self.model_configs: - return self.model_configs[primary_key] - return self.model_configs.get( - secondary_key, self.model_configs[LLMTasks.DEFAULT] - ) + def _get_model_config(self, *keys): + """Get model config based on key priority""" + for key in keys: + if key in self.model_configs: + return self.model_configs[key] + return self.model_configs[LLMTasks.DEFAULT] def validate_plugin_configuration(self): """[NOT PUBLIC API] Validate plugin is properly configured""" From 2729dcdd2d60a2b7e9a8be48542775435747832d Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Fri, 13 Mar 2026 15:43:22 -0600 Subject: [PATCH 38/44] Update logging statement --- compass/plugin/one_shot/components.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compass/plugin/one_shot/components.py b/compass/plugin/one_shot/components.py index f29b7877..d0970cbe 100644 --- a/compass/plugin/one_shot/components.py +++ b/compass/plugin/one_shot/components.py @@ -254,8 +254,10 @@ async def _process(self, text_chunks): """Perform extraction processing""" logger.info( - "Extracting summary text from %d text chunks asynchronously...", + "Extracting summary text from %d text chunks asynchronously " + "using LLM: %r...", len(text_chunks), + self.llm_service.model_name, ) outer_task_name = asyncio.current_task().get_name() summaries = [ From 7f7a8eb77d5109dddbfa5bc51511e2d12d77e171 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Fri, 13 Mar 2026 15:43:41 -0600 Subject: [PATCH 39/44] Change logging level --- compass/plugin/one_shot/components.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compass/plugin/one_shot/components.py b/compass/plugin/one_shot/components.py index d0970cbe..0cf47fd2 100644 --- a/compass/plugin/one_shot/components.py +++ b/compass/plugin/one_shot/components.py @@ -372,7 +372,9 @@ async def parse(self, text): }, usage_sub_label=LLMUsageCategory.ORDINANCE_VALUE_EXTRACTION, ) - logger.debug("LLM response:\n%s", json.dumps(extraction, indent=4)) + logger.debug_to_file( + "LLM response:\n%s", json.dumps(extraction, indent=4) + ) data = extraction["outputs"] if not data: logger.debug( From 6b44d1989f1f3dee98554f4b2a939623f1a8e94b Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Fri, 13 Mar 2026 16:03:39 -0600 Subject: [PATCH 40/44] Fix import --- compass/extraction/ghp/__init__.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compass/extraction/ghp/__init__.py b/compass/extraction/ghp/__init__.py index a66f25ac..232622ea 100644 --- a/compass/extraction/ghp/__init__.py +++ b/compass/extraction/ghp/__init__.py @@ -6,8 +6,6 @@ COMPASSGeoHeatPumpExtractor = create_schema_based_one_shot_extraction_plugin( - importlib.resources.files("compass.extraction.ghp") - # / "ghp" - / "plugin_config.yaml", + importlib.resources.files("compass.extraction.ghp") / "plugin_config.yaml", tech="ghp", ) From faa0baae5f982da479f17c680478d70c713c3478 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Fri, 13 Mar 2026 16:11:21 -0600 Subject: [PATCH 41/44] Align playwright versions --- pixi.lock | 181 ++++++++++++++++++++++++++----------------------- pyproject.toml | 4 +- 2 files changed, 98 insertions(+), 87 deletions(-) diff --git a/pixi.lock b/pixi.lock index 6b38a270..2b79030f 100644 --- a/pixi.lock +++ b/pixi.lock @@ -129,7 +129,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nltk-3.9.2-pyhcf101f3_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-22.21.1-h4a9c4b4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-20.19.6-hc8774ed_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nspr-4.38-h29cc59b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nss-3.118-h445c969_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.1-py313hf6604e3_0.conda @@ -148,7 +148,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.3-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/playwright-1.51.1-hbf95b10_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/playwright-1.49.1-h92b4e83_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/poppler-24.12.0-hd7b24de_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda @@ -219,6 +219,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.12-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/yarl-1.22.0-py313h3dea7bd_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.25.0-py313h54dd161_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda - pypi: https://files.pythonhosted.org/packages/67/84/d844b79acd9fe15ded60b614b7df04a12fad854ee1fbb8415d726ab1beeb/aiobotocore-3.1.1-py3-none-any.whl @@ -478,7 +479,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.3-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pixman-0.46.4-h7ac5ae9_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/playwright-1.51.1-h0ee932a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/playwright-1.49.1-h0ee932a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/poppler-24.12.0-h549c9f3_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda @@ -771,7 +772,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.3-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/pixman-0.46.4-ha059160_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/playwright-1.51.1-h046caca_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/playwright-1.49.1-h046caca_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/poppler-24.12.0-hcc361ce_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda @@ -1039,7 +1040,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nltk-3.9.2-pyhcf101f3_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-22.21.1-hf2fe37f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-20.19.6-h509f43f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nspr-4.38-heaf21c2_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nss-3.118-h1c710a3_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.1-py313h16eae64_0.conda @@ -1058,7 +1059,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.3-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pixman-0.46.4-h81086ad_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/playwright-1.51.1-h3339cab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/playwright-1.49.1-hb67532b_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/poppler-24.12.0-ha29e788_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda @@ -1124,6 +1125,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/xorg-libxdmcp-1.1.5-hc919400_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/yaml-0.2.5-h925e9cb_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/yarl-1.22.0-py313h7d74516_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zlib-1.3.1-h8359307_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstandard-0.25.0-py313h9734d34_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-hbf9d68e_6.conda - pypi: https://files.pythonhosted.org/packages/67/84/d844b79acd9fe15ded60b614b7df04a12fad854ee1fbb8415d726ab1beeb/aiobotocore-3.1.1-py3-none-any.whl @@ -1334,7 +1336,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.3-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/pixman-0.46.4-h5112557_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/microsoft/noarch/playwright-1.51.0-py_0.conda + - conda: https://conda.anaconda.org/microsoft/win-64/playwright-1.49.1-py313_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/win-64/poppler-24.12.0-heaa0bce_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda @@ -1641,7 +1643,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nltk-3.9.2-pyhcf101f3_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-22.21.1-h4a9c4b4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-20.19.6-hc8774ed_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nspr-4.38-h29cc59b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nss-3.118-h445c969_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.1-py313hf6604e3_0.conda @@ -1661,7 +1663,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/playwright-1.51.1-hbf95b10_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/playwright-1.49.1-h92b4e83_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/poppler-24.12.0-hd7b24de_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda @@ -1748,6 +1750,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/yarl-1.22.0-py313h3dea7bd_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.25.0-py313h54dd161_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda - pypi: https://files.pythonhosted.org/packages/67/84/d844b79acd9fe15ded60b614b7df04a12fad854ee1fbb8415d726ab1beeb/aiobotocore-3.1.1-py3-none-any.whl @@ -2004,7 +2007,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pixman-0.46.4-h7ac5ae9_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/playwright-1.51.1-h0ee932a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/playwright-1.49.1-h0ee932a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/poppler-24.12.0-h549c9f3_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda @@ -2309,7 +2312,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/pixman-0.46.4-ha059160_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/playwright-1.51.1-h046caca_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/playwright-1.49.1-h046caca_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/poppler-24.12.0-hcc361ce_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda @@ -2589,7 +2592,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nltk-3.9.2-pyhcf101f3_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-22.21.1-hf2fe37f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-20.19.6-h509f43f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nspr-4.38-heaf21c2_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nss-3.118-h1c710a3_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.1-py313h16eae64_0.conda @@ -2609,7 +2612,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pixman-0.46.4-h81086ad_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/playwright-1.51.1-h3339cab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/playwright-1.49.1-hb67532b_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/poppler-24.12.0-ha29e788_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda @@ -2693,6 +2696,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/yaml-0.2.5-h925e9cb_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/yarl-1.22.0-py313h7d74516_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zlib-1.3.1-h8359307_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstandard-0.25.0-py313h9734d34_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-hbf9d68e_6.conda - pypi: https://files.pythonhosted.org/packages/67/84/d844b79acd9fe15ded60b614b7df04a12fad854ee1fbb8415d726ab1beeb/aiobotocore-3.1.1-py3-none-any.whl @@ -2898,7 +2902,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/pixman-0.46.4-h5112557_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/microsoft/noarch/playwright-1.51.0-py_0.conda + - conda: https://conda.anaconda.org/microsoft/win-64/playwright-1.49.1-py313_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/win-64/poppler-24.12.0-heaa0bce_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda @@ -3269,7 +3273,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.6.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nltk-3.9.2-pyhcf101f3_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-22.21.1-h4a9c4b4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-20.19.6-hc8774ed_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/notebook-7.5.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nspr-4.38-h29cc59b_0.conda @@ -3296,7 +3300,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/playwright-1.51.1-hbf95b10_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/playwright-1.49.1-h92b4e83_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/poppler-24.12.0-hd7b24de_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda @@ -3785,7 +3789,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pixman-0.46.4-h7ac5ae9_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/playwright-1.51.1-h0ee932a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/playwright-1.49.1-h0ee932a_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/poppler-24.12.0-h549c9f3_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda @@ -4236,7 +4240,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/pixman-0.46.4-ha059160_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/playwright-1.51.1-h046caca_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/playwright-1.49.1-h046caca_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/poppler-24.12.0-hcc361ce_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda @@ -4655,7 +4659,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.6.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nltk-3.9.2-pyhcf101f3_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-22.21.1-hf2fe37f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-20.19.6-h509f43f_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/notebook-7.5.2-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nspr-4.38-heaf21c2_0.conda @@ -4682,7 +4686,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pixman-0.46.4-h81086ad_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/playwright-1.51.1-h3339cab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/playwright-1.49.1-hb67532b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/poppler-24.12.0-ha29e788_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda @@ -5115,7 +5119,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/pixman-0.46.4-h5112557_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/microsoft/noarch/playwright-1.51.0-py_0.conda + - conda: https://conda.anaconda.org/microsoft/win-64/playwright-1.49.1-py313_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/poppler-24.12.0-heaa0bce_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda @@ -5481,7 +5485,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nltk-3.9.2-pyhcf101f3_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-22.21.1-h4a9c4b4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-20.19.6-hc8774ed_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nspr-4.38-h29cc59b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nss-3.118-h445c969_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.1-py313hf6604e3_0.conda @@ -5500,7 +5504,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.3-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/playwright-1.51.1-hbf95b10_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/playwright-1.49.1-h92b4e83_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/poppler-24.12.0-hd7b24de_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda @@ -5596,6 +5600,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/yarl-1.22.0-py313h3dea7bd_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.25.0-py313h54dd161_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda - pypi: https://files.pythonhosted.org/packages/67/84/d844b79acd9fe15ded60b614b7df04a12fad854ee1fbb8415d726ab1beeb/aiobotocore-3.1.1-py3-none-any.whl @@ -5858,7 +5863,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.3-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pixman-0.46.4-h7ac5ae9_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/playwright-1.51.1-h0ee932a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/playwright-1.49.1-h0ee932a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/poppler-24.12.0-h549c9f3_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda @@ -6179,7 +6184,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.3-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/pixman-0.46.4-ha059160_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/playwright-1.51.1-h046caca_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/playwright-1.49.1-h046caca_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/poppler-24.12.0-hcc361ce_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda @@ -6475,7 +6480,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nltk-3.9.2-pyhcf101f3_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-22.21.1-hf2fe37f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-20.19.6-h509f43f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nspr-4.38-heaf21c2_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nss-3.118-h1c710a3_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.1-py313h16eae64_0.conda @@ -6494,7 +6499,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.3-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pixman-0.46.4-h81086ad_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/playwright-1.51.1-h3339cab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/playwright-1.49.1-hb67532b_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/poppler-24.12.0-ha29e788_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda @@ -6587,6 +6592,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/yaml-0.2.5-h925e9cb_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/yarl-1.22.0-py313h7d74516_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zlib-1.3.1-h8359307_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstandard-0.25.0-py313h9734d34_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-hbf9d68e_6.conda - pypi: https://files.pythonhosted.org/packages/67/84/d844b79acd9fe15ded60b614b7df04a12fad854ee1fbb8415d726ab1beeb/aiobotocore-3.1.1-py3-none-any.whl @@ -6798,7 +6804,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.3-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/pixman-0.46.4-h5112557_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/microsoft/noarch/playwright-1.51.0-py_0.conda + - conda: https://conda.anaconda.org/microsoft/win-64/playwright-1.49.1-py313_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/win-64/poppler-24.12.0-heaa0bce_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda @@ -7110,7 +7116,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nltk-3.9.2-pyhcf101f3_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-22.21.1-h4a9c4b4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-20.19.6-hc8774ed_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nspr-4.38-h29cc59b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nss-3.118-h445c969_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.1-py313hf6604e3_0.conda @@ -7129,7 +7135,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.3-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h54a6638_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/playwright-1.51.1-hbf95b10_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/playwright-1.49.1-h92b4e83_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/poppler-24.12.0-hd7b24de_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda @@ -7226,6 +7232,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/yarl-1.22.0-py313h3dea7bd_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.25.0-py313h54dd161_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda - pypi: https://files.pythonhosted.org/packages/67/84/d844b79acd9fe15ded60b614b7df04a12fad854ee1fbb8415d726ab1beeb/aiobotocore-3.1.1-py3-none-any.whl @@ -7490,7 +7497,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.3-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pixman-0.46.4-h7ac5ae9_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/playwright-1.51.1-h0ee932a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/playwright-1.49.1-h0ee932a_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/poppler-24.12.0-h549c9f3_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda @@ -7813,7 +7820,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.3-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/pixman-0.46.4-ha059160_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/playwright-1.51.1-h046caca_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/playwright-1.49.1-h046caca_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/poppler-24.12.0-hcc361ce_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda @@ -8112,7 +8119,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nltk-3.9.2-pyhcf101f3_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-22.21.1-hf2fe37f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-20.19.6-h509f43f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nspr-4.38-heaf21c2_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nss-3.118-h1c710a3_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.1-py313h16eae64_0.conda @@ -8131,7 +8138,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.3-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pixman-0.46.4-h81086ad_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/playwright-1.51.1-h3339cab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/playwright-1.49.1-hb67532b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/poppler-24.12.0-ha29e788_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda @@ -8225,6 +8232,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/yaml-0.2.5-h925e9cb_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/yarl-1.22.0-py313h7d74516_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zlib-1.3.1-h8359307_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstandard-0.25.0-py313h9734d34_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-hbf9d68e_6.conda - pypi: https://files.pythonhosted.org/packages/67/84/d844b79acd9fe15ded60b614b7df04a12fad854ee1fbb8415d726ab1beeb/aiobotocore-3.1.1-py3-none-any.whl @@ -8438,7 +8446,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.3-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/pixman-0.46.4-h5112557_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.5.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/microsoft/noarch/playwright-1.51.0-py_0.conda + - conda: https://conda.anaconda.org/microsoft/win-64/playwright-1.49.1-py313_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/poppler-24.12.0-heaa0bce_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda @@ -16692,8 +16700,8 @@ packages: timestamp: 1736252433366 - pypi: ./ name: infra-compass - version: 0.15.1.dev4+g6fe3c864 - sha256: 8510ce98ab5a11f50a1cd3d5d5f797788a2d3005f54f27b6707b68eef772c014 + version: 0.15.3.dev43+g6b44d198.d20260313 + sha256: 28bc51640b48a1c841e9366c8c2562c159476f1e39364e28a7c5ab14d95c46fa requires_dist: - beautifulsoup4>=4.12.3,<5 - click>=8.1.7,<9 @@ -24156,22 +24164,23 @@ packages: - pkg:pypi/nltk?source=hash-mapping size: 1131839 timestamp: 1759331744254 -- conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-22.21.1-h4a9c4b4_0.conda - sha256: 7808695078b286548a56a0833bbe65f0d2a547bc134bc8a12d106b384d048e17 - md5: 3fe7cdb8ea3181917e358f31a9a0b514 +- conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-20.19.6-hc8774ed_0.conda + sha256: af0f725985bd342f06c8ed125ea6147241f0ce0f68984790509c6dcdb4f99e74 + md5: 73759c61e3ba658b26532a1628d6415e depends: + - __glibc >=2.17,<3.0.a0 + - icu >=75.1,<76.0a0 - libgcc >=14 - - __glibc >=2.28,<3.0.a0 - libstdcxx >=14 - - openssl >=3.5.4,<4.0a0 - - icu >=75.1,<76.0a0 - libuv >=1.51.0,<2.0a0 - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.4,<4.0a0 + - zlib license: MIT license_family: MIT purls: [] - size: 24194392 - timestamp: 1765444695531 + size: 17303839 + timestamp: 1765387868386 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/nodejs-22.21.1-h43d1aef_0.conda sha256: d9ba407d99dfb70cc11a4c39d2efcbbf054ffe85a13c57b4d46265b650779d8d md5: 68a6ae2c0b9d1e6bce614dac3708b374 @@ -24203,21 +24212,22 @@ packages: purls: [] size: 17689796 timestamp: 1765374535104 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-22.21.1-hf2fe37f_0.conda - sha256: 16fc66a8f7c566aa626833482bfeb20f6a1953861ba5d7e91eb4f72c600c4151 - md5: cd2e913e4e61a013e1707daf551165d3 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-20.19.6-h509f43f_0.conda + sha256: 4a025873d47a79ad2391516076031be5409c9919650c7cac46687c3c0ec2cc60 + md5: aaefcf6b93549b4ea625289fdf57e1be depends: - __osx >=11.0 - - libcxx >=19 - - openssl >=3.5.4,<4.0a0 - - libzlib >=1.3.1,<2.0a0 - icu >=75.1,<76.0a0 + - libcxx >=19 - libuv >=1.51.0,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.4,<4.0a0 + - zlib license: MIT license_family: MIT purls: [] - size: 16727525 - timestamp: 1765374502949 + size: 11286015 + timestamp: 1765397426647 - conda: https://conda.anaconda.org/conda-forge/noarch/notebook-7.5.2-pyhcf101f3_0.conda sha256: 05bda90b7a980593c5e955dec5c556ff4dabf56e6ff45a3fb6c670f5f20b11e6 md5: 47b58fa741a608dac785b71b8083bdb7 @@ -26332,57 +26342,58 @@ packages: - pyee>=12,<13 - greenlet>=3.1.1,<4.0.0 requires_python: '>=3.9' -- conda: https://conda.anaconda.org/conda-forge/linux-64/playwright-1.51.1-hbf95b10_0.conda - sha256: 640ab22e30fe3812071a74eb5e645ed65f6f1f5a8f0835359c3c97749debe5be - md5: 07e561e3f35b2792d510e56adcc4a1c3 +- conda: https://conda.anaconda.org/conda-forge/linux-64/playwright-1.49.1-h92b4e83_0.conda + sha256: 5b339443515aa86bded9ab90f2460e0b3af80cddfef2150b7a0943b497b1975e + md5: 893fa6fdf129ea348fa7615df26217d4 depends: - - nodejs >=22.13.0,<23.0a0 + - nodejs >=20.18.0,<21.0a0 license: Apache-2.0 license_family: APACHE purls: [] - size: 1906266 - timestamp: 1742276050528 -- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/playwright-1.51.1-h0ee932a_0.conda - sha256: 19433cf8ce8fe8b4a50df36169b38ebe2d884f1bbc9ffbedc458794357575f2e - md5: 1162db34235fd46585c69a6d805b0156 + size: 1995164 + timestamp: 1733850891948 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/playwright-1.49.1-h0ee932a_0.conda + sha256: 1bd8846e0c6276733bd1dd435d8576425504fb011e659a35736b4cd29003cd04 + md5: ed5667840302152ed533198dfe094e76 depends: - - nodejs >=22.13.0,<23.0a0 + - nodejs >=22.11.0,<23.0a0 license: Apache-2.0 license_family: APACHE purls: [] - size: 1906308 - timestamp: 1742276049890 -- conda: https://conda.anaconda.org/conda-forge/osx-64/playwright-1.51.1-h046caca_0.conda - sha256: 5de226d1f194084a2d8fe2b0ecb32c88d8c196b4b53123339056edaf7d3ddbbb - md5: 3bad837b7fa81d838424e0469e9ffd04 + size: 1985460 + timestamp: 1733850928890 +- conda: https://conda.anaconda.org/conda-forge/osx-64/playwright-1.49.1-h046caca_0.conda + sha256: 6eb4d99656a891ee846346a082512fac971785c607971ab41854719a0a3f33b6 + md5: 6fd1a03b174e8967cf4e89e1656ef5af depends: - - nodejs >=22.13.0,<23.0a0 + - nodejs >=22.11.0,<23.0a0 license: Apache-2.0 license_family: APACHE purls: [] - size: 1908104 - timestamp: 1742276188188 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/playwright-1.51.1-h3339cab_0.conda - sha256: 16915012ea8fbe2600efc587a09844fde03d2bbde48635416df23e4a4f1bbcbb - md5: d24799ec18f5f13e3348d9e890ce9761 + size: 1959783 + timestamp: 1733851018899 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/playwright-1.49.1-hb67532b_0.conda + sha256: a0e0c0cffd694e93214f892097f74fd5326fa0a842c61cd9360e28590898ea0b + md5: f8b7fae96302798befadf9d384ad32b6 depends: - - nodejs >=22.13.0,<23.0a0 + - nodejs >=20.18.0,<21.0a0 license: Apache-2.0 license_family: APACHE purls: [] - size: 1908772 - timestamp: 1742276155750 -- conda: https://conda.anaconda.org/microsoft/noarch/playwright-1.51.0-py_0.conda - sha256: 5208d11faba6609ad7575d64d1305c287a16f477f6879223976c7c9e13965598 - md5: ba661bebc0efa14c83c05ae1132fe111 + size: 1966211 + timestamp: 1733851060131 +- conda: https://conda.anaconda.org/microsoft/win-64/playwright-1.49.1-py313_0.tar.bz2 + sha256: 6514593b2349513ab6c5b5d3556634932abb3c1a6df952081f0d3cb39fb39ef9 + md5: bd258ec0c38ce4cd624a11943be01fbc depends: - - greenlet >=3.1.1,<4.0.0 - - pyee >=12,<13 - - python >=3.9 + - greenlet 3.1.1 + - pyee 12.0.0 + - python >=3.13,<3.14.0a0 + - python_abi 3.13.* *_cp313 license: Apache-2.0 license_family: Apache - size: 26371093 - timestamp: 1742289623780 + size: 32026235 + timestamp: 1733852567054 - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda sha256: e14aafa63efa0528ca99ba568eaf506eb55a0371d12e6250aaaa61718d2eb62e md5: d7585b6550ad04c8c5e21097ada2888e diff --git a/pyproject.toml b/pyproject.toml index deb2347a..4a6347a2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -174,7 +174,7 @@ openai = ">=1.1.0" pandas = ">=2.2.3,<3" pdf2image = ">=1.17.0,<2" pillow = ">=10.4,<11.dev0" # version range required for c4ai -playwright = ">=1.49.0,<1.52" # version range required for c4ai +playwright = ">=1.49.1,<1.50" # version range required for c4ai is >=1.49.0,<1.52, but we pin for consistency with rebrowser-playwright platformdirs = ">=4.5.1,<5" pypdf2 = ">=3.0.1,<4" pytesseract = ">=0.3.13,<0.4" @@ -213,7 +213,7 @@ crawl4ai = ">=0.6.3" ddgs = ">=9.2.3,<10" fake-useragent = ">=2.0.3,<3" google-search-results = ">=2.4.2,<3" -rebrowser-playwright = ">=1.47.0,<2" +rebrowser-playwright = ">=1.49.1,<1.50" # match playwright dep scrapling = ">=0.2.99,<0.3" tavily-python = ">=0.5.0,<0.6" tf-playwright-stealth = ">=1.2.0,<2" From dc4d87a14fcf6440ff9c4fa497b52b7f3fb7faf1 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Fri, 13 Mar 2026 17:22:59 -0600 Subject: [PATCH 42/44] Fix bug in llm config retrieval --- compass/plugin/ordinance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compass/plugin/ordinance.py b/compass/plugin/ordinance.py index 591fe54b..998bbbc7 100644 --- a/compass/plugin/ordinance.py +++ b/compass/plugin/ordinance.py @@ -868,7 +868,7 @@ async def _run_text_extractors(self, doc_for_extraction, parser_class): te = te[0] model_config = self._get_model_config( - parser_class.TASK_ID, + te.TASK_ID, LLMTasks.ORDINANCE_TEXT_EXTRACTION, LLMTasks.TEXT_EXTRACTION, ) From 84422f105008fdbb83673d4231f508baba074f5a Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Sun, 15 Mar 2026 15:15:02 -0600 Subject: [PATCH 43/44] Provide additional context even if user submits prompt --- compass/plugin/one_shot/components.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/compass/plugin/one_shot/components.py b/compass/plugin/one_shot/components.py index 0cf47fd2..1887de03 100644 --- a/compass/plugin/one_shot/components.py +++ b/compass/plugin/one_shot/components.py @@ -101,14 +101,13 @@ """ _DATA_PARSER_SYSTEM_PROMPT = """\ You are a legal scholar extracting structured data from {desc}documents. \ -Follow all instructions in the following schema carefully: - -{schema} - +Follow all instructions in the schema descriptions carefully.\ +""" +_DATA_PARSER_ADDITIONAL_CONTEXT = """\ # ADDITIONAL CONTEXT # -Today's date is {todays_date}. If a moratorium or temporary restriction \ -includes an explicit end date that has already passed as of today, treat it \ -as expired and omit that prohibition feature.\ +- Today's date is {todays_date}. If you are extracting a moratorium or \ +temporary restriction that includes an explicit end date that has already \ +passed as of today, treat it as expired and omit that prohibition feature.\ """ @@ -348,7 +347,10 @@ async def parse(self, text): ) todays_date = datetime.now().strftime("%B %d, %Y") - sys_prompt = self.SYSTEM_PROMPT.format( + sys_prompt = ( + f"{self.SYSTEM_PROMPT}\n\n{_DATA_PARSER_ADDITIONAL_CONTEXT}" + ) + sys_prompt = sys_prompt.format( desc=desc, schema=self.SCHEMA, todays_date=todays_date ) From ebff81217b16b45205cdc38f5b2bed9c03304e93 Mon Sep 17 00:00:00 2001 From: ppinchuk Date: Sun, 15 Mar 2026 15:49:18 -0600 Subject: [PATCH 44/44] Fix pandas link --- docs/source/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 9c365357..cdc8bd2e 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -64,7 +64,7 @@ "matplotlib": ("https://matplotlib.org/stable", None), "networkx": ("https://networkx.org/documentation/stable", None), "numpy": ("https://numpy.org/doc/stable/", None), - "pandas": ("https://pandas.pydata.org/pandas-docs/stable", None), + "pandas": ("https://pandas.pydata.org/docs", None), "plotly": ("https://plotly.com/python-api-reference", None), "psycopg": ("https://www.psycopg.org/psycopg3/docs", None), "python": ("https://docs.python.org/3/", None),