recce-nightly 0.59.0.20250325__tar.gz → 0.60.0.20250327__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of recce-nightly might be problematic. Click here for more details.
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/PKG-INFO +1 -1
- recce_nightly-0.60.0.20250327/recce/VERSION +1 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/adapter/base.py +1 -1
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/adapter/dbt_adapter/__init__.py +203 -135
- recce_nightly-0.60.0.20250327/recce/data/404.html +1 -0
- recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/269-9a6f1447f09759ef.js +65 -0
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/29e3cc0d-b9131230fdb267e7.js → recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/29e3cc0d-6e3b0cf904a6874d.js +1 -1
- recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/36e1c10d-800596efe83e74a6.js +1 -0
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/523b8219-cd28a6efac8e1cf1.js → recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/38610ee6-24a85e2dfb424ddb.js +1 -1
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/3998a672-18454f939c052b39.js → recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/3998a672-63fc54b2b517ee2b.js +1 -1
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/450c323b-ff537c106edf3f59.js → recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/450c323b-b36e745822edebe2.js +1 -1
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/47d8844f-cac2989cb39ba350.js → recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/47d8844f-0516cea2ef568380.js +1 -1
- recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/6dc81886-9871b611a22bd997.js +1 -0
- recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/783-784ce10322400a48.js +2 -0
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/7a8a3e83-277b00caf162a419.js → recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/7a8a3e83-dd26fafa0a7421e5.js +1 -1
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/7f27ae6c-9c6bdf82ccd2f646.js → recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/7f27ae6c-4ddea120696db611.js +1 -1
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/9746af58-344daabf5df08121.js → recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/9746af58-527fd8cbd2d17eee.js +1 -1
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/a30376cd-0e2abcaded0e4cfc.js → recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/a30376cd-1ad5a3f522da896c.js +1 -1
- recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/app/_not-found/page-76f691066176b63a.js +1 -0
- recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/app/layout-fdacc83a3bf974a3.js +1 -0
- recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/app/page-139ac00bab13bd3c.js +1 -0
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/b63b1b3f-fbe2ac2c00b4eb2f.js → recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/b63b1b3f-fe714039749c1250.js +1 -1
- recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/c132bf7d-4cb4c4a123e27340.js +1 -0
- recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/c1ceaa8b-64142a5184f1b8b2.js +1 -0
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/cd9f8d63-ba9b342f3d5e92ac.js → recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/cd9f8d63-543677b0ef49da87.js +3 -3
- recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/ce84277d-4bca7695ec1ada94.js +1 -0
- recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/e24bf851-5db5db8459b0b291.js +1 -0
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/fee69bc6-4490eb47d2aaaa72.js → recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/fee69bc6-1df8306af9d11293.js +1 -1
- recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/main-7183c49fe89a1f9b.js +1 -0
- recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/main-app-cfd795a5fe58bf37.js +1 -0
- recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/pages/_app-9f1049bbd7b90455.js +1 -0
- recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/pages/_error-71ed60313c005df1.js +1 -0
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/webpack-5ab3237140d2c0f8.js → recce_nightly-0.60.0.20250327/recce/data/_next/static/chunks/webpack-8a8709fe9d22c323.js +1 -1
- recce_nightly-0.60.0.20250327/recce/data/_next/static/toQz_Vr_ujCxxim6p2pBl/_buildManifest.js +1 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/data/index.html +2 -2
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/data/index.txt +5 -5
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/server.py +24 -2
- recce_nightly-0.60.0.20250327/recce/util/lineage.py +34 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce_nightly.egg-info/PKG-INFO +1 -1
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce_nightly.egg-info/SOURCES.txt +31 -30
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/tests/adapter/dbt_adapter/dbt_test_helper.py +3 -1
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/tests/adapter/dbt_adapter/test_dbt_cll.py +11 -9
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/tests/tasks/test_schema.py +0 -3
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/tests/test_dbt.py +1 -5
- recce_nightly-0.59.0.20250325/recce/VERSION +0 -1
- recce_nightly-0.59.0.20250325/recce/data/404.html +0 -1
- recce_nightly-0.59.0.20250325/recce/data/_next/static/H9OYwyR7yb7CjKNEdDwCX/_buildManifest.js +0 -1
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/36e1c10d-28bb82b9a3d959e7.js +0 -1
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/6dc81886-d45acadb4b6674c7.js +0 -1
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/727-81ddfe5839f762d5.js +0 -65
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/921-4158ef2dc23e4a01.js +0 -2
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/app/_not-found/page-8fb2dd95da4548ae.js +0 -1
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/app/layout-2ba8d6f3664176aa.js +0 -1
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/app/page-db98e82acba724d7.js +0 -1
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/c132bf7d-3375ff4277eceb81.js +0 -1
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/c1ceaa8b-c4f0232ef5c2c9ba.js +0 -1
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/ce84277d-3aa717f588901c96.js +0 -1
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/e24bf851-38fffe87a7b8784a.js +0 -1
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/main-535eacaa53931854.js +0 -1
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/main-app-6f45568a6a7cd7b0.js +0 -1
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/pages/_app-bbd1966052cb1e5d.js +0 -1
- recce_nightly-0.59.0.20250325/recce/data/_next/static/chunks/pages/_error-2456b9a2e0600a52.js +0 -1
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/LICENSE +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/README.md +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/__init__.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/adapter/__init__.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/adapter/dbt_adapter/dbt_version.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/adapter/sqlmesh_adapter.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/apis/__init__.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/apis/check_api.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/apis/check_func.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/apis/run_api.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/apis/run_func.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/artifact.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/cli.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/config.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/core.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/data/_next/static/chunks/framework-ded83d71b51ce901.js +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/data/_next/static/chunks/polyfills-42372ed130431b0a.js +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/data/_next/static/css/c9ecb46a4b21c126.css +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/data/_next/static/media/montserrat-cyrillic-800-normal.22628180.woff2 +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/data/_next/static/media/montserrat-cyrillic-800-normal.31d693bb.woff +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/data/_next/static/media/montserrat-cyrillic-ext-800-normal.7e2c1e62.woff +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/data/_next/static/media/montserrat-cyrillic-ext-800-normal.94a63aea.woff2 +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/data/_next/static/media/montserrat-latin-800-normal.6f8fa298.woff2 +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/data/_next/static/media/montserrat-latin-800-normal.97e20d5e.woff +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/data/_next/static/media/montserrat-latin-ext-800-normal.013b84f9.woff2 +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/data/_next/static/media/montserrat-latin-ext-800-normal.aff52ab0.woff +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/data/_next/static/media/montserrat-vietnamese-800-normal.5f21869b.woff +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/data/_next/static/media/montserrat-vietnamese-800-normal.c0035377.woff2 +0 -0
- {recce_nightly-0.59.0.20250325/recce/data/_next/static/H9OYwyR7yb7CjKNEdDwCX → recce_nightly-0.60.0.20250327/recce/data/_next/static/toQz_Vr_ujCxxim6p2pBl}/_ssgManifest.js +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/data/favicon.ico +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/data/imgs/feedback/thumbs-down.png +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/data/imgs/feedback/thumbs-up.png +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/data/logo/recce-logo-white.png +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/diff.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/event/CONFIG +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/event/SENTRY_DNS +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/event/__init__.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/event/collector.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/event/track.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/exceptions.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/git.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/github.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/models/__init__.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/models/check.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/models/run.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/models/types.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/pull_request.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/run.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/state.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/summary.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/tasks/__init__.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/tasks/core.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/tasks/dataframe.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/tasks/histogram.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/tasks/lineage.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/tasks/profile.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/tasks/query.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/tasks/rowcount.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/tasks/schema.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/tasks/top_k.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/tasks/valuediff.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/util/__init__.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/util/breaking.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/util/cache.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/util/cll.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/util/io.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/util/logger.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/util/pydantic_model.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/util/recce_cloud.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/util/singleton.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce/yaml/__init__.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce_nightly.egg-info/dependency_links.txt +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce_nightly.egg-info/entry_points.txt +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce_nightly.egg-info/requires.txt +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/recce_nightly.egg-info/top_level.txt +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/setup.cfg +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/setup.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/tests/__init__.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/tests/adapter/__init__.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/tests/adapter/dbt_adapter/__init__.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/tests/adapter/dbt_adapter/conftest.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/tests/adapter/dbt_adapter/test_dbt_adapter.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/tests/adapter/dbt_adapter/test_selector.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/tests/tasks/__init__.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/tests/tasks/conftest.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/tests/tasks/test_histogram.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/tests/tasks/test_lineage.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/tests/tasks/test_preset_checks.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/tests/tasks/test_profile.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/tests/tasks/test_query.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/tests/tasks/test_row_count.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/tests/tasks/test_top_k.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/tests/tasks/test_valuediff.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/tests/test_cli.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/tests/test_config.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/tests/test_core.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/tests/test_pull_request.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/tests/test_server.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/tests/test_state.py +0 -0
- {recce_nightly-0.59.0.20250325 → recce_nightly-0.60.0.20250327}/tests/test_summary.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.60.0.20250327
|
|
@@ -42,7 +42,7 @@ class BaseAdapter(ABC):
|
|
|
42
42
|
|
|
43
43
|
diff[key] = NodeDiff(change_status='modified', change_category='breaking')
|
|
44
44
|
elif base_node:
|
|
45
|
-
diff[key] = NodeDiff(
|
|
45
|
+
diff[key] = NodeDiff(change_status='removed')
|
|
46
46
|
elif curr_node:
|
|
47
47
|
diff[key] = NodeDiff(change_status='added')
|
|
48
48
|
return LineageDiff(
|
|
@@ -3,6 +3,7 @@ import logging
|
|
|
3
3
|
import os
|
|
4
4
|
import uuid
|
|
5
5
|
from contextlib import contextmanager
|
|
6
|
+
from copy import deepcopy
|
|
6
7
|
from dataclasses import dataclass, fields
|
|
7
8
|
from errno import ENOENT
|
|
8
9
|
from functools import lru_cache
|
|
@@ -13,6 +14,7 @@ from recce.event import log_performance
|
|
|
13
14
|
from recce.exceptions import RecceException
|
|
14
15
|
from recce.util.cll import cll, CLLPerformanceTracking
|
|
15
16
|
from ...tasks.profile import ProfileTask
|
|
17
|
+
from recce.util.lineage import find_upstream, find_downstream
|
|
16
18
|
|
|
17
19
|
try:
|
|
18
20
|
import agate
|
|
@@ -571,22 +573,12 @@ class DbtAdapter(BaseAdapter):
|
|
|
571
573
|
|
|
572
574
|
return parent_map
|
|
573
575
|
|
|
574
|
-
|
|
575
|
-
def build_table_map(self, base: Optional[bool] = False) -> Dict[str, str]:
|
|
576
|
+
def build_parent_list_per_node(self, node_id: str, base: Optional[bool] = False) -> List[str]:
|
|
576
577
|
manifest = self.curr_manifest if base is False else self.base_manifest
|
|
577
578
|
manifest_dict = manifest.to_dict()
|
|
578
579
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
resource_type = node['resource_type']
|
|
582
|
-
if resource_type not in ['model', 'seed', 'exposure', 'snapshot']:
|
|
583
|
-
continue
|
|
584
|
-
table_map[node['unique_id']] = node.get('alias')
|
|
585
|
-
|
|
586
|
-
for source in manifest_dict['sources'].values():
|
|
587
|
-
table_map[source['unique_id']] = source.get('identifier')
|
|
588
|
-
|
|
589
|
-
return table_map
|
|
580
|
+
if node_id in manifest_dict['parent_map']:
|
|
581
|
+
return manifest_dict['parent_map'][node_id]
|
|
590
582
|
|
|
591
583
|
def get_lineage(self, base: Optional[bool] = False):
|
|
592
584
|
manifest = self.curr_manifest if base is False else self.base_manifest
|
|
@@ -687,24 +679,16 @@ class DbtAdapter(BaseAdapter):
|
|
|
687
679
|
'resource_type': source['resource_type'],
|
|
688
680
|
'package_name': source['package_name'],
|
|
689
681
|
'config': source['config'],
|
|
690
|
-
'columns': {
|
|
691
|
-
col.get('name'): {
|
|
692
|
-
'name': col.get('name'),
|
|
693
|
-
'type': col.get('data_type')
|
|
694
|
-
}
|
|
695
|
-
for col in source.get('columns', {}).values()
|
|
696
|
-
}
|
|
697
682
|
}
|
|
698
683
|
|
|
699
684
|
if catalog is not None and unique_id in catalog.sources:
|
|
700
|
-
columns = {
|
|
685
|
+
nodes[unique_id]['columns'] = {
|
|
701
686
|
col_name: {
|
|
702
687
|
'name': col_name,
|
|
703
688
|
'type': col_metadata.type
|
|
704
689
|
}
|
|
705
690
|
for col_name, col_metadata in catalog.sources[unique_id].columns.items()
|
|
706
691
|
}
|
|
707
|
-
nodes[unique_id]['columns'].update(columns)
|
|
708
692
|
|
|
709
693
|
for exposure in manifest_dict['exposures'].values():
|
|
710
694
|
nodes[exposure['unique_id']] = {
|
|
@@ -735,16 +719,10 @@ class DbtAdapter(BaseAdapter):
|
|
|
735
719
|
|
|
736
720
|
parent_map = self.build_parent_map(nodes, base)
|
|
737
721
|
|
|
738
|
-
# Handle column-level lineage, only enable if env var is set to true
|
|
739
|
-
if os.getenv('RECCE_CLL_ENABLED') != 'false':
|
|
740
|
-
if base is False:
|
|
741
|
-
cll_tracker.start_column_lineage()
|
|
742
|
-
self.append_column_lineage(nodes, parent_map, base)
|
|
743
|
-
cll_tracker.end_column_lineage()
|
|
744
|
-
|
|
745
722
|
if base is False:
|
|
746
723
|
cll_tracker.end_lineage()
|
|
747
|
-
|
|
724
|
+
cll_tracker.set_total_nodes(len(nodes))
|
|
725
|
+
log_performance('model lineage', cll_tracker.to_dict())
|
|
748
726
|
cll_tracker.reset()
|
|
749
727
|
|
|
750
728
|
return dict(
|
|
@@ -754,111 +732,6 @@ class DbtAdapter(BaseAdapter):
|
|
|
754
732
|
catalog_metadata=catalog_metadata,
|
|
755
733
|
)
|
|
756
734
|
|
|
757
|
-
def append_column_lineage(self, nodes: Dict, parent_map: Dict, base: Optional[bool] = False):
|
|
758
|
-
def _apply_all_columns(node, trans_type, depends_on):
|
|
759
|
-
for col in node.get('columns', {}).values():
|
|
760
|
-
col['transformation_type'] = trans_type
|
|
761
|
-
col['depends_on'] = depends_on
|
|
762
|
-
|
|
763
|
-
def _depend_node_to_id(column_lineage, nodes):
|
|
764
|
-
for cl in column_lineage.values():
|
|
765
|
-
for depend_on in cl.depends_on:
|
|
766
|
-
if depend_on.node.startswith('__'):
|
|
767
|
-
for n in nodes.values():
|
|
768
|
-
if n.get('resource_type') != 'source':
|
|
769
|
-
continue
|
|
770
|
-
# __source__table -> source.table
|
|
771
|
-
source_table = depend_on.node.lstrip("_").replace("__", ".", 1).lower()
|
|
772
|
-
if source_table in n.get('id'):
|
|
773
|
-
depend_on.node = n.get('id')
|
|
774
|
-
break
|
|
775
|
-
else:
|
|
776
|
-
for n in nodes.values():
|
|
777
|
-
if n.get('name') == depend_on.node.lower():
|
|
778
|
-
depend_on.node = n.get('id')
|
|
779
|
-
break
|
|
780
|
-
|
|
781
|
-
cll_tracker = CLLPerformanceTracking()
|
|
782
|
-
cll_tracker.set_total_nodes(len(nodes))
|
|
783
|
-
manifest = as_manifest(self.get_manifest(base))
|
|
784
|
-
for node in nodes.values():
|
|
785
|
-
resource_type = node.get('resource_type')
|
|
786
|
-
if resource_type not in {'model', 'seed', 'source', 'snapshot'}:
|
|
787
|
-
continue
|
|
788
|
-
|
|
789
|
-
if resource_type == 'source' or resource_type == 'seed':
|
|
790
|
-
_apply_all_columns(node, 'source', [])
|
|
791
|
-
continue
|
|
792
|
-
|
|
793
|
-
if node.get('raw_code') is None or self.is_python_model(node.get('id'), base=base):
|
|
794
|
-
_apply_all_columns(node, 'unknown', [])
|
|
795
|
-
continue
|
|
796
|
-
|
|
797
|
-
# dbt <= 1.8, MetricFlow expects the time spine table to be named metricflow_time_spine
|
|
798
|
-
if node.get('name') == 'metricflow_time_spine':
|
|
799
|
-
_apply_all_columns(node, 'source', [])
|
|
800
|
-
continue
|
|
801
|
-
|
|
802
|
-
if not node.get('columns', {}):
|
|
803
|
-
# no catalog
|
|
804
|
-
continue
|
|
805
|
-
|
|
806
|
-
def ref_func(*args):
|
|
807
|
-
if len(args) == 1:
|
|
808
|
-
node = args[0]
|
|
809
|
-
elif len(args) > 1:
|
|
810
|
-
node = args[1]
|
|
811
|
-
else:
|
|
812
|
-
return None
|
|
813
|
-
return node
|
|
814
|
-
|
|
815
|
-
def source_func(source_name, table_name):
|
|
816
|
-
return f"__{source_name}__{table_name}"
|
|
817
|
-
|
|
818
|
-
raw_code = node.get('raw_code')
|
|
819
|
-
jinja_context = dict(
|
|
820
|
-
ref=ref_func,
|
|
821
|
-
source=source_func,
|
|
822
|
-
)
|
|
823
|
-
|
|
824
|
-
schema = {}
|
|
825
|
-
for parent_id in parent_map[node.get('id')]:
|
|
826
|
-
parent_node = nodes.get(parent_id)
|
|
827
|
-
if parent_node is None:
|
|
828
|
-
continue
|
|
829
|
-
columns = parent_node.get('columns') or {}
|
|
830
|
-
name = parent_node.get('name')
|
|
831
|
-
if parent_node.get('resource_type') == 'source':
|
|
832
|
-
parts = parent_id.split('.')
|
|
833
|
-
source = parts[2]
|
|
834
|
-
table = parts[3]
|
|
835
|
-
name = f"__{source}__{table}"
|
|
836
|
-
schema[name] = {
|
|
837
|
-
name: column.get('type') for name, column in columns.items()
|
|
838
|
-
}
|
|
839
|
-
|
|
840
|
-
try:
|
|
841
|
-
# provide a manifest to speedup and not pollute the manifest
|
|
842
|
-
compiled_sql = self.generate_sql(raw_code, base=base, context=jinja_context, provided_manifest=manifest)
|
|
843
|
-
dialect = self.adapter.type()
|
|
844
|
-
column_lineage = cll(compiled_sql, schema=schema, dialect=dialect)
|
|
845
|
-
except RecceException:
|
|
846
|
-
# TODO: provide parsing error message if needed
|
|
847
|
-
_apply_all_columns(node, 'unknown', [])
|
|
848
|
-
cll_tracker.increment_sqlglot_error_nodes()
|
|
849
|
-
continue
|
|
850
|
-
except Exception:
|
|
851
|
-
_apply_all_columns(node, 'unknown', [])
|
|
852
|
-
cll_tracker.increment_other_error_nodes()
|
|
853
|
-
continue
|
|
854
|
-
|
|
855
|
-
_depend_node_to_id(column_lineage, nodes)
|
|
856
|
-
|
|
857
|
-
for name, column in node.get('columns', {}).items():
|
|
858
|
-
if name in column_lineage:
|
|
859
|
-
column['depends_on'] = column_lineage[name].depends_on
|
|
860
|
-
column['transformation_type'] = column_lineage[name].type
|
|
861
|
-
|
|
862
735
|
@lru_cache(maxsize=1)
|
|
863
736
|
def _get_lineage_diff_cached(self, cache_key) -> LineageDiff:
|
|
864
737
|
base = self.get_lineage(base=True)
|
|
@@ -902,6 +775,198 @@ class DbtAdapter(BaseAdapter):
|
|
|
902
775
|
diff=diff,
|
|
903
776
|
)
|
|
904
777
|
|
|
778
|
+
def get_cll_by_node_id(self, node_id: str, base: Optional[bool] = False):
|
|
779
|
+
cll_tracker = CLLPerformanceTracking()
|
|
780
|
+
cll_tracker.start_column_lineage()
|
|
781
|
+
|
|
782
|
+
manifest = self.curr_manifest if base is False else self.base_manifest
|
|
783
|
+
manifest_dict = manifest.to_dict()
|
|
784
|
+
|
|
785
|
+
parent_ids = find_upstream(node_id, manifest_dict.get('parent_map'))
|
|
786
|
+
child_ids = find_downstream(node_id, manifest_dict.get('child_map'))
|
|
787
|
+
cll_node_ids = parent_ids.union(child_ids)
|
|
788
|
+
cll_node_ids.add(node_id)
|
|
789
|
+
|
|
790
|
+
node_manifest = self.get_lineage_nodes_metadata(base=base)
|
|
791
|
+
nodes = {}
|
|
792
|
+
for node_id in cll_node_ids:
|
|
793
|
+
if node_id not in node_manifest:
|
|
794
|
+
continue
|
|
795
|
+
nodes[node_id] = self.get_cll_cached(node_id, base=base)
|
|
796
|
+
|
|
797
|
+
cll_tracker.end_column_lineage()
|
|
798
|
+
cll_tracker.set_total_nodes(len(nodes))
|
|
799
|
+
log_performance('column level lineage', cll_tracker.to_dict())
|
|
800
|
+
cll_tracker.reset()
|
|
801
|
+
|
|
802
|
+
return dict(nodes=nodes)
|
|
803
|
+
|
|
804
|
+
@lru_cache(maxsize=128)
|
|
805
|
+
def get_cll_cached(self, node_id: str, base: Optional[bool] = False):
|
|
806
|
+
nodes = self.get_lineage_nodes_metadata(base=base)
|
|
807
|
+
|
|
808
|
+
manifest = self.curr_manifest if base is False else self.base_manifest
|
|
809
|
+
manifest_dict = manifest.to_dict()
|
|
810
|
+
parent_list = []
|
|
811
|
+
if node_id in manifest_dict['parent_map']:
|
|
812
|
+
parent_list = manifest_dict['parent_map'][node_id]
|
|
813
|
+
|
|
814
|
+
node = deepcopy(nodes[node_id])
|
|
815
|
+
self.append_column_lineage(node, parent_list, base)
|
|
816
|
+
return node
|
|
817
|
+
|
|
818
|
+
def append_column_lineage(self, node: Dict, parent_list: List, base: Optional[bool] = False):
|
|
819
|
+
def _apply_all_columns(node, trans_type, depends_on):
|
|
820
|
+
for col in node.get('columns', {}).values():
|
|
821
|
+
col['transformation_type'] = trans_type
|
|
822
|
+
col['depends_on'] = depends_on
|
|
823
|
+
|
|
824
|
+
def _depend_node_to_id(column_lineage, nodes):
|
|
825
|
+
for cl in column_lineage.values():
|
|
826
|
+
for depend_on in cl.depends_on:
|
|
827
|
+
if depend_on.node.startswith('__'):
|
|
828
|
+
for n in nodes.values():
|
|
829
|
+
if n.get('resource_type') != 'source':
|
|
830
|
+
continue
|
|
831
|
+
# __source__table -> source.table
|
|
832
|
+
source_table = depend_on.node.lstrip("_").replace("__", ".", 1).lower()
|
|
833
|
+
if source_table in n.get('id'):
|
|
834
|
+
depend_on.node = n.get('id')
|
|
835
|
+
break
|
|
836
|
+
else:
|
|
837
|
+
for n in nodes.values():
|
|
838
|
+
if n.get('name') == depend_on.node.lower():
|
|
839
|
+
depend_on.node = n.get('id')
|
|
840
|
+
break
|
|
841
|
+
|
|
842
|
+
cll_tracker = CLLPerformanceTracking()
|
|
843
|
+
nodes = self.get_lineage_nodes_metadata(base=base)
|
|
844
|
+
manifest = as_manifest(self.get_manifest(base))
|
|
845
|
+
resource_type = node.get('resource_type')
|
|
846
|
+
if resource_type not in {'model', 'seed', 'source', 'snapshot'}:
|
|
847
|
+
return
|
|
848
|
+
|
|
849
|
+
if resource_type == 'source' or resource_type == 'seed':
|
|
850
|
+
_apply_all_columns(node, 'source', [])
|
|
851
|
+
return
|
|
852
|
+
|
|
853
|
+
if node.get('raw_code') is None or self.is_python_model(node.get('id'), base=base):
|
|
854
|
+
_apply_all_columns(node, 'unknown', [])
|
|
855
|
+
return
|
|
856
|
+
|
|
857
|
+
# dbt <= 1.8, MetricFlow expects the time spine table to be named metricflow_time_spine
|
|
858
|
+
if node.get('name') == 'metricflow_time_spine':
|
|
859
|
+
_apply_all_columns(node, 'source', [])
|
|
860
|
+
return
|
|
861
|
+
|
|
862
|
+
if not node.get('columns', {}):
|
|
863
|
+
# no catalog
|
|
864
|
+
return
|
|
865
|
+
|
|
866
|
+
def ref_func(*args):
|
|
867
|
+
if len(args) == 1:
|
|
868
|
+
node = args[0]
|
|
869
|
+
elif len(args) > 1:
|
|
870
|
+
node = args[1]
|
|
871
|
+
else:
|
|
872
|
+
return None
|
|
873
|
+
return node
|
|
874
|
+
|
|
875
|
+
def source_func(source_name, table_name):
|
|
876
|
+
return f"__{source_name}__{table_name}"
|
|
877
|
+
|
|
878
|
+
raw_code = node.get('raw_code')
|
|
879
|
+
jinja_context = dict(
|
|
880
|
+
ref=ref_func,
|
|
881
|
+
source=source_func,
|
|
882
|
+
)
|
|
883
|
+
|
|
884
|
+
schema = {}
|
|
885
|
+
for parent_id in parent_list:
|
|
886
|
+
parent_node = nodes.get(parent_id)
|
|
887
|
+
if parent_node is None:
|
|
888
|
+
continue
|
|
889
|
+
columns = parent_node.get('columns') or {}
|
|
890
|
+
name = parent_node.get('name')
|
|
891
|
+
if parent_node.get('resource_type') == 'source':
|
|
892
|
+
parts = parent_id.split('.')
|
|
893
|
+
source = parts[2]
|
|
894
|
+
table = parts[3]
|
|
895
|
+
name = f"__{source}__{table}"
|
|
896
|
+
schema[name] = {
|
|
897
|
+
name: column.get('type') for name, column in columns.items()
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
try:
|
|
901
|
+
# provide a manifest to speedup and not pollute the manifest
|
|
902
|
+
compiled_sql = self.generate_sql(raw_code, base=base, context=jinja_context, provided_manifest=manifest)
|
|
903
|
+
dialect = self.adapter.type()
|
|
904
|
+
column_lineage = cll(compiled_sql, schema=schema, dialect=dialect)
|
|
905
|
+
except RecceException:
|
|
906
|
+
# TODO: provide parsing error message if needed
|
|
907
|
+
_apply_all_columns(node, 'unknown', [])
|
|
908
|
+
cll_tracker.increment_sqlglot_error_nodes()
|
|
909
|
+
return
|
|
910
|
+
except Exception:
|
|
911
|
+
_apply_all_columns(node, 'unknown', [])
|
|
912
|
+
cll_tracker.increment_other_error_nodes()
|
|
913
|
+
return
|
|
914
|
+
|
|
915
|
+
_depend_node_to_id(column_lineage, nodes)
|
|
916
|
+
|
|
917
|
+
for name, column in node.get('columns', {}).items():
|
|
918
|
+
if name in column_lineage:
|
|
919
|
+
column['depends_on'] = column_lineage[name].depends_on
|
|
920
|
+
column['transformation_type'] = column_lineage[name].type
|
|
921
|
+
|
|
922
|
+
@lru_cache(maxsize=2)
|
|
923
|
+
def get_lineage_nodes_metadata(self, base: Optional[bool] = False):
|
|
924
|
+
manifest = self.curr_manifest if base is False else self.base_manifest
|
|
925
|
+
catalog = self.curr_catalog if base is False else self.base_catalog
|
|
926
|
+
manifest_dict = manifest.to_dict()
|
|
927
|
+
|
|
928
|
+
nodes = {}
|
|
929
|
+
for node in manifest_dict['nodes'].values():
|
|
930
|
+
unique_id = node['unique_id']
|
|
931
|
+
resource_type = node['resource_type']
|
|
932
|
+
|
|
933
|
+
if resource_type not in ['model', 'seed', 'exposure', 'snapshot']:
|
|
934
|
+
continue
|
|
935
|
+
|
|
936
|
+
nodes[unique_id] = {
|
|
937
|
+
'id': node['unique_id'],
|
|
938
|
+
'name': node['name'],
|
|
939
|
+
'resource_type': node['resource_type'],
|
|
940
|
+
'raw_code': node['raw_code'],
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
if catalog is not None and unique_id in catalog.nodes:
|
|
944
|
+
columns = {}
|
|
945
|
+
for col_name, col_metadata in catalog.nodes[unique_id].columns.items():
|
|
946
|
+
col = dict(name=col_name, type=col_metadata.type)
|
|
947
|
+
columns[col_name] = col
|
|
948
|
+
nodes[unique_id]['columns'] = columns
|
|
949
|
+
|
|
950
|
+
for source in manifest_dict['sources'].values():
|
|
951
|
+
unique_id = source['unique_id']
|
|
952
|
+
|
|
953
|
+
nodes[unique_id] = {
|
|
954
|
+
'id': source['unique_id'],
|
|
955
|
+
'name': source['name'],
|
|
956
|
+
'resource_type': source['resource_type'],
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
if catalog is not None and unique_id in catalog.sources:
|
|
960
|
+
nodes[unique_id]['columns'] = {
|
|
961
|
+
col_name: {
|
|
962
|
+
'name': col_name,
|
|
963
|
+
'type': col_metadata.type
|
|
964
|
+
}
|
|
965
|
+
for col_name, col_metadata in catalog.sources[unique_id].columns.items()
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
return nodes
|
|
969
|
+
|
|
905
970
|
def get_manifests_by_id(self, unique_id: str):
|
|
906
971
|
curr_manifest = self.get_manifest(base=False)
|
|
907
972
|
base_manifest = self.get_manifest(base=True)
|
|
@@ -997,8 +1062,11 @@ class DbtAdapter(BaseAdapter):
|
|
|
997
1062
|
if refresh_file_path.endswith('manifest.json'):
|
|
998
1063
|
self.curr_manifest = load_manifest(path=refresh_file_path)
|
|
999
1064
|
self.manifest = as_manifest(self.curr_manifest)
|
|
1065
|
+
self.get_cll_cached.cache_clear()
|
|
1066
|
+
self.get_lineage_nodes_metadata.cache_clear()
|
|
1000
1067
|
elif refresh_file_path.endswith('catalog.json'):
|
|
1001
1068
|
self.curr_catalog = load_catalog(path=refresh_file_path)
|
|
1069
|
+
self.get_lineage_nodes_metadata.cache_clear()
|
|
1002
1070
|
elif self.base_path and target_type == os.path.basename(self.base_path):
|
|
1003
1071
|
if refresh_file_path.endswith('manifest.json'):
|
|
1004
1072
|
self.base_manifest = load_manifest(path=refresh_file_path)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-8a8709fe9d22c323.js"/><script src="/_next/static/chunks/38610ee6-24a85e2dfb424ddb.js" async=""></script><script src="/_next/static/chunks/783-784ce10322400a48.js" async=""></script><script src="/_next/static/chunks/main-app-cfd795a5fe58bf37.js" async=""></script><meta name="robots" content="noindex"/><title>404: This page could not be found.</title><title>recce</title><meta name="description" content="Recce: Data validation toolkit for comprehensive PR review"/><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><script src="/_next/static/chunks/webpack-8a8709fe9d22c323.js" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0]);self.__next_f.push([2,null])</script><script>self.__next_f.push([1,"1:I[83798,[],\"\"]\n3:I[26375,[],\"\"]\n4:I[22587,[],\"\"]\na:I[114,[],\"\"]\n5:{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"}\n6:{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"}\n7:{\"display\":\"inline-block\"}\n8:{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0}\nb:[]\n"])</script><script>self.__next_f.push([1,"0:[\"$\",\"$L1\",null,{\"buildId\":\"toQz_Vr_ujCxxim6p2pBl\",\"assetPrefix\":\"\",\"urlParts\":[\"\",\"_not-found\"],\"initialTree\":[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],\"initialSeedData\":[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{},[[\"$L2\",[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":\"404\"}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],null],null],null]},[null,[\"$\",\"$L3\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\",\"/_not-found\",\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L4\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"notFoundStyles\":\"$undefined\"}]],null]},[[null,[\"$\",\"html\",null,{\"lang\":\"en\",\"children\":[\"$\",\"body\",null,{\"suppressHydrationWarning\":true,\"children\":[\"$\",\"$L3\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L4\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":\"$5\",\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":\"$6\",\"children\":\"404\"}],[\"$\",\"div\",null,{\"style\":\"$7\",\"children\":[\"$\",\"h2\",null,{\"style\":\"$8\",\"children\":\"This page could not be found.\"}]}]]}]}]],\"notFoundStyles\":[]}]}]}]],null],null],\"couldBeIntercepted\":false,\"initialHead\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],\"$L9\"],\"globalErrorComponent\":\"$a\",\"missingSlots\":\"$Wb\"}]\n"])</script><script>self.__next_f.push([1,"9:[[\"$\",\"meta\",\"0\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}],[\"$\",\"meta\",\"1\",{\"charSet\":\"utf-8\"}],[\"$\",\"title\",\"2\",{\"children\":\"recce\"}],[\"$\",\"meta\",\"3\",{\"name\":\"description\",\"content\":\"Recce: Data validation toolkit for comprehensive PR review\"}]]\n2:null\n"])</script></body></html>
|