@pyric/cli 0.1.0-alpha.15 → 0.1.0-alpha.17
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.
- package/README.md +13 -9
- package/dist/assurance/.generated/conformance-verdicts.d.ts +80 -72
- package/dist/assurance/.generated/conformance-verdicts.d.ts.map +1 -1
- package/dist/assurance/.generated/conformance-verdicts.js +80 -72
- package/dist/assurance/.generated/conformance-verdicts.js.map +1 -1
- package/dist/bridge/client/dispatch.js +1 -1
- package/dist/bridge/client/dispatch.js.map +1 -1
- package/dist/cli/database-rules.d.ts.map +1 -1
- package/dist/cli/database-rules.js +6 -4
- package/dist/cli/database-rules.js.map +1 -1
- package/dist/cli/dev-runner.d.ts +9 -0
- package/dist/cli/dev-runner.d.ts.map +1 -1
- package/dist/cli/dev-runner.js +18 -0
- package/dist/cli/dev-runner.js.map +1 -1
- package/dist/cli/serve.d.ts.map +1 -1
- package/dist/cli/serve.js +61 -6
- package/dist/cli/serve.js.map +1 -1
- package/dist/cli/verify.js +2 -2
- package/dist/cli/verify.js.map +1 -1
- package/dist/conformance/.generated/can-i-use-browser.d.ts.map +1 -1
- package/dist/conformance/.generated/can-i-use-browser.js +1 -1
- package/dist/conformance/.generated/can-i-use-browser.js.map +1 -1
- package/dist/conformance/.generated/can-i-use.d.ts.map +1 -1
- package/dist/conformance/.generated/can-i-use.js +1 -1
- package/dist/conformance/.generated/can-i-use.js.map +1 -1
- package/dist/conformance/.generated/conformance-docs.d.ts.map +1 -1
- package/dist/conformance/.generated/conformance-docs.js +1 -1
- package/dist/conformance/.generated/conformance-docs.js.map +1 -1
- package/dist/next/client-aliases.d.ts +11 -0
- package/dist/next/client-aliases.d.ts.map +1 -0
- package/dist/next/client-aliases.js +38 -0
- package/dist/next/client-aliases.js.map +1 -0
- package/dist/next/dev-rewrites.d.ts +9 -0
- package/dist/next/dev-rewrites.d.ts.map +1 -0
- package/dist/next/dev-rewrites.js +53 -0
- package/dist/next/dev-rewrites.js.map +1 -0
- package/dist/next/guard.d.ts +15 -0
- package/dist/next/guard.d.ts.map +1 -0
- package/dist/next/guard.js +52 -0
- package/dist/next/guard.js.map +1 -0
- package/dist/next/index.d.ts +12 -0
- package/dist/next/index.d.ts.map +1 -0
- package/dist/next/index.js +11 -0
- package/dist/next/index.js.map +1 -0
- package/dist/next/runtime-env.d.ts +7 -0
- package/dist/next/runtime-env.d.ts.map +1 -0
- package/dist/next/runtime-env.js +13 -0
- package/dist/next/runtime-env.js.map +1 -0
- package/dist/next/server-external-packages.d.ts +10 -0
- package/dist/next/server-external-packages.d.ts.map +1 -0
- package/dist/next/server-external-packages.js +34 -0
- package/dist/next/server-external-packages.js.map +1 -0
- package/dist/next/target-url.d.ts +11 -0
- package/dist/next/target-url.d.ts.map +1 -0
- package/dist/next/target-url.js +36 -0
- package/dist/next/target-url.js.map +1 -0
- package/dist/next/turbopack-config.d.ts +9 -0
- package/dist/next/turbopack-config.d.ts.map +1 -0
- package/dist/next/turbopack-config.js +39 -0
- package/dist/next/turbopack-config.js.map +1 -0
- package/dist/next/types.d.ts +40 -0
- package/dist/next/types.d.ts.map +1 -0
- package/dist/next/types.js +5 -0
- package/dist/next/types.js.map +1 -0
- package/dist/next/webpack-config.d.ts +11 -0
- package/dist/next/webpack-config.d.ts.map +1 -0
- package/dist/next/webpack-config.js +51 -0
- package/dist/next/webpack-config.js.map +1 -0
- package/dist/next/with-pyric.d.ts +22 -0
- package/dist/next/with-pyric.d.ts.map +1 -0
- package/dist/next/with-pyric.js +49 -0
- package/dist/next/with-pyric.js.map +1 -0
- package/dist/register/app-bridge.d.ts +9 -0
- package/dist/register/app-bridge.d.ts.map +1 -0
- package/dist/register/app-bridge.js +56 -0
- package/dist/register/app-bridge.js.map +1 -0
- package/dist/register/hooks.d.ts.map +1 -1
- package/dist/register/hooks.js +6 -1
- package/dist/register/hooks.js.map +1 -1
- package/dist/register/index.js +1 -1
- package/dist/register/index.js.map +1 -1
- package/dist/register/mapping.d.ts +3 -1
- package/dist/register/mapping.d.ts.map +1 -1
- package/dist/register/mapping.js +41 -5
- package/dist/register/mapping.js.map +1 -1
- package/dist/rtdb/rules-json.d.ts +12 -0
- package/dist/rtdb/rules-json.d.ts.map +1 -1
- package/dist/rtdb/rules-json.js +98 -0
- package/dist/rtdb/rules-json.js.map +1 -1
- package/dist/serve/bundler.d.ts.map +1 -1
- package/dist/serve/bundler.js +2 -0
- package/dist/serve/bundler.js.map +1 -1
- package/dist/serve/discovery.d.ts +4 -4
- package/dist/serve/discovery.d.ts.map +1 -1
- package/dist/serve/discovery.js +59 -38
- package/dist/serve/discovery.js.map +1 -1
- package/dist/serve/entries/app-ai-passthrough.d.ts +8 -0
- package/dist/serve/entries/app-ai-passthrough.d.ts.map +1 -0
- package/dist/serve/entries/app-ai-passthrough.js +59 -0
- package/dist/serve/entries/app-ai-passthrough.js.map +1 -0
- package/dist/serve/entries/auth-helper-core.d.ts +9 -0
- package/dist/serve/entries/auth-helper-core.d.ts.map +1 -1
- package/dist/serve/entries/auth-helper-core.js +37 -8
- package/dist/serve/entries/auth-helper-core.js.map +1 -1
- package/dist/serve/entries/auth.d.ts +1 -0
- package/dist/serve/entries/auth.d.ts.map +1 -1
- package/dist/serve/entries/auth.js +7 -4
- package/dist/serve/entries/auth.js.map +1 -1
- package/dist/serve/entries/bridge-url.d.ts.map +1 -1
- package/dist/serve/entries/bridge-url.js +7 -2
- package/dist/serve/entries/bridge-url.js.map +1 -1
- package/dist/serve/entries/database.d.ts +1 -0
- package/dist/serve/entries/database.d.ts.map +1 -1
- package/dist/serve/entries/database.js +1 -0
- package/dist/serve/entries/database.js.map +1 -1
- package/dist/serve/entries/firestore.d.ts +1 -0
- package/dist/serve/entries/firestore.d.ts.map +1 -1
- package/dist/serve/entries/firestore.js +1 -0
- package/dist/serve/entries/firestore.js.map +1 -1
- package/dist/serve/entries/init.d.ts.map +1 -1
- package/dist/serve/entries/init.js +4 -2
- package/dist/serve/entries/init.js.map +1 -1
- package/dist/serve/entries/runtime.js +23 -0
- package/dist/serve/entries/runtime.js.map +1 -1
- package/dist/serve/entries/storage.d.ts +2 -0
- package/dist/serve/entries/storage.d.ts.map +1 -1
- package/dist/serve/entries/storage.js +9 -2
- package/dist/serve/entries/storage.js.map +1 -1
- package/dist/serve/html-injection.d.ts +3 -1
- package/dist/serve/html-injection.d.ts.map +1 -1
- package/dist/serve/html-injection.js +27 -1
- package/dist/serve/html-injection.js.map +1 -1
- package/dist/serve/rules.js +2 -2
- package/dist/serve/rules.js.map +1 -1
- package/dist/serve/runtime/chip-config.d.ts +1 -1
- package/dist/serve/runtime/chip-config.d.ts.map +1 -1
- package/dist/serve/runtime/chip-config.js +16 -8
- package/dist/serve/runtime/chip-config.js.map +1 -1
- package/dist/serve/sandbox-session.d.ts +1 -0
- package/dist/serve/sandbox-session.d.ts.map +1 -1
- package/dist/serve/sandbox-session.js +30 -2
- package/dist/serve/sandbox-session.js.map +1 -1
- package/dist/serve/site-ui/_astro/_studio_.B6b_G1ev.css +1 -0
- package/dist/serve/site-ui/_astro/app.bnmVTkIY.js +11 -0
- package/dist/serve/site-ui/_astro/app.t6u-adB_.js +1 -0
- package/dist/serve/site-ui/_astro/{chess-showcase.DzPO6kz0.js → chess-showcase.kC8dXLKY.js} +1 -1
- package/dist/serve/site-ui/_astro/{example-runtime.CM0H02rx.js → example-runtime.D79PnoSk.js} +1 -1
- package/dist/serve/site-ui/_astro/index.DzVde04M.js +1 -0
- package/dist/serve/site-ui/_astro/reads.BYBRLbsE.js +1 -0
- package/dist/serve/site-ui/_astro/sandbox-controls.C9Aaazt8.js +1252 -0
- package/dist/serve/site-ui/_astro/{seed.BCn5DhHS.js → seed.DANAIyRw.js} +1 -1
- package/dist/serve/site-ui/auth/index.html +2 -2
- package/dist/serve/site-ui/docs/_rhythm/index.html +1 -1
- package/dist/serve/site-ui/docs/agent/set-up-your-agent/index.html +1 -1
- package/dist/serve/site-ui/docs/agent/watch-and-review/index.html +1 -1
- package/dist/serve/site-ui/docs/agent/work-with-an-agent/index.html +1 -1
- package/dist/serve/site-ui/docs/ai-compat/index.html +85 -85
- package/dist/serve/site-ui/docs/ai-compat.md +84 -84
- package/dist/serve/site-ui/docs/api-reference/index.html +3 -1
- package/dist/serve/site-ui/docs/api-reference.md +2 -0
- package/dist/serve/site-ui/docs/app-compat/index.html +28 -28
- package/dist/serve/site-ui/docs/app-compat.md +27 -27
- package/dist/serve/site-ui/docs/auth-compat/index.html +122 -122
- package/dist/serve/site-ui/docs/auth-compat.md +121 -121
- package/dist/serve/site-ui/docs/build/ai-logic/index.html +1 -1
- package/dist/serve/site-ui/docs/build/authentication/index.html +1 -1
- package/dist/serve/site-ui/docs/build/cloud-firestore/index.html +1 -1
- package/dist/serve/site-ui/docs/build/cloud-messaging/index.html +1 -1
- package/dist/serve/site-ui/docs/build/cloud-storage/index.html +1 -1
- package/dist/serve/site-ui/docs/build/realtime-database/index.html +1 -1
- package/dist/serve/site-ui/docs/conformance-scores/index.html +4 -4
- package/dist/serve/site-ui/docs/conformance-scores.md +3 -3
- package/dist/serve/site-ui/docs/create-pyric-reference-api/index.html +6 -6
- package/dist/serve/site-ui/docs/create-pyric-reference-api.md +5 -5
- package/dist/serve/site-ui/docs/database-compat/index.html +200 -448
- package/dist/serve/site-ui/docs/database-compat.md +198 -461
- package/dist/serve/site-ui/docs/examples/chess/index.html +2 -2
- package/dist/serve/site-ui/docs/examples/index.html +1 -1
- package/dist/serve/site-ui/docs/firestore-compat/index.html +186 -195
- package/dist/serve/site-ui/docs/firestore-compat.md +184 -195
- package/dist/serve/site-ui/docs/functions-rtdb-compat/index.html +15 -15
- package/dist/serve/site-ui/docs/functions-rtdb-compat.md +14 -14
- package/dist/serve/site-ui/docs/get-started/how-the-swap-works/index.html +1 -1
- package/dist/serve/site-ui/docs/get-started/nextjs/index.html +57 -0
- package/dist/serve/site-ui/docs/get-started/nextjs.md +86 -0
- package/dist/serve/site-ui/docs/get-started/start-building/index.html +25 -8
- package/dist/serve/site-ui/docs/get-started/start-building.md +34 -5
- package/dist/serve/site-ui/docs/get-started/vite/index.html +26 -0
- package/dist/serve/site-ui/docs/get-started/vite.md +45 -0
- package/dist/serve/site-ui/docs/index.json +668 -103
- package/dist/serve/site-ui/docs/messaging-compat/index.html +56 -56
- package/dist/serve/site-ui/docs/messaging-compat.md +55 -55
- package/dist/serve/site-ui/docs/observe/resolve-runtime-status/index.html +1 -1
- package/dist/serve/site-ui/docs/observe/see-whats-happening/index.html +1 -1
- package/dist/serve/site-ui/docs/observe/shape-your-data/index.html +1 -1
- package/dist/serve/site-ui/docs/overview/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-admin-app-reference-api/index.html +39 -13
- package/dist/serve/site-ui/docs/pyric-admin-app-reference-api.md +28 -2
- package/dist/serve/site-ui/docs/pyric-admin-auth-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-admin-database-reference-api/index.html +38 -6
- package/dist/serve/site-ui/docs/pyric-admin-database-reference-api.md +43 -0
- package/dist/serve/site-ui/docs/pyric-admin-firestore-reference-api/index.html +9 -1
- package/dist/serve/site-ui/docs/pyric-admin-firestore-reference-api.md +8 -0
- package/dist/serve/site-ui/docs/pyric-admin-messaging-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-admin-storage-reference-api/index.html +27 -4
- package/dist/serve/site-ui/docs/pyric-admin-storage-reference-api.md +23 -0
- package/dist/serve/site-ui/docs/pyric-ai-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ai-scripting-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-app-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-auth-reference-api/index.html +2 -2
- package/dist/serve/site-ui/docs/pyric-auth-reference-api.md +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-assurance-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-bridge-client-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-bridge-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-conformance-browser-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-conformance-docs-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-conformance-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-credentials-node-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-discover-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-next-reference-api/index.html +123 -0
- package/dist/serve/site-ui/docs/pyric-cli-next-reference-api.md +99 -0
- package/dist/serve/site-ui/docs/pyric-cli-register-app-bridge-reference-api/index.html +127 -0
- package/dist/serve/site-ui/docs/pyric-cli-register-app-bridge-reference-api.md +174 -0
- package/dist/serve/site-ui/docs/pyric-cli-register-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-remote-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-serve-worker-reference-api/index.html +570 -326
- package/dist/serve/site-ui/docs/pyric-cli-serve-worker-reference-api.md +198 -6
- package/dist/serve/site-ui/docs/pyric-cli-verify-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-cli-vite-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-database-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-firestore-reference-api/index.html +2971 -627
- package/dist/serve/site-ui/docs/pyric-firestore-reference-api.md +2873 -517
- package/dist/serve/site-ui/docs/pyric-messaging-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-messaging-sw-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-rules-reference-api/index.html +43 -3
- package/dist/serve/site-ui/docs/pyric-rules-reference-api.md +8 -0
- package/dist/serve/site-ui/docs/pyric-sandbox-database-reference-api/index.html +26 -2
- package/dist/serve/site-ui/docs/pyric-sandbox-database-reference-api.md +24 -0
- package/dist/serve/site-ui/docs/pyric-sandbox-firestore-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-sandbox-reference-api/index.html +77 -9
- package/dist/serve/site-ui/docs/pyric-sandbox-reference-api.md +28 -13
- package/dist/serve/site-ui/docs/pyric-storage-reference-api/index.html +240 -63
- package/dist/serve/site-ui/docs/pyric-storage-reference-api.md +164 -5
- package/dist/serve/site-ui/docs/pyric-ui-agents-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-auth-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-events-hooks-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-events-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-firestore-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-primitives-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-rtdb-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-rules-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-storage-reference-api/index.html +2 -1
- package/dist/serve/site-ui/docs/pyric-ui-storage-reference-api.md +1 -0
- package/dist/serve/site-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/pyric-ui-traffic-reference-api/index.html +1 -1
- package/dist/serve/site-ui/docs/rules-compat/index.html +87 -79
- package/dist/serve/site-ui/docs/rules-compat.md +86 -78
- package/dist/serve/site-ui/docs/secure/audit-your-rules/index.html +1 -1
- package/dist/serve/site-ui/docs/secure/firestore-rules-limits/index.html +1 -1
- package/dist/serve/site-ui/docs/secure/read-a-denial/index.html +1 -1
- package/dist/serve/site-ui/docs/secure/rtdb-rules-in-typescript/index.html +1 -1
- package/dist/serve/site-ui/docs/secure/rules-standard-library/index.html +1 -1
- package/dist/serve/site-ui/docs/secure/secure-it-with-rules/index.html +1 -1
- package/dist/serve/site-ui/docs/secure/simulate-and-lint/index.html +1 -1
- package/dist/serve/site-ui/docs/secure/write-a-rules-test-suite/index.html +1 -1
- package/dist/serve/site-ui/docs/ship/ship-to-production/index.html +1 -1
- package/dist/serve/site-ui/docs/ship/test-in-node/index.html +1 -1
- package/dist/serve/site-ui/docs/storage-compat/index.html +119 -125
- package/dist/serve/site-ui/docs/storage-compat.md +118 -124
- package/dist/serve/site-ui/docs/trust/how-we-know-it-matches-firebase/index.html +1 -1
- package/dist/serve/site-ui/docs/trust/rules-standard-library/index.html +1 -1
- package/dist/serve/site-ui/docs/trust/storage-rules-stdlib-research/index.html +1 -1
- package/dist/serve/site-ui/docs/trust/versioning-and-compatibility/index.html +1 -1
- package/dist/serve/site-ui/docs/tutorial/index.html +1 -1
- package/dist/serve/site-ui/examples/chess/index.html +1 -1
- package/dist/serve/site-ui/examples/firestore-first-write/index.html +1 -1
- package/dist/serve/site-ui/firestore/index.html +2 -2
- package/dist/serve/site-ui/index.html +2 -2
- package/dist/serve/site-ui/llms.txt +6 -2
- package/dist/serve/site-ui/rtdb/index.html +2 -2
- package/dist/serve/site-ui/settings/index.html +2 -2
- package/dist/serve/site-ui/storage/index.html +2 -2
- package/dist/serve/site-ui/traffic/index.html +2 -2
- package/dist/serve/vite-ai-config.d.ts +4 -1
- package/dist/serve/vite-ai-config.d.ts.map +1 -1
- package/dist/serve/vite-ai-config.js +83 -19
- package/dist/serve/vite-ai-config.js.map +1 -1
- package/dist/serve/vite-generation-rules-watch.d.ts.map +1 -1
- package/dist/serve/vite-generation-rules-watch.js +61 -14
- package/dist/serve/vite-generation-rules-watch.js.map +1 -1
- package/dist/serve/vite-module-swap.d.ts +4 -1
- package/dist/serve/vite-module-swap.d.ts.map +1 -1
- package/dist/serve/vite-module-swap.js +106 -21
- package/dist/serve/vite-module-swap.js.map +1 -1
- package/dist/serve/vite-plugin.d.ts.map +1 -1
- package/dist/serve/vite-plugin.js +45 -5
- package/dist/serve/vite-plugin.js.map +1 -1
- package/dist/serve/vite-sandbox-generation.js +1 -1
- package/dist/serve/vite-sandbox-generation.js.map +1 -1
- package/dist/serve/worker/client/resumable.d.ts +30 -0
- package/dist/serve/worker/client/resumable.d.ts.map +1 -0
- package/dist/serve/worker/client/resumable.js +416 -0
- package/dist/serve/worker/client/resumable.js.map +1 -0
- package/dist/serve/worker/client/rtdb-references.d.ts.map +1 -1
- package/dist/serve/worker/client/rtdb-references.js +4 -1
- package/dist/serve/worker/client/rtdb-references.js.map +1 -1
- package/dist/serve/worker/client/storage.d.ts +16 -2
- package/dist/serve/worker/client/storage.d.ts.map +1 -1
- package/dist/serve/worker/client/storage.js +57 -6
- package/dist/serve/worker/client/storage.js.map +1 -1
- package/dist/serve/worker/host/rules.d.ts.map +1 -1
- package/dist/serve/worker/host/rules.js +2 -1
- package/dist/serve/worker/host/rules.js.map +1 -1
- package/dist/serve/worker/index.d.ts +1 -1
- package/dist/serve/worker/index.d.ts.map +1 -1
- package/dist/serve/worker/index.js +1 -1
- package/dist/serve/worker/index.js.map +1 -1
- package/dist/serve/worker/serve-init.d.ts.map +1 -1
- package/dist/serve/worker/serve-init.js +31 -0
- package/dist/serve/worker/serve-init.js.map +1 -1
- package/package.json +15 -4
- package/src/assurance/.generated/conformance-verdicts.ts +80 -72
- package/src/bridge/client/dispatch.ts +1 -1
- package/src/cli/cli.test.ts +14 -0
- package/src/cli/database-rules.ts +6 -4
- package/src/cli/dev-runner.ts +21 -0
- package/src/cli/serve.ts +62 -5
- package/src/cli/verify.ts +2 -2
- package/src/conformance/.generated/can-i-use-browser.ts +1 -1
- package/src/conformance/.generated/can-i-use.ts +1 -1
- package/src/conformance/.generated/conformance-docs.ts +1 -1
- package/src/next/client-aliases.ts +39 -0
- package/src/next/dev-rewrites.ts +77 -0
- package/src/next/guard.ts +61 -0
- package/src/next/index.ts +16 -0
- package/src/next/runtime-env.ts +18 -0
- package/src/next/server-external-packages.ts +43 -0
- package/src/next/target-url.ts +46 -0
- package/src/next/turbopack-config.ts +54 -0
- package/src/next/types.ts +47 -0
- package/src/next/webpack-config.ts +71 -0
- package/src/next/with-pyric.ts +58 -0
- package/src/register/app-bridge.ts +79 -0
- package/src/register/hooks.ts +6 -1
- package/src/register/index.ts +1 -1
- package/src/register/mapping.ts +50 -4
- package/src/rtdb/rules-json.ts +110 -0
- package/src/serve/bundler.ts +2 -0
- package/src/serve/discovery.ts +65 -44
- package/src/serve/entries/app-ai-passthrough.ts +83 -0
- package/src/serve/entries/auth-helper-core.ts +44 -8
- package/src/serve/entries/auth.ts +9 -4
- package/src/serve/entries/bridge-url.ts +9 -2
- package/src/serve/entries/database.ts +1 -0
- package/src/serve/entries/firestore.ts +1 -0
- package/src/serve/entries/init.ts +5 -2
- package/src/serve/entries/runtime.ts +25 -0
- package/src/serve/entries/storage.ts +12 -1
- package/src/serve/html-injection.ts +26 -1
- package/src/serve/rules.ts +2 -2
- package/src/serve/runtime/chip-config.ts +19 -6
- package/src/serve/sandbox-session.ts +31 -2
- package/src/serve/vite-ai-config.ts +86 -19
- package/src/serve/vite-generation-rules-watch.ts +67 -15
- package/src/serve/vite-module-swap.ts +121 -21
- package/src/serve/vite-plugin.ts +44 -6
- package/src/serve/vite-sandbox-generation.ts +1 -1
- package/src/serve/worker/client/resumable.ts +506 -0
- package/src/serve/worker/client/rtdb-references.ts +4 -1
- package/src/serve/worker/client/storage.ts +77 -7
- package/src/serve/worker/host/rules.ts +2 -1
- package/src/serve/worker/index.ts +4 -0
- package/src/serve/worker/serve-init.ts +30 -0
- package/dist/serve/site-ui/_astro/_studio_.BtYpqe1A.css +0 -1
- package/dist/serve/site-ui/_astro/app.BnMC0ywl.js +0 -109
- package/dist/serve/site-ui/_astro/app.DVXXR-WI.js +0 -1
- package/dist/serve/site-ui/_astro/index.B4Kh80he.js +0 -1
- package/dist/serve/site-ui/_astro/reads.D1exkX1-.js +0 -1
- package/dist/serve/site-ui/_astro/sandbox-controls.BqMePr5V.js +0 -1153
|
@@ -19,123 +19,131 @@
|
|
|
19
19
|
<div class="compat-list">
|
|
20
20
|
<details class="compat-row" data-status="ok">
|
|
21
21
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior">CEL builtins <code>math.<em></code>/<code>timestamp.</em></code>/<code>duration.*</code> (FM3) — arithmetic, date, and duration comparisons in rules</span></span></span></summary>
|
|
22
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-firestore-builtins-time-and-math</code> — production Firestore Rules Test API verdicts for corpus scenario "builtins-time-and-math", replayed verdict-for-verdict against the local rules simulator by <code>unit:rules/oracle-conformance.test.ts</code>; all cases match production.</div></div>
|
|
22
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-builtins-time-and-math.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-builtins-time-and-math</code></a> — production Firestore Rules Test API verdicts for corpus scenario "builtins-time-and-math", replayed verdict-for-verdict against the local rules simulator by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L55" target="_blank" rel="noopener noreferrer"><code>unit:rules/oracle-conformance.test.ts</code></a>; all cases match production.</div></div>
|
|
23
23
|
</details>
|
|
24
24
|
<details class="compat-row" data-status="ok">
|
|
25
25
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior"><code>Bytes</code>, <code>String.toUtf8()</code>, and <code>hashing.{md5,sha256,crc32,crc32c}()</code> (Item 5.3) in rules</span></span></span></summary>
|
|
26
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-firestore-bytes-toutf8-and-hashing</code> — a 2026-07-21 production Firestore Rules Test API recapture supplies 20 verdicts, including paired negative and positive witnesses for padded base64url, the URL-safe alphabet, uppercase hexadecimal MD5/SHA-256, and production's little-endian CRC32/CRC32C byte serialization. <code>unit:rules/oracle-conformance.test.ts</code> replays all verdicts against the local simulator; <code>unit:rules/simulator/wrappers/bytes.test.ts</code> pins the exact representations and reference digests.</div></div>
|
|
26
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-bytes-toutf8-and-hashing.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-bytes-toutf8-and-hashing</code></a> — a 2026-07-21 production Firestore Rules Test API recapture supplies 20 verdicts, including paired negative and positive witnesses for padded base64url, the URL-safe alphabet, uppercase hexadecimal MD5/SHA-256, and production's little-endian CRC32/CRC32C byte serialization. <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>unit:rules/oracle-conformance.test.ts</code></a> replays all verdicts against the local simulator; <code>unit:rules/simulator/wrappers/bytes.test.ts</code> pins the exact representations and reference digests.</div></div>
|
|
27
27
|
</details>
|
|
28
28
|
<details class="compat-row" data-status="ok">
|
|
29
29
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior">Typed cross-type operator overloads for <code>Timestamp</code>/<code>Duration</code> (Item 2) in rules — no silent numeric coercion / type-identity loss</span></span></span></summary>
|
|
30
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-firestore-cross-type-operator-overloads</code> — production Firestore Rules Test API verdicts for corpus scenario "cross-type-operator-overloads", replayed verdict-for-verdict against the local rules simulator by <code>unit:rules/oracle-conformance.test.ts</code>; all cases match production.</div></div>
|
|
30
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-cross-type-operator-overloads.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-cross-type-operator-overloads</code></a> — production Firestore Rules Test API verdicts for corpus scenario "cross-type-operator-overloads", replayed verdict-for-verdict against the local rules simulator by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>unit:rules/oracle-conformance.test.ts</code></a>; all cases match production.</div></div>
|
|
31
31
|
</details>
|
|
32
32
|
<details class="compat-row" data-status="ok">
|
|
33
33
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior">CEL tri-state error absorption in <code>||</code>/<code>&&</code> (RULES-B3) — <code>error || true</code> → ALLOW, <code>error && false</code> → DENY, commutative absorption (not JS left-to-right short-circuit)</span></span></span></summary>
|
|
34
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-firestore-error-absorption-and-or</code> — production Firestore Rules Test API verdicts for corpus scenario "error-absorption-and-or", replayed verdict-for-verdict against the local rules simulator by <code>unit:rules/oracle-conformance.test.ts</code>; all cases match production.</div></div>
|
|
34
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-error-absorption-and-or.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-error-absorption-and-or</code></a> — production Firestore Rules Test API verdicts for corpus scenario "error-absorption-and-or", replayed verdict-for-verdict against the local rules simulator by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>unit:rules/oracle-conformance.test.ts</code></a>; all cases match production.</div></div>
|
|
35
35
|
</details>
|
|
36
36
|
<details class="compat-row" data-status="ok">
|
|
37
37
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior"><code>getAfter()</code>/<code>existsAfter()</code> expose the projected post-write target and cross-document atomic batch state; create exists, delete does not, and an unrelated unchanged document falls back to its committed existence</span></span></span></summary>
|
|
38
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-firestore-get-after-and-exists-after</code> records authenticated Web SDK verdicts against temporarily deployed production rules, including target create/delete and unrelated-path semantics. Its lifecycle proves exact rules release restoration; retained diagnostics document why the hosted Rules Test API was not sufficient. Replayed verdict-for-verdict by <code>unit:rules/oracle-conformance.test.ts</code>; <code>get-after.test.ts</code> and <code>get-after-batch.test.ts</code> cover target, sibling-write, solo-write denial, delete, and atomicity locally.</div></div>
|
|
38
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-get-after-and-exists-after.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-get-after-and-exists-after</code></a> records authenticated Web SDK verdicts against temporarily deployed production rules, including target create/delete and unrelated-path semantics. Its lifecycle proves exact rules release restoration; retained diagnostics document why the hosted Rules Test API was not sufficient. Replayed verdict-for-verdict by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L28" target="_blank" rel="noopener noreferrer"><code>unit:rules/oracle-conformance.test.ts</code></a>; <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/sandbox/firestore/simulator/get-after.test.ts#L2" target="_blank" rel="noopener noreferrer"><code>get-after.test.ts</code></a> and <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/sandbox/firestore/simulator/get-after-batch.test.ts#L4" target="_blank" rel="noopener noreferrer"><code>get-after-batch.test.ts</code></a> cover target, sibling-write, solo-write denial, delete, and atomicity locally.</div></div>
|
|
39
39
|
</details>
|
|
40
40
|
<details class="compat-row" data-status="ok">
|
|
41
41
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior"><code>get()</code> of a missing document (RULES-B8) in rules — resource identity (<code>id</code>/<code>__name__</code>) exposure on a mocked/missing get() result</span></span></span></summary>
|
|
42
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-firestore-get-missing-doc</code> — production Firestore Rules Test API verdicts for corpus scenario "get-missing-doc", replayed verdict-for-verdict against the local rules simulator by <code>unit:rules/oracle-conformance.test.ts</code>. Serializable <code>functionMocks</code> now retain their production data-only shape, so mocked <code>get()</code> results leave <code>id</code>/<code>__name__</code> absent and both identity reads error to DENY; real DocStore lookups retain their separate identity-bearing path. All 8 cases match production.</div></div>
|
|
42
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-get-missing-doc.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-get-missing-doc</code></a> — production Firestore Rules Test API verdicts for corpus scenario "get-missing-doc", replayed verdict-for-verdict against the local rules simulator by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>unit:rules/oracle-conformance.test.ts</code></a>. Serializable <code>functionMocks</code> now retain their production data-only shape, so mocked <code>get()</code> results leave <code>id</code>/<code>__name__</code> absent and both identity reads error to DENY; real DocStore lookups retain their separate identity-bearing path. All 8 cases match production.</div></div>
|
|
43
43
|
</details>
|
|
44
44
|
<details class="compat-row" data-status="ok">
|
|
45
45
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior"><code>request.path</code>/<code>request.query</code>/<code>resource.id</code>/<code>resource.__name__</code> globals (Item 6) in rules</span></span></span></summary>
|
|
46
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-firestore-globals-request-path-and-resource-id</code> — production Firestore Rules Test API verdicts for corpus scenario "globals-request-path-and-resource-id", replayed verdict-for-verdict against the local rules simulator by <code>unit:rules/oracle-conformance.test.ts</code>. <code>request.query</code> is now absent on non-list operations, so reading it on create errors to DENY instead of false-ALLOWing through an invented empty map. <code>request.path</code> and the create-time absent-resource controls remain unchanged; all 6 cases match production. Resource identity on an EXISTING document is scoped to firestore-rules#183.</div></div>
|
|
46
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-globals-request-path-and-resource-id.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-globals-request-path-and-resource-id</code></a> — production Firestore Rules Test API verdicts for corpus scenario "globals-request-path-and-resource-id", replayed verdict-for-verdict against the local rules simulator by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>unit:rules/oracle-conformance.test.ts</code></a>. <code>request.query</code> is now absent on non-list operations, so reading it on create errors to DENY instead of false-ALLOWing through an invented empty map. <code>request.path</code> and the create-time absent-resource controls remain unchanged; all 6 cases match production. Resource identity on an EXISTING document is scoped to firestore-rules#183.</div></div>
|
|
47
47
|
</details>
|
|
48
48
|
<details class="compat-row" data-status="ok">
|
|
49
49
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior"><code>int</code>/<code>float</code> division and type distinction (RULES-B5) in rules — truncating int÷int, float division stays float, div-by-zero denies, <code>is int</code>/<code>is float</code> distinct</span></span></span></summary>
|
|
50
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-firestore-int-float-and-division</code> — production Firestore Rules Test API verdicts for all ten corpus cases, replayed verdict-for-verdict by <code>unit:rules/oracle-conformance.test.ts</code>. The simulator now revives non-integral JSON wire numbers as RulesFloat values, preserving production's float payload type while retaining bare integral numbers as ints; <code>unit:rules/simulator/handler.test.ts</code> pins both literal and payload distinctions.</div></div>
|
|
50
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-int-float-and-division.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-int-float-and-division</code></a> — production Firestore Rules Test API verdicts for all ten corpus cases, replayed verdict-for-verdict by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>unit:rules/oracle-conformance.test.ts</code></a>. The simulator now revives non-integral JSON wire numbers as RulesFloat values, preserving production's float payload type while retaining bare integral numbers as ints; <code>unit:rules/simulator/handler.test.ts</code> pins both literal and payload distinctions.</div></div>
|
|
51
51
|
</details>
|
|
52
52
|
<details class="compat-row" data-status="ok">
|
|
53
53
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior"><code>List.concat()</code>/<code>removeAll()</code>/<code>toSet()</code> (Item 5.2) in rules</span></span></span></summary>
|
|
54
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-firestore-list-methods-concat-removeall-toset</code> — production Firestore Rules Test API verdicts for all nine cases, replayed verdict-for-verdict by <code>unit:rules/oracle-conformance.test.ts</code>. The seven positive List witnesses and the concat DENY witness match; the historical <code>toSet().difference(list)</code> case remains DENY because production requires a Set argument.</div></div>
|
|
54
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-list-methods-concat-removeall-toset.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-list-methods-concat-removeall-toset</code></a> — production Firestore Rules Test API verdicts for all nine cases, replayed verdict-for-verdict by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>unit:rules/oracle-conformance.test.ts</code></a>. The seven positive List witnesses and the concat DENY witness match; the historical <code>toSet().difference(list)</code> case remains DENY because production requires a Set argument.</div></div>
|
|
55
55
|
</details>
|
|
56
56
|
<details class="compat-row" data-status="ok">
|
|
57
57
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior"><code>Map.get(key, default)</code>, including list-form nested-path traversal (Item 3), in rules</span></span></span></summary>
|
|
58
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-firestore-map-get-string-and-list-form</code> — production Firestore Rules Test API verdicts for corpus scenario "map-get-string-and-list-form", replayed verdict-for-verdict against the local rules simulator by <code>unit:rules/oracle-conformance.test.ts</code>; all cases match production.</div></div>
|
|
58
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-map-get-string-and-list-form.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-map-get-string-and-list-form</code></a> — production Firestore Rules Test API verdicts for corpus scenario "map-get-string-and-list-form", replayed verdict-for-verdict against the local rules simulator by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>unit:rules/oracle-conformance.test.ts</code></a>; all cases match production.</div></div>
|
|
59
59
|
</details>
|
|
60
60
|
<details class="compat-row" data-status="ok">
|
|
61
61
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior"><code>matches()</code> as an anchored full-string RE2 match (RULES-B4) in rules — a pattern matching only a substring is <code>false</code></span></span></span></summary>
|
|
62
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-firestore-matches-full-string-regex</code> — production Firestore Rules Test API verdicts for corpus scenario "matches-full-string-regex", replayed verdict-for-verdict against the local rules simulator by <code>unit:rules/oracle-conformance.test.ts</code>; all cases match production.</div></div>
|
|
62
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-matches-full-string-regex.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-matches-full-string-regex</code></a> — production Firestore Rules Test API verdicts for corpus scenario "matches-full-string-regex", replayed verdict-for-verdict against the local rules simulator by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>unit:rules/oracle-conformance.test.ts</code></a>; all cases match production.</div></div>
|
|
63
63
|
</details>
|
|
64
64
|
<details class="compat-row" data-status="ok">
|
|
65
65
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior"><code>Path</code> wrapper, <code>path()</code> constructor, and <code>Path.bind()</code> (Item 5.4) in rules</span></span></span></summary>
|
|
66
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-firestore-path-constructor-and-bind</code> — production Firestore Rules Test API verdicts for all nine corpus cases in "path-constructor-and-bind", replayed verdict-for-verdict against the local rules simulator by <code>unit:rules/oracle-conformance.test.ts</code>, including production's rejection of a Path argument to <code>path()</code>.</div></div>
|
|
66
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-path-constructor-and-bind.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-path-constructor-and-bind</code></a> — production Firestore Rules Test API verdicts for all nine corpus cases in "path-constructor-and-bind", replayed verdict-for-verdict against the local rules simulator by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>unit:rules/oracle-conformance.test.ts</code></a>, including production's rejection of a Path argument to <code>path()</code>.</div></div>
|
|
67
67
|
</details>
|
|
68
68
|
<details class="compat-row" data-status="ok">
|
|
69
69
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior">Own-keys-only map membership and constructor-access denial (RULES-B7) in rules — <code>'toString' in map</code> is <code>false</code>, <code>.constructor</code> access errors (no JS prototype-chain leakage)</span></span></span></summary>
|
|
70
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-firestore-prototype-chain-keys</code> — production Firestore Rules Test API verdicts for corpus scenario "prototype-chain-keys", replayed verdict-for-verdict against the local rules simulator by <code>unit:rules/oracle-conformance.test.ts</code>; all cases match production.</div></div>
|
|
70
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-prototype-chain-keys.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-prototype-chain-keys</code></a> — production Firestore Rules Test API verdicts for corpus scenario "prototype-chain-keys", replayed verdict-for-verdict against the local rules simulator by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>unit:rules/oracle-conformance.test.ts</code></a>; all cases match production.</div></div>
|
|
71
71
|
</details>
|
|
72
72
|
<details class="compat-row" data-status="ok">
|
|
73
73
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior">Range-slice <code>[i:j]</code> syntax for <code>List</code> and <code>String</code> (Item 4) in rules</span></span></span></summary>
|
|
74
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-firestore-range-slice-list-and-string</code> — production Firestore Rules Test API verdicts for all ten corpus cases in "range-slice-list-and-string", replayed verdict-for-verdict against the local rules simulator by <code>unit:rules/oracle-conformance.test.ts</code>, including out-of-bounds slice-end rejection for both lists and strings.</div></div>
|
|
74
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-range-slice-list-and-string.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-range-slice-list-and-string</code></a> — production Firestore Rules Test API verdicts for all ten corpus cases in "range-slice-list-and-string", replayed verdict-for-verdict against the local rules simulator by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>unit:rules/oracle-conformance.test.ts</code></a>, including out-of-bounds slice-end rejection for both lists and strings.</div></div>
|
|
75
75
|
</details>
|
|
76
76
|
<details class="compat-row" data-status="ok">
|
|
77
77
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior"><code>Set.difference()</code>/<code>union()</code>/<code>intersection()</code> (Item 5.1) in rules</span></span></span></summary>
|
|
78
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-firestore-set-algebra-difference-union-intersection</code> captures the receiver and argument boundary in twelve production cases: Map.keys() is a List and rejects Set-only algebra, explicit toSet() receivers ALLOW difference/union/intersection with Set arguments, and a wrong-result control DENIES. The local simulator replays every verdict and the per-construct acceptance probes use the same positive toSet() shapes
|
|
78
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-set-algebra-difference-union-intersection.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-set-algebra-difference-union-intersection</code></a> captures the receiver and argument boundary in twelve production cases: Map.keys() is a List and rejects Set-only algebra, explicit toSet() receivers ALLOW difference/union/intersection with Set arguments, and a wrong-result control DENIES. The local simulator replays every verdict and the per-construct acceptance probes use the same positive toSet() shapes. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>oracle-conformance.test.ts</code></a>)</div></div>
|
|
79
79
|
</details>
|
|
80
80
|
<details class="compat-row" data-status="ok">
|
|
81
81
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior">String-literal escape handling feeding <code>matches()</code> (Class B) in rules — <code>\\.</code> is unescaped before RE2 compilation, not forwarded raw to a JS <code>RegExp</code></span></span></span></summary>
|
|
82
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-firestore-string-literals-and-regex</code> — production Firestore Rules Test API verdicts for corpus scenario "string-literals-and-regex", replayed verdict-for-verdict against the local rules simulator by <code>unit:rules/oracle-conformance.test.ts</code>; all cases match production.</div></div>
|
|
82
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-string-literals-and-regex.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-string-literals-and-regex</code></a> — production Firestore Rules Test API verdicts for corpus scenario "string-literals-and-regex", replayed verdict-for-verdict against the local rules simulator by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>unit:rules/oracle-conformance.test.ts</code></a>; all cases match production.</div></div>
|
|
83
83
|
</details>
|
|
84
84
|
<details class="compat-row" data-status="ok">
|
|
85
85
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior">Missing-field access as a runtime error (RULES-B2) in rules — <code>typo == null</code> denies (missing access is not null); <code>!(key in map)</code> is the real absence check</span></span></span></summary>
|
|
86
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-firestore-undefined-field-access</code> — production Firestore Rules Test API verdicts for corpus scenario "undefined-field-access", replayed verdict-for-verdict against the local rules simulator by <code>unit:rules/oracle-conformance.test.ts</code>; all cases match production.</div></div>
|
|
86
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-undefined-field-access.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-undefined-field-access</code></a> — production Firestore Rules Test API verdicts for corpus scenario "undefined-field-access", replayed verdict-for-verdict against the local rules simulator by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>unit:rules/oracle-conformance.test.ts</code></a>; all cases match production.</div></div>
|
|
87
87
|
</details>
|
|
88
88
|
<details class="compat-row" data-status="ok">
|
|
89
89
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior">Explicit <code>UNSUPPORTED</code> reporting for unimplemented built-ins (Item 0.A) in rules — an unimplemented built-in abstains rather than silently DENYing</span></span></span></summary>
|
|
90
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-firestore-unsupported-feature-witness</code> — production Firestore Rules Test API verdicts for corpus scenario "unsupported-feature-witness", replayed verdict-for-verdict against the local rules simulator by <code>unit:rules/oracle-conformance.test.ts</code>; all cases match production.</div></div>
|
|
90
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-unsupported-feature-witness.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-unsupported-feature-witness</code></a> — production Firestore Rules Test API verdicts for corpus scenario "unsupported-feature-witness", replayed verdict-for-verdict against the local rules simulator by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>unit:rules/oracle-conformance.test.ts</code></a>; all cases match production.</div></div>
|
|
91
91
|
</details>
|
|
92
92
|
<details class="compat-row" data-status="ok">
|
|
93
93
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior">Required-fields validation idiom in rules — <code>request.resource.data.keys().hasAll()/hasOnly()</code> and the <code>diff().addedKeys()/removedKeys()/changedKeys()/affectedKeys()/unchangedKeys()</code> MapDiff family gating field-level mutations</span></span></span></summary>
|
|
94
|
-
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 7 cases (exact required-field set on create, field-scoped update via MapDiff). <code>oracle:rules-firestore-required-fields-and-mapdiff</code> — replayed by <code>unit:rules/oracle-conformance.test.ts</code>.</div></div>
|
|
94
|
+
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 7 cases (exact required-field set on create, field-scoped update via MapDiff). <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-required-fields-and-mapdiff.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-required-fields-and-mapdiff</code></a> — replayed by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>unit:rules/oracle-conformance.test.ts</code></a>.</div></div>
|
|
95
95
|
</details>
|
|
96
96
|
<details class="compat-row" data-status="ok">
|
|
97
97
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior"><code>String.split()/lower()/upper()/trim()/replace()/size()</code>, <code>List.hasAll()/hasAny()/hasOnly()/join()</code>, and <code>Map.values()</code> in rules</span></span></span></summary>
|
|
98
|
-
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 4 cases (CSV-split membership, slug/title/code normalization). <code>oracle:rules-firestore-list-and-string-methods</code> — replayed by <code>unit:rules/oracle-conformance.test.ts</code>.</div></div>
|
|
98
|
+
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 4 cases (CSV-split membership, slug/title/code normalization). <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-list-and-string-methods.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-list-and-string-methods</code></a> — replayed by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>unit:rules/oracle-conformance.test.ts</code></a>.</div></div>
|
|
99
99
|
</details>
|
|
100
100
|
<details class="compat-row" data-status="ok">
|
|
101
101
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior"><code>request.time</code> Timestamp accessors (year/month/day/hours/minutes/seconds/nanos/dayOfWeek/dayOfYear/toMillis/date/time), <code>math.floor/round/sqrt/pow/isNaN</code>, <code>int()/float()/string()</code> casts, <code>request.method</code>, and <code>>=</code> / <code>*</code> operators in rules</span></span></span></summary>
|
|
102
|
-
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 3 cases (request.time pinned via requestTime for determinism). <code>oracle:rules-firestore-time-math-and-casts</code> — replayed by <code>unit:rules/oracle-conformance.test.ts</code>.</div></div>
|
|
102
|
+
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 3 cases (request.time pinned via requestTime for determinism). <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-time-math-and-casts.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-time-math-and-casts</code></a> — replayed by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L24" target="_blank" rel="noopener noreferrer"><code>unit:rules/oracle-conformance.test.ts</code></a>.</div></div>
|
|
103
103
|
</details>
|
|
104
104
|
<details class="compat-row" data-status="ok">
|
|
105
105
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior"><code>latlng.value().latitude()/longitude()/distance()</code> and <code>duration.value()/time()/abs()</code> in rules</span></span></span></summary>
|
|
106
|
-
<div class="compat-evidence"><div class="compat-probe">Production captures from 2026-07-12 and the 2026-07-21 recapture prove the simulator matches the Firestore Rules Test API verdict-for-verdict on all 3 cases: coordinate and duration bounds plus exact <code>duration.value(1500, 'ms').seconds()</code> / <code>.nanos()</code> components. <code>oracle:rules-firestore-duration-and-latlng</code> — replayed by <code>unit:rules/oracle-conformance.test.ts</code>.</div></div>
|
|
106
|
+
<div class="compat-evidence"><div class="compat-probe">Production captures from 2026-07-12 and the 2026-07-21 recapture prove the simulator matches the Firestore Rules Test API verdict-for-verdict on all 3 cases: coordinate and duration bounds plus exact <code>duration.value(1500, 'ms').seconds()</code> / <code>.nanos()</code> components. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-duration-and-latlng.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-duration-and-latlng</code></a> — replayed by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>unit:rules/oracle-conformance.test.ts</code></a>.</div></div>
|
|
107
107
|
</details>
|
|
108
108
|
<details class="compat-row" data-status="ok">
|
|
109
109
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior">User-defined <code>function</code>/<code>let</code>, granular <code>allow get/list/update/write</code> verbs, the ternary operator, and a recursive <code>{document=**}</code> match in rules</span></span></span></summary>
|
|
110
|
-
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 7 cases (role-gated docs + public recursive subtree). <code>oracle:rules-firestore-functions-verbs-and-recursive</code> — replayed by <code>unit:rules/oracle-conformance.test.ts</code>.</div></div>
|
|
110
|
+
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 7 cases (role-gated docs + public recursive subtree). <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-functions-verbs-and-recursive.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-functions-verbs-and-recursive</code></a> — replayed by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L33" target="_blank" rel="noopener noreferrer"><code>unit:rules/oracle-conformance.test.ts</code></a>.</div></div>
|
|
111
111
|
</details>
|
|
112
112
|
<details class="compat-row" data-status="ok">
|
|
113
113
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior">Resource identity (<code>resource.id</code>/<code>resource.__name__</code>/<code>request.resource.id</code>) on an EXISTING document (RULES-B12) — production leaves the identity keys ABSENT, so reading one errors → DENY, the error survives negation, and only a determining <code>||</code> operand absorbs it</span></span></span></summary>
|
|
114
|
-
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 13 cases. Production builds <code>resource</code> (and <code>request.resource</code>) from the supplied document alone and derives NO identity from the request path, so <code>resource.id</code>/<code>resource.__name__</code>/<code>request.resource.id</code> read as absent properties — verbatim <code>Property id is undefined on object.</code> / <code>Property __name__ is undefined on object.</code> — which absorb to DENY. The simulator previously SYNTHESIZED <code>id</code>/<code>__name__</code> from the request path on get/list/update/delete, so <code>resource.id == id</code> ALLOWed where production DENIES: an over-permissive divergence, now removed. The negation cases (<code>resource.id != 'zzz'</code>, <code>!(resource.id == 'zzz')</code>) pin that the absent read is a propagating error rather than a false, which an absent-as-undefined model would false-ALLOW. <code>oracle:rules-firestore-resource-document-identity</code> — replayed by <code>unit:rules/oracle-conformance.test.ts</code>.</div></div>
|
|
114
|
+
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 13 cases. Production builds <code>resource</code> (and <code>request.resource</code>) from the supplied document alone and derives NO identity from the request path, so <code>resource.id</code>/<code>resource.__name__</code>/<code>request.resource.id</code> read as absent properties — verbatim <code>Property id is undefined on object.</code> / <code>Property __name__ is undefined on object.</code> — which absorb to DENY. The simulator previously SYNTHESIZED <code>id</code>/<code>__name__</code> from the request path on get/list/update/delete, so <code>resource.id == id</code> ALLOWed where production DENIES: an over-permissive divergence, now removed. The negation cases (<code>resource.id != 'zzz'</code>, <code>!(resource.id == 'zzz')</code>) pin that the absent read is a propagating error rather than a false, which an absent-as-undefined model would false-ALLOW. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-resource-document-identity.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-resource-document-identity</code></a> — replayed by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>unit:rules/oracle-conformance.test.ts</code></a>.</div></div>
|
|
115
115
|
</details>
|
|
116
116
|
<details class="compat-row" data-status="ok">
|
|
117
117
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior">Request-target <code>resource</code> on a missing document (RULES-B13) — get/update/delete existence guards, null comparison, and data access all error to DENY</span></span></span></summary>
|
|
118
|
-
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-12: production capture proves the simulator matches the Firestore Rules Test API verdict-for-verdict on all 9 cases. A missing request target makes the <code>resource</code> global an error value: <code>resource != null</code>, <code>resource == null</code>, and <code>resource.data.value</code> all DENY. The simulator previously constructed <code>{ data: {} }</code> for missing get/update/delete requests, so the ordinary <code>resource != null</code> existence guard false-ALLOWed all three operations. Modeling the target as raw null fixes that guard but makes <code>resource == null</code> false-ALLOW, so the evaluator now raises <code>Null value error.</code> when the absent <code>resource</code> identifier itself is evaluated. Existing-document get/update/delete and data-access controls still ALLOW. <code>oracle:rules-firestore-resource-missing-document</code> — replayed by <code>packages/pyric/test/rules/oracle-conformance.test.ts</code>.</div></div>
|
|
118
|
+
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-12: production capture proves the simulator matches the Firestore Rules Test API verdict-for-verdict on all 9 cases. A missing request target makes the <code>resource</code> global an error value: <code>resource != null</code>, <code>resource == null</code>, and <code>resource.data.value</code> all DENY. The simulator previously constructed <code>{ data: {} }</code> for missing get/update/delete requests, so the ordinary <code>resource != null</code> existence guard false-ALLOWed all three operations. Modeling the target as raw null fixes that guard but makes <code>resource == null</code> false-ALLOW, so the evaluator now raises <code>Null value error.</code> when the absent <code>resource</code> identifier itself is evaluated. Existing-document get/update/delete and data-access controls still ALLOW. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-resource-missing-document.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-resource-missing-document</code></a> — replayed by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>packages/pyric/test/rules/oracle-conformance.test.ts</code></a>.</div></div>
|
|
119
119
|
</details>
|
|
120
120
|
<details class="compat-row" data-status="ok">
|
|
121
121
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior">A ruleset with NO <code>rules_version</code> declaration — production accepts it and defaults to v1</span></span></span></summary>
|
|
122
|
-
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-17: production capture proves a version-less ruleset deploys and evaluates (production defaults <code>rules_version</code> to v1; the shared grammar previously rejected the file at parse — PR #333 grammar fix, the same evidence that reclassified corpus file 001-missing-version.rules from invalid to edge-cases). <code>oracle:rules-firestore-optional-rules-version</code> matches the local simulator verdict-for-verdict on all 3 cases
|
|
122
|
+
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-17: production capture proves a version-less ruleset deploys and evaluates (production defaults <code>rules_version</code> to v1; the shared grammar previously rejected the file at parse — PR #333 grammar fix, the same evidence that reclassified corpus file 001-missing-version.rules from invalid to edge-cases). <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-optional-rules-version.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-optional-rules-version</code></a> matches the local simulator verdict-for-verdict on all 3 cases. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>oracle-conformance.test.ts</code></a>)</div></div>
|
|
123
123
|
</details>
|
|
124
124
|
<details class="compat-row" data-status="ok">
|
|
125
125
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior">Function declarations at GLOBAL and SERVICE scope in a Firestore ruleset, with match-scope shadowing</span></span></span></summary>
|
|
126
|
-
<div class="compat-evidence"><div class="compat-probe">ROW CORRECTED, 2026-07-17 (same day): the simulator now seeds the match-tree walk with global- and service-scope function declarations (declaration order global → service → match preserves inner-shadows-outer), so the previously-abstaining cases evaluate. <code>oracle:rules-firestore-global-and-service-scope-functions</code> — production Firestore Rules Test API verdicts captured 2026-07-17 — now replays verdict-for-verdict against the local simulator with all 5 cases matching (shadowing included), asserted by <code>unit:rules/oracle-conformance.test.ts</code>. The prior unsupported row recorded the honest UNSUPPORTED abstention; that gap is closed (#346).</div></div>
|
|
126
|
+
<div class="compat-evidence"><div class="compat-probe">ROW CORRECTED, 2026-07-17 (same day): the simulator now seeds the match-tree walk with global- and service-scope function declarations (declaration order global → service → match preserves inner-shadows-outer), so the previously-abstaining cases evaluate. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-global-and-service-scope-functions.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-global-and-service-scope-functions</code></a> — production Firestore Rules Test API verdicts captured 2026-07-17 — now replays verdict-for-verdict against the local simulator with all 5 cases matching (shadowing included), asserted by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>unit:rules/oracle-conformance.test.ts</code></a>. The prior unsupported row recorded the honest UNSUPPORTED abstention; that gap is closed (#346).</div></div>
|
|
127
127
|
</details>
|
|
128
128
|
<details class="compat-row" data-status="ok">
|
|
129
129
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior">Hierarchical nested <code>match</code> composition — a child match resolves relative to its parent and grants only the exact nested document path</span></span></span></summary>
|
|
130
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-firestore-hierarchical-match-cascade</code> captures the exact nested child ALLOW plus parent, sibling, and over-deep DENY controls from the production Firestore Rules Test API, replayed verdict-for-verdict by <code>packages/pyric/test/rules/oracle-conformance.test.ts</code>.</div></div>
|
|
130
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-hierarchical-match-cascade.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-hierarchical-match-cascade</code></a> captures the exact nested child ALLOW plus parent, sibling, and over-deep DENY controls from the production Firestore Rules Test API, replayed verdict-for-verdict by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>packages/pyric/test/rules/oracle-conformance.test.ts</code></a>.</div></div>
|
|
131
131
|
</details>
|
|
132
132
|
<details class="compat-row" data-status="ok">
|
|
133
133
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior">Strict boolean operands for <code>&&</code>, <code>||</code>, and ternary control flow, plus create-time <code>resource</code> / <code>request.resource</code> semantics</span></span></span></summary>
|
|
134
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-firestore-strict-boolean-control-flow</code> captures three direct non-boolean DENYs, three tautological error discriminators that still DENY, a boolean ALLOW control, create-time <code>resource == null</code> DENY, and incoming <code>request.resource.data</code> ALLOW; replayed verdict-for-verdict by <code>packages/pyric/test/rules/oracle-conformance.test.ts</code>.</div></div>
|
|
134
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-strict-boolean-control-flow.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-strict-boolean-control-flow</code></a> captures three direct non-boolean DENYs, three tautological error discriminators that still DENY, a boolean ALLOW control, create-time <code>resource == null</code> DENY, and incoming <code>request.resource.data</code> ALLOW; replayed verdict-for-verdict by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>packages/pyric/test/rules/oracle-conformance.test.ts</code></a>.</div></div>
|
|
135
135
|
</details>
|
|
136
136
|
<details class="compat-row" data-status="ok">
|
|
137
137
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior">The exact six shared <code>auth</code> and <code>membership</code> function bodies preserve signed-in, owner, custom-claim, explicit membership-map, and role semantics under Firestore Rules</span></span></span></summary>
|
|
138
|
-
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-21: one bounded, read-only Firestore Rules Test API request captured 12 verdicts for the exact bodies shipped from <code>auth</code> and <code>membership</code>; <code>oracle:rules-firestore-common-auth-membership-firestore</code> matches the local Firestore rules simulator verdict-for-verdict (6 ALLOW, 6 DENY). The cross-service source-lock test requires these six Firestore corpus bodies, the previously captured Storage corpus bodies, and the shipped modules to remain normalized-AST-identical
|
|
138
|
+
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-21: one bounded, read-only Firestore Rules Test API request captured 12 verdicts for the exact bodies shipped from <code>auth</code> and <code>membership</code>; <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-common-auth-membership-firestore.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-firestore-common-auth-membership-firestore</code></a> matches the local Firestore rules simulator verdict-for-verdict (6 ALLOW, 6 DENY). The cross-service source-lock test requires these six Firestore corpus bodies, the previously captured Storage corpus bodies, and the shipped modules to remain normalized-AST-identical. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>oracle-conformance.test.ts</code></a>)</div></div>
|
|
139
|
+
</details>
|
|
140
|
+
<details class="compat-row" data-status="ok">
|
|
141
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior">In multi-document batched writes and transactions, getAfter() deep-merges incoming updates with pre-existing sibling document state, preserving unmodified fields; updates targeting non-existent siblings project to null so existsAfter() returns false.</span></span></span></summary>
|
|
142
|
+
<div class="compat-evidence"><div class="compat-probe">Captured production behavior via rules-firestore-atomic-batch-sibling-merge proves getAfter() evaluates against deep-merged sibling state during multi-document atomic updates. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-atomic-batch-sibling-merge.json" target="_blank" rel="noopener noreferrer"><code>rules-firestore-atomic-batch-sibling-merge</code></a>, <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L28" target="_blank" rel="noopener noreferrer"><code>oracle-conformance.test.ts</code></a>, <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/sandbox/firestore/simulator/get-after-batch.test.ts#L2" target="_blank" rel="noopener noreferrer"><code>get-after-batch.test.ts</code></a>)</div></div>
|
|
143
|
+
</details>
|
|
144
|
+
<details class="compat-row" data-status="ok">
|
|
145
|
+
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior">Compile-time AST verification rejects non-conforming casts (bool()), unsupported helper methods (debug(), math.isInfinite()), and bare Map membership assertions (map.hasAll/hasAny/hasOnly).</span></span></span></summary>
|
|
146
|
+
<div class="compat-evidence"><div class="compat-probe">Captured production behavior via rules-firestore-ast-strictness-and-unsupported-casts proves compile-time AST verification and execution rejection of bool(), math.isInfinite(), debug(), and bare Map membership assertions. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/firestore-rules/rules-firestore-ast-strictness-and-unsupported-casts.json" target="_blank" rel="noopener noreferrer"><code>rules-firestore-ast-strictness-and-unsupported-casts</code></a>, <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/oracle-conformance.test.ts#L55" target="_blank" rel="noopener noreferrer"><code>oracle-conformance.test.ts</code></a>, <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/linter/hallucinations.test.ts#L137" target="_blank" rel="noopener noreferrer"><code>hallucinations.test.ts</code></a>)</div></div>
|
|
139
147
|
</details>
|
|
140
148
|
</div>
|
|
141
149
|
|
|
@@ -144,131 +152,131 @@
|
|
|
144
152
|
<div class="compat-list">
|
|
145
153
|
<details class="compat-row" data-status="ok">
|
|
146
154
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior"><code>parseStorageRules(source)</code> returns an opaque handle</span></span></span></summary>
|
|
147
|
-
<div class="compat-evidence"><div class="compat-probe"><code>unit:storage/sandbox/rules.test.ts</code> ("parses the canonical session-archive ruleset")</div></div>
|
|
155
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/sandbox/rules.test.ts#L2" target="_blank" rel="noopener noreferrer"><code>unit:storage/sandbox/rules.test.ts</code></a> ("parses the canonical session-archive ruleset")</div></div>
|
|
148
156
|
</details>
|
|
149
157
|
<details class="compat-row" data-status="ok">
|
|
150
158
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior"><code>parseStorageRules</code> rejects non-<code>firebase.storage</code> service headers</span></span></span></summary>
|
|
151
|
-
<div class="compat-evidence"><div class="compat-probe"><code>unit:storage/sandbox/rules.test.ts</code> ("rejects unknown service header")</div></div>
|
|
159
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/sandbox/rules.test.ts#L2" target="_blank" rel="noopener noreferrer"><code>unit:storage/sandbox/rules.test.ts</code></a> ("rejects unknown service header")</div></div>
|
|
152
160
|
</details>
|
|
153
161
|
<details class="compat-row" data-status="ok">
|
|
154
162
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior"><code>evaluateStorageRules</code> supports granular verbs (<code>get</code>/<code>list</code>/<code>create</code>/<code>update</code>/<code>delete</code>) alongside <code>read</code>/<code>write</code> umbrella expansion, comma-separated verb lists, and per-verb default-deny</span></span></span></summary>
|
|
155
|
-
<div class="compat-evidence"><div class="compat-probe">STALE ROW, corrected 2026-07-10: production capture proves the evaluator already supports the full six-verb grant surface (umbrella read→{get,list}, write→{create,update,delete}, single granular grants, comma-separated grants, per-verb deny-by-default), matching production verdict-for-verdict on 12 of the scenario's 13 non-existence cases. <code>oracle:rules-storage-verbs-umbrella-granular</code> (all <code>read</code>/<code>write</code>/<code>get</code>/comma-verb cases). One related existence-semantics case in the same scenario diverges over-permissively and is carried by <code>#118 Rules</code> (the <code>resource == null</code> create-if-absent guard), not by this granular-verb row
|
|
163
|
+
<div class="compat-evidence"><div class="compat-probe">STALE ROW, corrected 2026-07-10: production capture proves the evaluator already supports the full six-verb grant surface (umbrella read→{get,list}, write→{create,update,delete}, single granular grants, comma-separated grants, per-verb deny-by-default), matching production verdict-for-verdict on 12 of the scenario's 13 non-existence cases. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/storage-rules/rules-storage-verbs-umbrella-granular.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-storage-verbs-umbrella-granular</code></a> (all <code>read</code>/<code>write</code>/<code>get</code>/comma-verb cases). One related existence-semantics case in the same scenario diverges over-permissively and is carried by <code>#118 Rules</code> (the <code>resource == null</code> create-if-absent guard), not by this granular-verb row. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/rules-oracle-conformance.test.ts#L6" target="_blank" rel="noopener noreferrer"><code>rules-oracle-conformance.test.ts</code></a>)</div></div>
|
|
156
164
|
</details>
|
|
157
165
|
<details class="compat-row" data-status="ok">
|
|
158
166
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior"><code>parseStorageRules</code> rejects unterminated string literals with <code>SyntaxError</code></span></span></span></summary>
|
|
159
|
-
<div class="compat-evidence"><div class="compat-probe"><code>unit:storage/sandbox/rules.test.ts</code> ("rejects unterminated strings")</div></div>
|
|
167
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/sandbox/rules.test.ts#L2" target="_blank" rel="noopener noreferrer"><code>unit:storage/sandbox/rules.test.ts</code></a> ("rejects unterminated strings")</div></div>
|
|
160
168
|
</details>
|
|
161
169
|
<details class="compat-row" data-status="ok">
|
|
162
170
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior"><code>evaluateStorageRules</code> matches <code>match /sessions/{id} { allow read: if request.auth != null; }</code> for an authed read</span></span></span></summary>
|
|
163
|
-
<div class="compat-evidence"><div class="compat-probe"><code>unit:storage/sandbox/rules-evaluator.test.ts</code> ("allows authenticated reads of /sessions/{id}")</div></div>
|
|
171
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/sandbox/rules-evaluator.test.ts#L3" target="_blank" rel="noopener noreferrer"><code>unit:storage/sandbox/rules-evaluator.test.ts</code></a> ("allows authenticated reads of /sessions/{id}")</div></div>
|
|
164
172
|
</details>
|
|
165
173
|
<details class="compat-row" data-status="ok">
|
|
166
174
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior"><code>evaluateStorageRules</code> denies anonymous reads when the rule requires <code>request.auth != null</code></span></span></span></summary>
|
|
167
|
-
<div class="compat-evidence"><div class="compat-probe"><code>unit:storage/sandbox/rules-evaluator.test.ts</code> ("denies anonymous reads")</div></div>
|
|
175
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/sandbox/rules-evaluator.test.ts#L3" target="_blank" rel="noopener noreferrer"><code>unit:storage/sandbox/rules-evaluator.test.ts</code></a> ("denies anonymous reads")</div></div>
|
|
168
176
|
</details>
|
|
169
177
|
<details class="compat-row" data-status="ok">
|
|
170
178
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior"><code>evaluateStorageRules</code> supports <code>request.resource.size < N</code> constraints (with arithmetic literals like <code>10 <em> 1024 </em> 1024</code>)</span></span></span></summary>
|
|
171
|
-
<div class="compat-evidence"><div class="compat-probe"><code>unit:storage/sandbox/rules-evaluator.test.ts</code> ("allows JSON writes under 10MB")</div></div>
|
|
179
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/sandbox/rules-evaluator.test.ts#L3" target="_blank" rel="noopener noreferrer"><code>unit:storage/sandbox/rules-evaluator.test.ts</code></a> ("allows JSON writes under 10MB")</div></div>
|
|
172
180
|
</details>
|
|
173
181
|
<details class="compat-row" data-status="ok">
|
|
174
182
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior"><code>evaluateStorageRules</code> supports <code>request.resource.contentType == '<mime>'</code> constraints</span></span></span></summary>
|
|
175
|
-
<div class="compat-evidence"><div class="compat-probe"><code>unit:storage/sandbox/rules-evaluator.test.ts</code> (mime constraint inside the session-archive ruleset)</div></div>
|
|
183
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/sandbox/rules-evaluator.test.ts#L3" target="_blank" rel="noopener noreferrer"><code>unit:storage/sandbox/rules-evaluator.test.ts</code></a> (mime constraint inside the session-archive ruleset)</div></div>
|
|
176
184
|
</details>
|
|
177
185
|
<details class="compat-row" data-status="ok">
|
|
178
186
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior">Multi-segment wildcard <code>{allPaths=**}</code> matches zero-or-more remaining segments</span></span></span></summary>
|
|
179
|
-
<div class="compat-evidence"><div class="compat-probe"><code>unit:storage/sandbox/rules-evaluator.test.ts</code> (parser + evaluator both honor the <code>**</code> form)</div></div>
|
|
187
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/sandbox/rules-evaluator.test.ts#L2" target="_blank" rel="noopener noreferrer"><code>unit:storage/sandbox/rules-evaluator.test.ts</code></a> (parser + evaluator both honor the <code>**</code> form)</div></div>
|
|
180
188
|
</details>
|
|
181
189
|
<details class="compat-row" data-status="ok">
|
|
182
190
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior">Path-parameter binding (<code>{sessionId}</code>) accessible inside the <code>if</code> expression</span></span></span></summary>
|
|
183
|
-
<div class="compat-evidence"><div class="compat-probe"><code>unit:storage/sandbox/rules-evaluator.test.ts</code></div></div>
|
|
191
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/sandbox/rules-evaluator.test.ts#L2" target="_blank" rel="noopener noreferrer"><code>unit:storage/sandbox/rules-evaluator.test.ts</code></a></div></div>
|
|
184
192
|
</details>
|
|
185
193
|
<details class="compat-row" data-status="ok">
|
|
186
194
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior">User-defined <code>function</code> definitions — <code>let</code> bindings, functions calling functions, and match-block-scoped helper functions (lexical scoping)</span></span></span></summary>
|
|
187
|
-
<div class="compat-evidence"><div class="compat-probe">STALE ROW, corrected 2026-07-10: production capture proves the evaluator supports user-defined functions with <code>let</code> bindings, nested function calls, and block-scoped helpers. <code>oracle:rules-storage-functions-let-scope</code> matches production verdict-for-verdict on all 5 cases. Same-name shadowing and undefined-function calls are compile-time rejections in production and are covered by evaluator unit tests instead (they cannot be captured as a clean production verdict)
|
|
195
|
+
<div class="compat-evidence"><div class="compat-probe">STALE ROW, corrected 2026-07-10: production capture proves the evaluator supports user-defined functions with <code>let</code> bindings, nested function calls, and block-scoped helpers. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/storage-rules/rules-storage-functions-let-scope.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-storage-functions-let-scope</code></a> matches production verdict-for-verdict on all 5 cases. Same-name shadowing and undefined-function calls are compile-time rejections in production and are covered by evaluator unit tests instead (they cannot be captured as a clean production verdict). (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/rules-oracle-conformance.test.ts#L15" target="_blank" rel="noopener noreferrer"><code>rules-oracle-conformance.test.ts</code></a>)</div></div>
|
|
188
196
|
</details>
|
|
189
197
|
<details class="compat-row" data-status="ok">
|
|
190
198
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior"><code>request.time</code> compared against <code>timestamp.date(y,m,d)</code> and <code>timestamp.value(ms)</code> constructors</span></span></span></summary>
|
|
191
|
-
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-10: production capture proves the evaluator supports <code>request.time</code> comparisons against both timestamp constructors. <code>oracle:rules-storage-request-time-timestamp</code> matches production verdict-for-verdict on all 4 cases (deadline-before/after via <code>timestamp.date()</code>, epoch-bound before/after via <code>timestamp.value()</code>)
|
|
199
|
+
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-10: production capture proves the evaluator supports <code>request.time</code> comparisons against both timestamp constructors. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/storage-rules/rules-storage-request-time-timestamp.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-storage-request-time-timestamp</code></a> matches production verdict-for-verdict on all 4 cases (deadline-before/after via <code>timestamp.date()</code>, epoch-bound before/after via <code>timestamp.value()</code>). (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/rules-oracle-conformance.test.ts#L6" target="_blank" rel="noopener noreferrer"><code>rules-oracle-conformance.test.ts</code></a>)</div></div>
|
|
192
200
|
</details>
|
|
193
201
|
<details class="compat-row" data-status="ok">
|
|
194
202
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior"><code>string.matches(regex)</code> with whole-string anchoring (a partial match denies)</span></span></span></summary>
|
|
195
|
-
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-10: production capture proves <code>matches()</code> is whole-string anchored, matching a RE2 pattern only when it covers the entire string. <code>oracle:rules-storage-matches-regex</code> matches production verdict-for-verdict on all 3 cases. RE2-inexpressible patterns are rejected at ruleset compile time by production and are covered by evaluator unit tests instead
|
|
203
|
+
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-10: production capture proves <code>matches()</code> is whole-string anchored, matching a RE2 pattern only when it covers the entire string. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/storage-rules/rules-storage-matches-regex.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-storage-matches-regex</code></a> matches production verdict-for-verdict on all 3 cases. RE2-inexpressible patterns are rejected at ruleset compile time by production and are covered by evaluator unit tests instead. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/rules-oracle-conformance.test.ts#L194" target="_blank" rel="noopener noreferrer"><code>rules-oracle-conformance.test.ts</code></a>)</div></div>
|
|
196
204
|
</details>
|
|
197
205
|
<details class="compat-row" data-status="ok">
|
|
198
206
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior"><code>resource.metadata.<key></code> custom-metadata access in dotted (<code>resource.metadata.owner</code>) and bracket (<code>resource.metadata['owner']</code>) form, including missing-key deny</span></span></span></summary>
|
|
199
|
-
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-10: production capture proves dotted and bracket metadata access resolve identically, and a missing key denies. <code>oracle:rules-storage-metadata-access</code> matches production verdict-for-verdict on all 5 cases
|
|
207
|
+
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-10: production capture proves dotted and bracket metadata access resolve identically, and a missing key denies. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/storage-rules/rules-storage-metadata-access.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-storage-metadata-access</code></a> matches production verdict-for-verdict on all 5 cases. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/rules-oracle-conformance.test.ts#L131" target="_blank" rel="noopener noreferrer"><code>rules-oracle-conformance.test.ts</code></a>)</div></div>
|
|
200
208
|
</details>
|
|
201
209
|
<details class="compat-row" data-status="ok">
|
|
202
210
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior">Cross-service <code>firestore.get()</code> / <code>firestore.exists()</code> lookups from a Storage ruleset, with <code>$(expr)</code> path interpolation and qualified function-mock names</span></span></span></summary>
|
|
203
|
-
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-10: production capture proves the evaluator resolves cross-service Firestore lookups from Storage rules, including interpolated document paths and both the map-returning <code>get()</code> and bool-returning <code>exists()</code> forms. <code>oracle:rules-storage-firestore-lookup</code> matches production verdict-for-verdict on all 4 cases
|
|
211
|
+
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-10: production capture proves the evaluator resolves cross-service Firestore lookups from Storage rules, including interpolated document paths and both the map-returning <code>get()</code> and bool-returning <code>exists()</code> forms. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/storage-rules/rules-storage-firestore-lookup.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-storage-firestore-lookup</code></a> matches production verdict-for-verdict on all 4 cases. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/rules-oracle-conformance.test.ts#L71" target="_blank" rel="noopener noreferrer"><code>rules-oracle-conformance.test.ts</code></a>)</div></div>
|
|
204
212
|
</details>
|
|
205
213
|
<details class="compat-row" data-status="ok">
|
|
206
214
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior"><code>resource.name</code> (full object path), <code>resource.timeCreated</code>, <code>resource.updated</code>, <code>resource.bucket</code> — the object-identity and time fields of the existing-object binding, plus <code>duration.value(n, unit)</code></span></span></span></summary>
|
|
207
|
-
<div class="compat-evidence"><div class="compat-probe">ROW CORRECTED, 2026-07-12: the fields are now modeled, sourced from the persisted object record. <code>oracle:rules-storage-resource-object-identity</code> matches production verdict-for-verdict on all 9 cases — an extension guard (<code>resource.name.matches</code>), a freshness window (<code>resource.timeCreated + duration.value(1, 'h')</code>), an immutability check (<code>resource.timeCreated == resource.updated</code>), and an absent-property negation. Production semantics pinned by the capture: <code>resource.name</code> is the object's FULL path within the bucket (GCS object-name convention, sourced from the persisted record's <code>fullPath</code>, not the client SDK's last-segment <code>name</code>); <code>timeCreated</code>/<code>updated</code> are timestamps (production rejects an int with "Unsupported operation error. Received: int < timestamp"); the update-time field is <code>updated</code> — there is NO <code>resource.timeUpdated</code>. An absent property is an evaluation error that absorbs to DENY and SURVIVES negation, so <code>resource.name != 'x'</code> on an object with no name denies rather than false-allowing. The prior row recorded these fields as an unsupported gap; that gap is closed
|
|
215
|
+
<div class="compat-evidence"><div class="compat-probe">ROW CORRECTED, 2026-07-12: the fields are now modeled, sourced from the persisted object record. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/storage-rules/rules-storage-resource-object-identity.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-storage-resource-object-identity</code></a> matches production verdict-for-verdict on all 9 cases — an extension guard (<code>resource.name.matches</code>), a freshness window (<code>resource.timeCreated + duration.value(1, 'h')</code>), an immutability check (<code>resource.timeCreated == resource.updated</code>), and an absent-property negation. Production semantics pinned by the capture: <code>resource.name</code> is the object's FULL path within the bucket (GCS object-name convention, sourced from the persisted record's <code>fullPath</code>, not the client SDK's last-segment <code>name</code>); <code>timeCreated</code>/<code>updated</code> are timestamps (production rejects an int with "Unsupported operation error. Received: int < timestamp"); the update-time field is <code>updated</code> — there is NO <code>resource.timeUpdated</code>. An absent property is an evaluation error that absorbs to DENY and SURVIVES negation, so <code>resource.name != 'x'</code> on an object with no name denies rather than false-allowing. The prior row recorded these fields as an unsupported gap; that gap is closed. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/rules-oracle-conformance.test.ts#L6" target="_blank" rel="noopener noreferrer"><code>rules-oracle-conformance.test.ts</code></a>)</div></div>
|
|
208
216
|
</details>
|
|
209
217
|
<details class="compat-row" data-status="ok">
|
|
210
218
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior"><code>request.resource.size</code> arithmetic bounds (<code>+</code>/<code>-</code>/<code><em></code>/<code>/</code>, <code>>=</code>/<code><=</code>), request/existing content-type and custom <code>metadata</code> checks, <code>request.method</code>/<code>request.path</code>, a <code>request.auth.token</code> custom-claim branch, granular <code>allow list</code>, and a recursive <code>{allPaths=</em>*}</code> public read tree</span></span></span></summary>
|
|
211
|
-
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-12: production capture proves the evaluator matches the production Storage Rules Test API verdict-for-verdict on all 8 cases (owner-scoped size-bounded upload, immutable-content-type update, list grant, public recursive read). <code>oracle:rules-storage-metadata-verbs-and-arithmetic</code> — replayed by <code>packages/pyric/test/storage/rules-oracle-conformance.test.ts</code>.</div></div>
|
|
219
|
+
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-12: production capture proves the evaluator matches the production Storage Rules Test API verdict-for-verdict on all 8 cases (owner-scoped size-bounded upload, immutable-content-type update, list grant, public recursive read). <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/storage-rules/rules-storage-metadata-verbs-and-arithmetic.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-storage-metadata-verbs-and-arithmetic</code></a> — replayed by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/rules-oracle-conformance.test.ts#L75" target="_blank" rel="noopener noreferrer"><code>packages/pyric/test/storage/rules-oracle-conformance.test.ts</code></a>.</div></div>
|
|
212
220
|
</details>
|
|
213
221
|
<details class="compat-row" data-status="ok">
|
|
214
222
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior"><code>resource</code> on a create where no object exists: the create-if-absent guard <code>allow create: if resource == null</code></span></span></span></summary>
|
|
215
|
-
<div class="compat-evidence"><div class="compat-probe">GAP CLOSED, 2026-07-21: production raises a null-value error when <code>resource</code> is referenced on a create where no object exists, including <code>resource == null</code>, so the expression denies. The evaluator now represents the missing binding as a Rules error rather than a usable null. <code>oracle:rules-storage-verbs-umbrella-granular</code> replays the captured DENY directly with no divergence pin; <code>unit:storage/sandbox/rules-evaluator.test.ts</code> covers the evaluator seam
|
|
223
|
+
<div class="compat-evidence"><div class="compat-probe">GAP CLOSED, 2026-07-21: production raises a null-value error when <code>resource</code> is referenced on a create where no object exists, including <code>resource == null</code>, so the expression denies. The evaluator now represents the missing binding as a Rules error rather than a usable null. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/storage-rules/rules-storage-verbs-umbrella-granular.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-storage-verbs-umbrella-granular</code></a> replays the captured DENY directly with no divergence pin; <code>unit:storage/sandbox/rules-evaluator.test.ts</code> covers the evaluator seam. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/rules-oracle-conformance.test.ts#L6" target="_blank" rel="noopener noreferrer"><code>rules-oracle-conformance.test.ts</code></a>)</div></div>
|
|
216
224
|
</details>
|
|
217
225
|
<details class="compat-row" data-status="ok">
|
|
218
226
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior">Ternary <code>?:</code> — branch selection, error-in-condition deny, and <code>error || true</code> absorption</span></span></span></summary>
|
|
219
|
-
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-17: production capture proves the evaluator selects ternary branches by condition, denies when the CONDITION errors (even with identical <code>true</code> branches — production errors the whole conditional rather than falling through to a branch), and still absorbs the same error through <code>|| true</code>. <code>oracle:rules-storage-ternary-and-error-absorption</code> matches production verdict-for-verdict on all 5 cases. A division-by-zero in the condition previously yielded JS Infinity (no error) and false-ALLOWed the erroring-condition case; zero divisors now error-and-deny
|
|
227
|
+
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-17: production capture proves the evaluator selects ternary branches by condition, denies when the CONDITION errors (even with identical <code>true</code> branches — production errors the whole conditional rather than falling through to a branch), and still absorbs the same error through <code>|| true</code>. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/storage-rules/rules-storage-ternary-and-error-absorption.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-storage-ternary-and-error-absorption</code></a> matches production verdict-for-verdict on all 5 cases. A division-by-zero in the condition previously yielded JS Infinity (no error) and false-ALLOWed the erroring-condition case; zero divisors now error-and-deny. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/rules-oracle-conformance.test.ts#L6" target="_blank" rel="noopener noreferrer"><code>rules-oracle-conformance.test.ts</code></a>)</div></div>
|
|
220
228
|
</details>
|
|
221
229
|
<details class="compat-row" data-status="ok">
|
|
222
230
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior"><code>in</code> on list literals (membership) and on maps (OWN-key membership) — prototype names (<code>toString</code>/<code>constructor</code>/<code>hasOwnProperty</code>) are never keys</span></span></span></summary>
|
|
223
|
-
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-17: production capture proves <code>in</code> tests list membership and map OWN keys only — <code>'toString' in metadata</code> is false unless the map literally carries that key, for both custom-metadata maps and map literals. <code>oracle:rules-storage-in-membership-and-proto-keys</code> matches production verdict-for-verdict on all 8 cases. Pre-fix the evaluator used JS <code>in</code>, which walks the prototype chain and false-ALLOWed the proto-key cases (the same bug class the Firestore simulator fixed under RULES-B7); the own-key check now guards it, pinned by <code>unit:storage/sandbox/rules-values.test.ts</code> JS-semantics guards
|
|
231
|
+
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-17: production capture proves <code>in</code> tests list membership and map OWN keys only — <code>'toString' in metadata</code> is false unless the map literally carries that key, for both custom-metadata maps and map literals. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/storage-rules/rules-storage-in-membership-and-proto-keys.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-storage-in-membership-and-proto-keys</code></a> matches production verdict-for-verdict on all 8 cases. Pre-fix the evaluator used JS <code>in</code>, which walks the prototype chain and false-ALLOWed the proto-key cases (the same bug class the Firestore simulator fixed under RULES-B7); the own-key check now guards it, pinned by <code>unit:storage/sandbox/rules-values.test.ts</code> JS-semantics guards. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/rules-oracle-conformance.test.ts#L6" target="_blank" rel="noopener noreferrer"><code>rules-oracle-conformance.test.ts</code></a>)</div></div>
|
|
224
232
|
</details>
|
|
225
233
|
<details class="compat-row" data-status="ok">
|
|
226
234
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior"><code>is</code> type tests over the storage bindings (<code>size is int</code>, <code>contentType is string</code>, <code>metadata is map</code>, <code>split() is list</code>) and int/float LITERAL typing (<code>1.0 is float</code>, <code>1 is int</code>, cross checks false)</span></span></span></summary>
|
|
227
|
-
<div class="compat-evidence"><div class="compat-probe">ROW CORRECTED, 2026-07-17 (same day): the evaluator now adopts the simulator's RULES-B5 float model — a <code>RulesFloat</code> wrapper tags float values (a numeric literal written with a decimal point converts to one) while a bare JS number means int — so <code>1.0 is float</code> / <code>!(1.0 is int)</code> type by literal form exactly as production does. <code>oracle:rules-storage-type-checks-is</code> now matches production verdict-for-verdict on all 3 cases with no knownGap abstentions. The prior same-day row recorded the value-typed divergence; that gap is closed
|
|
235
|
+
<div class="compat-evidence"><div class="compat-probe">ROW CORRECTED, 2026-07-17 (same day): the evaluator now adopts the simulator's RULES-B5 float model — a <code>RulesFloat</code> wrapper tags float values (a numeric literal written with a decimal point converts to one) while a bare JS number means int — so <code>1.0 is float</code> / <code>!(1.0 is int)</code> type by literal form exactly as production does. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/storage-rules/rules-storage-type-checks-is.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-storage-type-checks-is</code></a> now matches production verdict-for-verdict on all 3 cases with no knownGap abstentions. The prior same-day row recorded the value-typed divergence; that gap is closed. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/rules-oracle-conformance.test.ts#L6" target="_blank" rel="noopener noreferrer"><code>rules-oracle-conformance.test.ts</code></a>)</div></div>
|
|
228
236
|
</details>
|
|
229
237
|
<details class="compat-row" data-status="ok">
|
|
230
238
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior">List/map literals, range-slice access <code>[i:j]</code> on lists and strings (out-of-range bounds ERROR, no JS clamp), and structural <code>==</code> on lists</span></span></span></summary>
|
|
231
|
-
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-17: production capture proves slices evaluate on <code>split()</code> lists and on strings, that an out-of-range slice END errors and denies (production does NOT clamp to length the way JS <code>.slice()</code> does — same semantics the Firestore capture pinned in rules-firestore-range-slice-list-and-string), and that a slice compares equal to a list literal structurally. <code>oracle:rules-storage-list-map-literals-and-slice</code> matches production verdict-for-verdict on all 6 cases. Pre-fix the evaluator clamped bounds JS-style and compared lists by reference identity; both fixed and pinned by <code>unit:storage/sandbox/rules-values.test.ts</code> JS-semantics guards
|
|
239
|
+
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-17: production capture proves slices evaluate on <code>split()</code> lists and on strings, that an out-of-range slice END errors and denies (production does NOT clamp to length the way JS <code>.slice()</code> does — same semantics the Firestore capture pinned in rules-firestore-range-slice-list-and-string), and that a slice compares equal to a list literal structurally. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/storage-rules/rules-storage-list-map-literals-and-slice.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-storage-list-map-literals-and-slice</code></a> matches production verdict-for-verdict on all 6 cases. Pre-fix the evaluator clamped bounds JS-style and compared lists by reference identity; both fixed and pinned by <code>unit:storage/sandbox/rules-values.test.ts</code> JS-semantics guards. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/rules-oracle-conformance.test.ts#L6" target="_blank" rel="noopener noreferrer"><code>rules-oracle-conformance.test.ts</code></a>)</div></div>
|
|
232
240
|
</details>
|
|
233
241
|
<details class="compat-row" data-status="ok">
|
|
234
242
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior">Float literals, <code>%</code>, unary minus, float division, negative-dividend modulo (<code>-7 % 2 == -1</code>), and TRUNCATING int division (<code>10 / 4 == 2</code>, <code>-7 / 2 == -3</code>)</span></span></span></summary>
|
|
235
|
-
<div class="compat-evidence"><div class="compat-probe">ROW CORRECTED, 2026-07-17 (same day): with the RULES-B5 float model adopted from the simulator, int ÷ int truncates toward zero, float division stays float (re-tagged), and int-op-float promotes to float. <code>oracle:rules-storage-float-modulo-unary-minus</code> now matches production verdict-for-verdict on all 6 cases with no knownGap abstentions. An int zero divisor errors-and-denies; a float zero divisor follows the simulator's CEL-pinned ±Infinity/NaN. The prior same-day row recorded the truncation divergence; that gap is closed
|
|
243
|
+
<div class="compat-evidence"><div class="compat-probe">ROW CORRECTED, 2026-07-17 (same day): with the RULES-B5 float model adopted from the simulator, int ÷ int truncates toward zero, float division stays float (re-tagged), and int-op-float promotes to float. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/storage-rules/rules-storage-float-modulo-unary-minus.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-storage-float-modulo-unary-minus</code></a> now matches production verdict-for-verdict on all 6 cases with no knownGap abstentions. An int zero divisor errors-and-denies; a float zero divisor follows the simulator's CEL-pinned ±Infinity/NaN. The prior same-day row recorded the truncation divergence; that gap is closed. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/rules-oracle-conformance.test.ts#L6" target="_blank" rel="noopener noreferrer"><code>rules-oracle-conformance.test.ts</code></a>)</div></div>
|
|
236
244
|
</details>
|
|
237
245
|
<details class="compat-row" data-status="ok">
|
|
238
246
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior">Function declarations at GLOBAL scope (above <code>service</code>) and SERVICE scope (inside <code>service</code>, outside any match), with inner-shadows-outer resolution</span></span></span></summary>
|
|
239
|
-
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-17: production capture proves production accepts functions declared at global and service scope and resolves a match-scope function over a same-named global (inner shadows outer). <code>oracle:rules-storage-function-scopes-and-shadowing</code> matches production verdict-for-verdict on all 5 cases. The shared grammar previously rejected both placements at parse (PR #333 grammar fix); the storage evaluator attaches global- and service-scope functions to the root match block, which the capture proves is verdict-equivalent to production's scoping for this surface
|
|
247
|
+
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-17: production capture proves production accepts functions declared at global and service scope and resolves a match-scope function over a same-named global (inner shadows outer). <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/storage-rules/rules-storage-function-scopes-and-shadowing.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-storage-function-scopes-and-shadowing</code></a> matches production verdict-for-verdict on all 5 cases. The shared grammar previously rejected both placements at parse (PR #333 grammar fix); the storage evaluator attaches global- and service-scope functions to the root match block, which the capture proves is verdict-equivalent to production's scoping for this surface. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/rules-oracle-conformance.test.ts#L6" target="_blank" rel="noopener noreferrer"><code>rules-oracle-conformance.test.ts</code></a>)</div></div>
|
|
240
248
|
</details>
|
|
241
249
|
<details class="compat-row" data-status="ok">
|
|
242
250
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior"><code>2+modules</code> Storage rules resolve through service-aware contracts: the common <code>auth</code> and <code>membership</code> exports are admitted and retain their production auth, claim, map-membership, and role semantics; Firestore-only helpers are rejected before evaluation</span></span></span></summary>
|
|
243
|
-
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-20; paired proof added 2026-07-21: one targeted production Rules Test API capture proves the exact six bundled function bodies (<code>isAuthenticated</code>, <code>isOwner</code>, <code>hasClaim</code>, <code>hasClaimRole</code>, <code>isMemberOf</code>, <code>hasRole</code>) under <code>firebase.storage</code>, matching the local evaluator verdict-for-verdict on 12 allow/deny cases. <code>oracle:rules-storage-common-auth-membership</code> supplies the Storage answer key; Firestore Rules row #189 independently captures the same exact bodies under <code>cloud.firestore</code> (12 matching verdicts). A separately authored, explicitly reconstructed normalized-AST digest locks the captured Storage corpus bodies, and the source-lock test requires the Firestore corpus and shipped modules to remain AST-identical. Resolver tests separately prove <code>2+modules</code> lowers these imports to plain v2 and fails closed with <code>INCOMPATIBLE_FUNCTION</code> for a Firestore-only export and for a transitive helper that reads <code>resource.data</code>; the Storage service integration test proves normal setup invokes that checked resolver
|
|
251
|
+
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-20; paired proof added 2026-07-21: one targeted production Rules Test API capture proves the exact six bundled function bodies (<code>isAuthenticated</code>, <code>isOwner</code>, <code>hasClaim</code>, <code>hasClaimRole</code>, <code>isMemberOf</code>, <code>hasRole</code>) under <code>firebase.storage</code>, matching the local evaluator verdict-for-verdict on 12 allow/deny cases. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/storage-rules/rules-storage-common-auth-membership.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-storage-common-auth-membership</code></a> supplies the Storage answer key; Firestore Rules row #189 independently captures the same exact bodies under <code>cloud.firestore</code> (12 matching verdicts). A separately authored, explicitly reconstructed normalized-AST digest locks the captured Storage corpus bodies, and the source-lock test requires the Firestore corpus and shipped modules to remain AST-identical. Resolver tests separately prove <code>2+modules</code> lowers these imports to plain v2 and fails closed with <code>INCOMPATIBLE_FUNCTION</code> for a Firestore-only export and for a transitive helper that reads <code>resource.data</code>; the Storage service integration test proves normal setup invokes that checked resolver. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/test/src/storage-stdlib-source-lock.test.ts#L73" target="_blank" rel="noopener noreferrer"><code>storage-stdlib-source-lock.test.ts</code></a>, <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/rules-oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>rules-oracle-conformance.test.ts</code></a>, <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/modules/resolver.test.ts#L9" target="_blank" rel="noopener noreferrer"><code>resolver.test.ts</code></a>, <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/enforce.test.ts#L17" target="_blank" rel="noopener noreferrer"><code>enforce.test.ts</code></a>)</div></div>
|
|
244
252
|
</details>
|
|
245
253
|
<details class="compat-row" data-status="ok">
|
|
246
254
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior">Storage-native upload primitives at security boundaries: inclusive byte maximums, exact and whole-string MIME checks, metadata-only updates with unchanged bytes/owner, string path wildcards, generation/metageneration identity, and strict creation-time windows</span></span></span></summary>
|
|
247
|
-
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-20: <code>oracle:rules-storage-upload-primitives-boundaries</code> captures 26 production cases in one Rules Test API request. The local evaluator matches every case scoped to this row: size 0/exact/+1, MIME exact/case/parameter and regex anchoring, metadata update invariants, filename wildcard typing, exact/absent generation identity, and request.time just before/at/after a strict 60-second boundary plus a future timeCreated fixture. Metadata collection methods and missing request.resource are separated into divergence rows #127/#128 rather than contaminating this credit
|
|
255
|
+
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-20: <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/storage-rules/rules-storage-upload-primitives-boundaries.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-storage-upload-primitives-boundaries</code></a> captures 26 production cases in one Rules Test API request. The local evaluator matches every case scoped to this row: size 0/exact/+1, MIME exact/case/parameter and regex anchoring, metadata update invariants, filename wildcard typing, exact/absent generation identity, and request.time just before/at/after a strict 60-second boundary plus a future timeCreated fixture. Metadata collection methods and missing request.resource are separated into divergence rows #127/#128 rather than contaminating this credit. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/rules-oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>rules-oracle-conformance.test.ts</code></a>)</div></div>
|
|
248
256
|
</details>
|
|
249
257
|
<details class="compat-row" data-status="ok">
|
|
250
258
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior">Storage custom-metadata collection methods: <code>Map.keys().hasAll()</code> for required-key policy and <code>Map.get(key, default)</code> for an absent key</span></span></span></summary>
|
|
251
|
-
<div class="compat-evidence"><div class="compat-probe">GAP CLOSED, 2026-07-21: the Storage evaluator now implements own-key <code>Map.keys()</code>, structural <code>hasAll()</code>, and string-key <code>Map.get(key, default)</code>. <code>oracle:rules-storage-upload-primitives-boundaries</code> replays the production required-key and absent-key-default cases directly with no divergence pin; public-seam unit cases cover both admitted forms
|
|
259
|
+
<div class="compat-evidence"><div class="compat-probe">GAP CLOSED, 2026-07-21: the Storage evaluator now implements own-key <code>Map.keys()</code>, structural <code>hasAll()</code>, and string-key <code>Map.get(key, default)</code>. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/storage-rules/rules-storage-upload-primitives-boundaries.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-storage-upload-primitives-boundaries</code></a> replays the production required-key and absent-key-default cases directly with no divergence pin; public-seam unit cases cover both admitted forms. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/rules-oracle-conformance.test.ts#L6" target="_blank" rel="noopener noreferrer"><code>rules-oracle-conformance.test.ts</code></a>)</div></div>
|
|
252
260
|
</details>
|
|
253
261
|
<details class="compat-row" data-status="ok">
|
|
254
262
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior"><code>request.resource</code> on delete where no incoming object exists: <code>request.resource == null</code></span></span></span></summary>
|
|
255
|
-
<div class="compat-evidence"><div class="compat-probe">GAP CLOSED, 2026-07-21: production errors when <code>request.resource</code> is absent on delete, including a direct null comparison. The evaluator now carries the absent incoming binding as a Rules error. <code>oracle:rules-storage-upload-primitives-boundaries</code> replays the captured DENY directly with no divergence pin; <code>unit:storage/sandbox/rules-evaluator.test.ts</code> covers the evaluator seam
|
|
263
|
+
<div class="compat-evidence"><div class="compat-probe">GAP CLOSED, 2026-07-21: production errors when <code>request.resource</code> is absent on delete, including a direct null comparison. The evaluator now carries the absent incoming binding as a Rules error. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/storage-rules/rules-storage-upload-primitives-boundaries.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-storage-upload-primitives-boundaries</code></a> replays the captured DENY directly with no divergence pin; <code>unit:storage/sandbox/rules-evaluator.test.ts</code> covers the evaluator seam. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/rules-oracle-conformance.test.ts#L128" target="_blank" rel="noopener noreferrer"><code>rules-oracle-conformance.test.ts</code></a>)</div></div>
|
|
256
264
|
</details>
|
|
257
265
|
<details class="compat-row" data-status="diverged">
|
|
258
266
|
<summary class="compat-line"><span class="compat-dot" data-status="diverged" role="img" aria-label="Diverged (documented)" title="Diverged (documented)"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior">Mocked Storage-to-Firestore lookup evaluation: get/exists return and missing-field errors, repeated and same-resolved-path calls, get+exists composition, and lazy <code>||</code>/<code>&&</code>/ternary branches with hosted function-call diagnostics</span></span></span></summary>
|
|
259
|
-
<div class="compat-evidence"><div class="compat-probe">DOCUMENTED MOCK-ORACLE DIVERGENCE, 2026-07-21: <code>oracle:rules-storage-firestore-lookup-budget</code> matches the local evaluator on 13 of 14 cases and hosted diagnostics prove lazy branches omit lookup calls. The one mismatch is intentional and pinned on both sides: the Rules Test API ALLOWs three distinct mocked exists calls, while the evaluator DENYs the third distinct path to match the separately captured real-resource production contract in row #131. This row remains diverged because its mocked observation is not verdict-identical; it supplies no budget credit
|
|
267
|
+
<div class="compat-evidence"><div class="compat-probe">DOCUMENTED MOCK-ORACLE DIVERGENCE, 2026-07-21: <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/storage-rules/rules-storage-firestore-lookup-budget.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-storage-firestore-lookup-budget</code></a> matches the local evaluator on 13 of 14 cases and hosted diagnostics prove lazy branches omit lookup calls. The one mismatch is intentional and pinned on both sides: the Rules Test API ALLOWs three distinct mocked exists calls, while the evaluator DENYs the third distinct path to match the separately captured real-resource production contract in row #131. This row remains diverged because its mocked observation is not verdict-identical; it supplies no budget credit. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/rules-oracle-conformance.test.ts#L71" target="_blank" rel="noopener noreferrer"><code>rules-oracle-conformance.test.ts</code></a>)</div></div>
|
|
260
268
|
</details>
|
|
261
269
|
<details class="compat-row" data-status="ok">
|
|
262
270
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior">Anonymous <code>request.auth != null</code> used as a ternary condition before a cross-service lookup</span></span></span></summary>
|
|
263
|
-
<div class="compat-evidence"><div class="compat-probe">GAP CLOSED, 2026-07-21: anonymous <code>request.auth</code> is now represented as an absent-property Rules error, so a ternary condition denies before selecting either lookup branch, matching hosted diagnostics. <code>oracle:rules-storage-firestore-lookup-budget</code> replays the captured DENY directly with no divergence pin; <code>unit:storage/sandbox/rules-methods.test.ts</code> covers the lookup evaluator seam
|
|
271
|
+
<div class="compat-evidence"><div class="compat-probe">GAP CLOSED, 2026-07-21: anonymous <code>request.auth</code> is now represented as an absent-property Rules error, so a ternary condition denies before selecting either lookup branch, matching hosted diagnostics. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/storage-rules/rules-storage-firestore-lookup-budget.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-storage-firestore-lookup-budget</code></a> replays the captured DENY directly with no divergence pin; <code>unit:storage/sandbox/rules-methods.test.ts</code> covers the lookup evaluator seam. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/rules-oracle-conformance.test.ts#L71" target="_blank" rel="noopener noreferrer"><code>rules-oracle-conformance.test.ts</code></a>)</div></div>
|
|
264
272
|
</details>
|
|
265
273
|
<details class="compat-row" data-status="ok">
|
|
266
274
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior">Real-resource Storage-to-Firestore contract: at most two distinct document paths per evaluation with repeated-path caching; typed document data and missing-document errors; default-database-only and owning-project isolation; lazy/helper/let composition; and independence from Firestore client rules</span></span></span></summary>
|
|
267
|
-
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-21: four deploy-observe-restore captures establish the real-resource contract beyond Rules Test API mocks: <code>oracle:stdlib-realstorage-p3-lookup-budget-iam-enabled</code>, <code>oracle:stdlib-realstorage-p3-advanced-iam-enabled</code>, <code>oracle:stdlib-realstorage-p3-named-database</code>, and <code>oracle:stdlib-realstorage-p3-project-isolation</code>. <code>unit:conformance/storage-stdlib-real-replay.test.ts</code> executes the locally decidable lookup matrices and locks reviewed reconstructions of their normalized probe code; the lock records state whether the digest covers an injected block or a canonical synthetic wrapper. The surrounding deployed base rules were not retained, so no full-source digest is claimed for these historical captures. Future rigs emit both probe-block and full deployed-rules-file digests. <code>unit:storage/enforce.test.ts</code> proves the normal enforcement seam reads only its owning sandbox and bypasses Firestore client rules. The separate consistency capture remains bounded characterization and is not promoted into a latency guarantee.</div></div>
|
|
275
|
+
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-21: four deploy-observe-restore captures establish the real-resource contract beyond Rules Test API mocks: <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/storage-rules/stdlib-realstorage-p3-lookup-budget-iam-enabled.json" target="_blank" rel="noopener noreferrer"><code>oracle:stdlib-realstorage-p3-lookup-budget-iam-enabled</code></a>, <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/storage-rules/stdlib-realstorage-p3-advanced-iam-enabled.json" target="_blank" rel="noopener noreferrer"><code>oracle:stdlib-realstorage-p3-advanced-iam-enabled</code></a>, <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/storage-rules/stdlib-realstorage-p3-named-database.json" target="_blank" rel="noopener noreferrer"><code>oracle:stdlib-realstorage-p3-named-database</code></a>, and <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/storage-rules/stdlib-realstorage-p3-project-isolation.json" target="_blank" rel="noopener noreferrer"><code>oracle:stdlib-realstorage-p3-project-isolation</code></a>. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/test/src/storage-stdlib-real-replay.test.ts#L90" target="_blank" rel="noopener noreferrer"><code>unit:conformance/storage-stdlib-real-replay.test.ts</code></a> executes the locally decidable lookup matrices and locks reviewed reconstructions of their normalized probe code; the lock records state whether the digest covers an injected block or a canonical synthetic wrapper. The surrounding deployed base rules were not retained, so no full-source digest is claimed for these historical captures. Future rigs emit both probe-block and full deployed-rules-file digests. <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/enforce.test.ts#L368" target="_blank" rel="noopener noreferrer"><code>unit:storage/enforce.test.ts</code></a> proves the normal enforcement seam reads only its owning sandbox and bypasses Firestore client rules. The separate consistency capture remains bounded characterization and is not promoted into a latency guarantee.</div></div>
|
|
268
276
|
</details>
|
|
269
277
|
<details class="compat-row" data-status="ok">
|
|
270
278
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior">The service-scoped <code>storage/uploads</code>, <code>storage/metadata</code>, <code>storage/objects</code>, and <code>storage/time</code> modules resolve through <code>2+modules</code> and preserve their production upload-bound, MIME, metadata, operation-identity, and strict timestamp-window semantics</span></span></span></summary>
|
|
271
|
-
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-21: one bounded Rules Test API batch captures 15 verdicts for the exact 13 deployable function bodies in the four shipped modules (<code>oracle:rules-storage-stdlib-storage-modules</code>). A separately authored, explicitly reconstructed normalized-AST digest locks the captured corpus bodies, and the source-lock test requires the shipped modules to remain AST-identical. The generic Storage stdlib fixture runner and oracle replay execute those bodies locally; resolver tests prove the modules are admitted only for <code>firebase.storage</code>, lower to plain v2, and fail closed under Firestore. The module surface intentionally excludes the advanced integrity, metadata-diff, and cross-service lookup candidates
|
|
279
|
+
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-21: one bounded Rules Test API batch captures 15 verdicts for the exact 13 deployable function bodies in the four shipped modules (<a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/storage-rules/rules-storage-stdlib-storage-modules.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-storage-stdlib-storage-modules</code></a>). A separately authored, explicitly reconstructed normalized-AST digest locks the captured corpus bodies, and the source-lock test requires the shipped modules to remain AST-identical. The generic Storage stdlib fixture runner and oracle replay execute those bodies locally; resolver tests prove the modules are admitted only for <code>firebase.storage</code>, lower to plain v2, and fail closed under Firestore. The module surface intentionally excludes the advanced integrity, metadata-diff, and cross-service lookup candidates. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/test/src/storage-stdlib-source-lock.test.ts#L53" target="_blank" rel="noopener noreferrer"><code>storage-stdlib-source-lock.test.ts</code></a>, <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/rules-oracle-conformance.test.ts#L7" target="_blank" rel="noopener noreferrer"><code>rules-oracle-conformance.test.ts</code></a>, <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/stdlib-cases.test.ts#L5" target="_blank" rel="noopener noreferrer"><code>stdlib-cases.test.ts</code></a>, <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/stdlib.test.ts#L3" target="_blank" rel="noopener noreferrer"><code>stdlib.test.ts</code></a>)</div></div>
|
|
272
280
|
</details>
|
|
273
281
|
</div>
|
|
274
282
|
|
|
@@ -277,63 +285,63 @@
|
|
|
277
285
|
<div class="compat-list">
|
|
278
286
|
<details class="compat-row" data-status="ok">
|
|
279
287
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior"><code>auth != null</code> gate on <code>.read</code>/<code>.write</code> — authed ops allow, signed-out ops deny</span></span></span></summary>
|
|
280
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-rtdb-r1-auth-only</code> — production verdicts captured by deploy-observe-restore against the live oracle database (RTDB has no server-side rules test API), replayed verdict-for-verdict against the in-process simulator by <code>packages/pyric/test/rules/rtdb/rules-conformance.test.ts</code>; all 4 cases match production.</div></div>
|
|
288
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/rtdb-rules/rules-rtdb-r1-auth-only.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-rtdb-r1-auth-only</code></a> — production verdicts captured by deploy-observe-restore against the live oracle database (RTDB has no server-side rules test API), replayed verdict-for-verdict against the in-process simulator by <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/rtdb/rules-conformance.test.ts#L2" target="_blank" rel="noopener noreferrer"><code>packages/pyric/test/rules/rtdb/rules-conformance.test.ts</code></a>; all 4 cases match production.</div></div>
|
|
281
289
|
</details>
|
|
282
290
|
<details class="compat-row" data-status="ok">
|
|
283
291
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior"><code>$uid</code> path-variable ownership (<code>$uid === auth.uid</code>) — the owner path allows, a foreign uid and an anonymous request deny</span></span></span></summary>
|
|
284
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-rtdb-r2-own-uid</code> — production verdicts captured by deploy-observe-restore, replayed verdict-for-verdict against the in-process simulator; all 5 cases match production, so the simulator binds the path variable against <code>auth.uid</code> exactly as production does
|
|
292
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/rtdb-rules/rules-rtdb-r2-own-uid.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-rtdb-r2-own-uid</code></a> — production verdicts captured by deploy-observe-restore, replayed verdict-for-verdict against the in-process simulator; all 5 cases match production, so the simulator binds the path variable against <code>auth.uid</code> exactly as production does. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/rtdb/rules-conformance.test.ts#L2" target="_blank" rel="noopener noreferrer"><code>rules-conformance.test.ts</code></a>)</div></div>
|
|
285
293
|
</details>
|
|
286
294
|
<details class="compat-row" data-status="ok">
|
|
287
295
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior">Write-rule CASCADE — a truthy ancestor <code>.write</code> grants the write regardless of a deeper <code>!data.exists()</code> rule, so the populated-path write ALLOWS</span></span></span></summary>
|
|
288
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-rtdb-r3-data-exists</code> — production verdicts captured by deploy-observe-restore, replayed verdict-for-verdict. Production ALLOWS the write to the populated path even though the child rule is <code>!data.exists()</code>: the ancestor <code>.write: auth != null</code> already granted it, and RTDB never consults a deeper rule to revoke a grant. All 3 cases match; the simulator models the same cascade
|
|
296
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/rtdb-rules/rules-rtdb-r3-data-exists.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-rtdb-r3-data-exists</code></a> — production verdicts captured by deploy-observe-restore, replayed verdict-for-verdict. Production ALLOWS the write to the populated path even though the child rule is <code>!data.exists()</code>: the ancestor <code>.write: auth != null</code> already granted it, and RTDB never consults a deeper rule to revoke a grant. All 3 cases match; the simulator models the same cascade. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/rtdb/rules-conformance.test.ts#L2" target="_blank" rel="noopener noreferrer"><code>rules-conformance.test.ts</code></a>)</div></div>
|
|
289
297
|
</details>
|
|
290
298
|
<details class="compat-row" data-status="ok">
|
|
291
299
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior"><code>.validate</code> VETO — a failing child <code>.validate</code> denies a write the <code>.write</code> rule would otherwise permit (validate does not cascade and cannot be overridden)</span></span></span></summary>
|
|
292
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-rtdb-r4-validate-structure</code> — production verdicts captured by deploy-observe-restore, replayed verdict-for-verdict; both cases match production. This row was the corpus's one historical simulator-vs-production divergence: at the 2026-05-18 agreement capture the simulator ALLOWED the missing-body write because it did not veto on the child <code>.validate</code>. The simulator now denies it, and this fresh capture re-confirms production's DENY, so the divergence is RESOLVED and needs no pin
|
|
300
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/rtdb-rules/rules-rtdb-r4-validate-structure.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-rtdb-r4-validate-structure</code></a> — production verdicts captured by deploy-observe-restore, replayed verdict-for-verdict; both cases match production. This row was the corpus's one historical simulator-vs-production divergence: at the 2026-05-18 agreement capture the simulator ALLOWED the missing-body write because it did not veto on the child <code>.validate</code>. The simulator now denies it, and this fresh capture re-confirms production's DENY, so the divergence is RESOLVED and needs no pin. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/rtdb/rules-conformance.test.ts#L2" target="_blank" rel="noopener noreferrer"><code>rules-conformance.test.ts</code></a>)</div></div>
|
|
293
301
|
</details>
|
|
294
302
|
<details class="compat-row" data-status="ok">
|
|
295
303
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior">Cascade is GRANT-ONLY — a root <code>.read: true</code> grants every descendant read (authed and anonymous), and a deeper <code>.write: false</code> cannot revoke a truthy ancestor <code>.write</code> grant</span></span></span></summary>
|
|
296
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-rtdb-r5-cascade-root-grant</code> — production verdicts captured by deploy-observe-restore, replayed verdict-for-verdict; all 4 cases ALLOW in production, including the write to a node whose own <code>.write</code> is literal <code>false</code>. The simulator reproduces grant-only cascade rather than treating the deeper <code>false</code> as a veto
|
|
304
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/rtdb-rules/rules-rtdb-r5-cascade-root-grant.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-rtdb-r5-cascade-root-grant</code></a> — production verdicts captured by deploy-observe-restore, replayed verdict-for-verdict; all 4 cases ALLOW in production, including the write to a node whose own <code>.write</code> is literal <code>false</code>. The simulator reproduces grant-only cascade rather than treating the deeper <code>false</code> as a veto. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/rtdb/rules-conformance.test.ts#L2" target="_blank" rel="noopener noreferrer"><code>rules-conformance.test.ts</code></a>)</div></div>
|
|
297
305
|
</details>
|
|
298
306
|
<details class="compat-row" data-status="ok">
|
|
299
307
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior">Literal <code>.read</code>/<code>.write: false</code> — the deny-all baseline denies every op, authed or anonymous, read or write</span></span></span></summary>
|
|
300
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-rtdb-r6-deny-everything</code> — production verdicts captured by deploy-observe-restore, replayed verdict-for-verdict; all 3 cases DENY in production and in the simulator
|
|
308
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/rtdb-rules/rules-rtdb-r6-deny-everything.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-rtdb-r6-deny-everything</code></a> — production verdicts captured by deploy-observe-restore, replayed verdict-for-verdict; all 3 cases DENY in production and in the simulator. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/rtdb/rules-conformance.test.ts#L2" target="_blank" rel="noopener noreferrer"><code>rules-conformance.test.ts</code></a>)</div></div>
|
|
301
309
|
</details>
|
|
302
310
|
<details class="compat-row" data-status="ok">
|
|
303
311
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior">Nested path variable in an expression (<code>$sessionId === auth.uid</code>) — the matching session allows, a mismatched session denies, and an unmatched anonymous op denies with no matching rule</span></span></span></summary>
|
|
304
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-rtdb-r7-pathvar-binding</code> — production verdicts captured by deploy-observe-restore, replayed verdict-for-verdict; all 4 cases match. The simulator binds the nested variable identically and returns NO_MATCHING_RULE (read as deny) where production denies for want of a rule
|
|
312
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/rtdb-rules/rules-rtdb-r7-pathvar-binding.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-rtdb-r7-pathvar-binding</code></a> — production verdicts captured by deploy-observe-restore, replayed verdict-for-verdict; all 4 cases match. The simulator binds the nested variable identically and returns NO_MATCHING_RULE (read as deny) where production denies for want of a rule. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/rtdb/rules-conformance.test.ts#L2" target="_blank" rel="noopener noreferrer"><code>rules-conformance.test.ts</code></a>)</div></div>
|
|
305
313
|
</details>
|
|
306
314
|
<details class="compat-row" data-status="ok">
|
|
307
315
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior"><code>newData</code> is projected at the RULE node, not the written path — a root <code>.write</code> reading <code>newData.hasChildren(['owner'])</code> sees <code>{item:{...}}</code> for a write one level deeper, so the predicate is false and the write DENIES</span></span></span></summary>
|
|
308
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-rtdb-r8-combined-check</code> — production verdicts captured by deploy-observe-restore, replayed verdict-for-verdict. Production DENIES all three writes, including the "matching owner" case whose <code>owner</code> field lives under <code>/item</code> rather than at the rule node; only the auth-gated read allows. All 4 cases match, so the simulator projects <code>newData</code> at the same node production does — rule placement relative to the written path decides the outcome
|
|
316
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/rtdb-rules/rules-rtdb-r8-combined-check.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-rtdb-r8-combined-check</code></a> — production verdicts captured by deploy-observe-restore, replayed verdict-for-verdict. Production DENIES all three writes, including the "matching owner" case whose <code>owner</code> field lives under <code>/item</code> rather than at the rule node; only the auth-gated read allows. All 4 cases match, so the simulator projects <code>newData</code> at the same node production does — rule placement relative to the written path decides the outcome. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/rtdb/rules-conformance.test.ts#L2" target="_blank" rel="noopener noreferrer"><code>rules-conformance.test.ts</code></a>)</div></div>
|
|
309
317
|
</details>
|
|
310
318
|
<details class="compat-row" data-status="ok">
|
|
311
319
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior">Arithmetic and comparison operators in quota rules — <code>+</code> <code>-</code> <code>*</code> <code>/</code> <code>%</code>, <code>></code> <code>>=</code> <code><</code> <code><=</code>, <code>!==</code>, loose <code>==</code>, <code>||</code>, the ternary, and unary minus</span></span></span></summary>
|
|
312
|
-
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-12: production capture proves the simulator evaluates every arithmetic and ordering operator as production does, across increment-only counters, doubling and halving deltas, a parity check, inclusive and exclusive range caps, a negative sentinel, loose equality against zero, a disjunction, and a ternary tier bound. <code>oracle:rules-rtdb-r9-quota-arithmetic</code> matches production verdict-for-verdict on all 23 cases
|
|
320
|
+
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-12: production capture proves the simulator evaluates every arithmetic and ordering operator as production does, across increment-only counters, doubling and halving deltas, a parity check, inclusive and exclusive range caps, a negative sentinel, loose equality against zero, a disjunction, and a ternary tier bound. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/rtdb-rules/rules-rtdb-r9-quota-arithmetic.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-rtdb-r9-quota-arithmetic</code></a> matches production verdict-for-verdict on all 23 cases. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/rtdb/rules-conformance.test.ts#L2" target="_blank" rel="noopener noreferrer"><code>rules-conformance.test.ts</code></a>)</div></div>
|
|
313
321
|
</details>
|
|
314
322
|
<details class="compat-row" data-status="ok">
|
|
315
323
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior">Snapshot structure and type guards — <code>hasChild</code>, <code>parent()</code>, <code>isString</code>, <code>isNumber</code>, <code>isBoolean</code></span></span></span></summary>
|
|
316
|
-
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-12: production capture proves the simulator resolves the type predicates and the <code>parent()</code> path climb as production does, including RTDB's rule that a child <code>.validate</code> runs only for children PRESENT in <code>newData</code> — the name-without-age write is denied by that field's own parent guard, not by the absent sibling's type rule, which never runs. <code>oracle:rules-rtdb-r10-snapshot-type-guards</code> matches production verdict-for-verdict on all 7 cases
|
|
324
|
+
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-12: production capture proves the simulator resolves the type predicates and the <code>parent()</code> path climb as production does, including RTDB's rule that a child <code>.validate</code> runs only for children PRESENT in <code>newData</code> — the name-without-age write is denied by that field's own parent guard, not by the absent sibling's type rule, which never runs. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/rtdb-rules/rules-rtdb-r10-snapshot-type-guards.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-rtdb-r10-snapshot-type-guards</code></a> matches production verdict-for-verdict on all 7 cases. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/rtdb/rules-conformance.test.ts#L2" target="_blank" rel="noopener noreferrer"><code>rules-conformance.test.ts</code></a>)</div></div>
|
|
317
325
|
</details>
|
|
318
326
|
<details class="compat-row" data-status="ok">
|
|
319
327
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior">String methods on a snapshot value — <code>beginsWith</code>, <code>contains</code>, <code>endsWith</code>, <code>matches</code> with a regex literal, <code>.length</code>, <code>toLowerCase</code>, <code>toUpperCase</code>, and replace-ALL <code>replace</code></span></span></span></summary>
|
|
320
|
-
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-12: production capture proves <code>String.replace</code> substitutes EVERY occurrence of the substring, not only the first — production ALLOWS the write whose rule is <code>newData.val().replace('_', '-') === 'a-b-c'</code> for the value <code>a_b_c</code>, which holds only under replace-all. The simulator delegated to JavaScript's <code>String.prototype.replace</code>, which given a string pattern substitutes only the first occurrence, and DENIED that write; the substitution now replaces every occurrence and the two-underscore case guards the regression. The same capture proves <code>toUpperCase</code> is a valid production rule method that the simulator's validator previously rejected outright as unknown. <code>oracle:rules-rtdb-r11-string-validation</code> matches production verdict-for-verdict on all 18 cases
|
|
328
|
+
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-12: production capture proves <code>String.replace</code> substitutes EVERY occurrence of the substring, not only the first — production ALLOWS the write whose rule is <code>newData.val().replace('_', '-') === 'a-b-c'</code> for the value <code>a_b_c</code>, which holds only under replace-all. The simulator delegated to JavaScript's <code>String.prototype.replace</code>, which given a string pattern substitutes only the first occurrence, and DENIED that write; the substitution now replaces every occurrence and the two-underscore case guards the regression. The same capture proves <code>toUpperCase</code> is a valid production rule method that the simulator's validator previously rejected outright as unknown. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/rtdb-rules/rules-rtdb-r11-string-validation.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-rtdb-r11-string-validation</code></a> matches production verdict-for-verdict on all 18 cases. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/rtdb/rules-conformance.test.ts#L12" target="_blank" rel="noopener noreferrer"><code>rules-conformance.test.ts</code></a>)</div></div>
|
|
321
329
|
</details>
|
|
322
330
|
<details class="compat-row" data-status="ok">
|
|
323
331
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior"><code>now</code> (the server evaluation clock) and <code>auth.token</code> claims, read both dotted (<code>auth.token.firebase.sign_in_provider</code>) and subscripted (<code>auth.token['firebase']['sign_in_provider']</code>)</span></span></span></summary>
|
|
324
|
-
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-12: production capture proves the simulator resolves the server clock and the decoded ID-token claims as production does, through both access forms. The subscript's receiver is load-bearing: production's rules compiler ACCEPTS <code>auth.token[...]</code>, a map indexed by key, but REJECTS the same subscript applied to a snapshot value — <code>newData.val()['kind']</code> fails to compile with "No such method/property" — so <code>[]</code> is a map accessor, not a general indexing operator. <code>oracle:rules-rtdb-r12-server-time-and-token</code> matches production verdict-for-verdict on all 7 cases
|
|
332
|
+
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-12: production capture proves the simulator resolves the server clock and the decoded ID-token claims as production does, through both access forms. The subscript's receiver is load-bearing: production's rules compiler ACCEPTS <code>auth.token[...]</code>, a map indexed by key, but REJECTS the same subscript applied to a snapshot value — <code>newData.val()['kind']</code> fails to compile with "No such method/property" — so <code>[]</code> is a map accessor, not a general indexing operator. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/rtdb-rules/rules-rtdb-r12-server-time-and-token.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-rtdb-r12-server-time-and-token</code></a> matches production verdict-for-verdict on all 7 cases. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/rtdb/rules-conformance.test.ts#L31" target="_blank" rel="noopener noreferrer"><code>rules-conformance.test.ts</code></a>)</div></div>
|
|
325
333
|
</details>
|
|
326
334
|
<details class="compat-row" data-status="ok">
|
|
327
335
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior"><code>getPriority()</code> on a plain <code>set</code> (an unset priority reads null) and the <code>.indexOn</code> query-planner directive</span></span></span></summary>
|
|
328
|
-
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-12: production capture proves a plain <code>set</code> leaves a node's priority unset, so <code>getPriority()</code> reports null in production exactly as the simulator does, and that a ruleset carrying <code>.indexOn</code> deploys and evaluates with every verdict intact. The scope is exactly that: <code>.indexOn</code> never changes an allow/deny verdict, so the twin evidences only that production's compiler accepts and deploys the directive, and it says nothing about query behavior. A NON-null priority stays unverified because writing one requires <code>setWithPriority</code>, outside the corpus op vocabulary of read and set. <code>oracle:rules-rtdb-r13-priority-and-index-directive</code> matches production verdict-for-verdict on all 4 cases
|
|
336
|
+
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-12: production capture proves a plain <code>set</code> leaves a node's priority unset, so <code>getPriority()</code> reports null in production exactly as the simulator does, and that a ruleset carrying <code>.indexOn</code> deploys and evaluates with every verdict intact. The scope is exactly that: <code>.indexOn</code> never changes an allow/deny verdict, so the twin evidences only that production's compiler accepts and deploys the directive, and it says nothing about query behavior. A NON-null priority stays unverified because writing one requires <code>setWithPriority</code>, outside the corpus op vocabulary of read and set. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/rtdb-rules/rules-rtdb-r13-priority-and-index-directive.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-rtdb-r13-priority-and-index-directive</code></a> matches production verdict-for-verdict on all 4 cases. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/rtdb/rules-conformance.test.ts#L2" target="_blank" rel="noopener noreferrer"><code>rules-conformance.test.ts</code></a>)</div></div>
|
|
329
337
|
</details>
|
|
330
338
|
<details class="compat-row" data-status="ok">
|
|
331
339
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior">The <code>root</code> binding — <code>root.child(...).exists()</code> resolved against the database root</span></span></span></summary>
|
|
332
|
-
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-12: production capture proves the simulator resolves the <code>root</code> binding and reports a missing child as absent exactly as production does. The scope is bounded by the rig: the capture runner mounts the scenario subtree under a per-run randomly-named namespace while the replay suite mounts it at the root, so a rule naming any PRESENT path through <code>root</code> would address a different node on each side and diverge for harness reasons. Only a sentinel key absent under BOTH roots is mount-invariant, so that is what this row verifies; a populated <code>root</code> lookup remains unverified and needs a rig that can seed outside the scenario subtree and mount both sides at the same depth. <code>oracle:rules-rtdb-r14-root-lookup</code> matches production verdict-for-verdict on all 3 cases
|
|
340
|
+
<div class="compat-evidence"><div class="compat-probe">NEW ROW, 2026-07-12: production capture proves the simulator resolves the <code>root</code> binding and reports a missing child as absent exactly as production does. The scope is bounded by the rig: the capture runner mounts the scenario subtree under a per-run randomly-named namespace while the replay suite mounts it at the root, so a rule naming any PRESENT path through <code>root</code> would address a different node on each side and diverge for harness reasons. Only a sentinel key absent under BOTH roots is mount-invariant, so that is what this row verifies; a populated <code>root</code> lookup remains unverified and needs a rig that can seed outside the scenario subtree and mount both sides at the same depth. <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/rtdb-rules/rules-rtdb-r14-root-lookup.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-rtdb-r14-root-lookup</code></a> matches production verdict-for-verdict on all 3 cases. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/rtdb/rules-conformance.test.ts#L31" target="_blank" rel="noopener noreferrer"><code>rules-conformance.test.ts</code></a>)</div></div>
|
|
333
341
|
</details>
|
|
334
342
|
<details class="compat-row" data-status="ok">
|
|
335
343
|
<summary class="compat-line"><span class="compat-dot" data-status="ok" role="img" aria-label="Conforming" title="Conforming"></span><span class="compat-main"><code class="compat-api">Rules simulator</code><span class="compat-sub"><span class="compat-behavior"><code>.validate</code> reaches ancestors of the written path — each applicable rule is evaluated against the merged post-write value at its own location</span></span></span></summary>
|
|
336
|
-
<div class="compat-evidence"><div class="compat-probe"><code>oracle:rules-rtdb-r15-validate-ancestor-scope</code> — production DENIES a deep write that leaves its validated ancestor without the required child, while the same write under a rule-free ancestor ALLOWS and the write ALLOWS once the ancestor requirement is seeded. The simulator now walks validation from the root through the write location against the merged post-write tree and matches all 5 captured production cases
|
|
344
|
+
<div class="compat-evidence"><div class="compat-probe"><a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/rtdb-rules/rules-rtdb-r15-validate-ancestor-scope.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-rtdb-r15-validate-ancestor-scope</code></a> — production DENIES a deep write that leaves its validated ancestor without the required child, while the same write under a rule-free ancestor ALLOWS and the write ALLOWS once the ancestor requirement is seeded. The simulator now walks validation from the root through the write location against the merged post-write tree and matches all 5 captured production cases. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/rules/rtdb/rules-conformance.test.ts#L2" target="_blank" rel="noopener noreferrer"><code>rules-conformance.test.ts</code></a>)</div></div>
|
|
337
345
|
</details>
|
|
338
346
|
</div>
|
|
339
347
|
|
|
@@ -345,5 +353,5 @@ Known differences between Pyric and production Firebase. Each remains tracked as
|
|
|
345
353
|
|
|
346
354
|
<div class="compat-list">
|
|
347
355
|
<details class="compat-row" data-status="diverged"><summary class="compat-line"><span class="compat-dot" data-status="diverged" role="img" aria-label="Diverged (documented)" title="Diverged (documented)"></span><span class="compat-main"><code class="compat-api">Rules</code><span class="compat-sub"><span class="compat-behavior">Mocked Storage-to-Firestore lookup evaluation: get/exists return and missing-field errors, repeated and same-resolved-path calls, get+exists composition, and lazy <code>||</code>/<code>&&</code>/ternary branches with hosted function-call diagnostics</span></span></span></summary>
|
|
348
|
-
<div class="compat-evidence"><div class="compat-note">DOCUMENTED MOCK-ORACLE DIVERGENCE, 2026-07-21: <code>oracle:rules-storage-firestore-lookup-budget</code> matches the local evaluator on 13 of 14 cases and hosted diagnostics prove lazy branches omit lookup calls. The one mismatch is intentional and pinned on both sides: the Rules Test API ALLOWs three distinct mocked exists calls, while the evaluator DENYs the third distinct path to match the separately captured real-resource production contract in row #131. This row remains diverged because its mocked observation is not verdict-identical; it supplies no budget credit
|
|
356
|
+
<div class="compat-evidence"><div class="compat-note">DOCUMENTED MOCK-ORACLE DIVERGENCE, 2026-07-21: <a href="https://github.com/davideast/pyric/blob/main/packages/conformance/observations/storage-rules/rules-storage-firestore-lookup-budget.json" target="_blank" rel="noopener noreferrer"><code>oracle:rules-storage-firestore-lookup-budget</code></a> matches the local evaluator on 13 of 14 cases and hosted diagnostics prove lazy branches omit lookup calls. The one mismatch is intentional and pinned on both sides: the Rules Test API ALLOWs three distinct mocked exists calls, while the evaluator DENYs the third distinct path to match the separately captured real-resource production contract in row #131. This row remains diverged because its mocked observation is not verdict-identical; it supplies no budget credit. (Structured evidence: <a href="https://github.com/davideast/pyric/blob/main/packages/pyric/test/storage/rules-oracle-conformance.test.ts#L71" target="_blank" rel="noopener noreferrer"><code>rules-oracle-conformance.test.ts</code></a>)</div></div></details>
|
|
349
357
|
</div>
|