@pyric/cli 0.1.0-alpha.9
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/LICENSE +216 -0
- package/README.md +156 -0
- package/README.md.orig +138 -0
- package/dist/assurance/attachment.d.ts +24 -0
- package/dist/assurance/attachment.d.ts.map +1 -0
- package/dist/assurance/attachment.js +138 -0
- package/dist/assurance/attachment.js.map +1 -0
- package/dist/assurance/browser.d.ts +7 -0
- package/dist/assurance/browser.d.ts.map +1 -0
- package/dist/assurance/browser.js +68 -0
- package/dist/assurance/browser.js.map +1 -0
- package/dist/assurance/campaign.d.ts +41 -0
- package/dist/assurance/campaign.d.ts.map +1 -0
- package/dist/assurance/campaign.js +364 -0
- package/dist/assurance/campaign.js.map +1 -0
- package/dist/assurance/capabilities.d.ts +7 -0
- package/dist/assurance/capabilities.d.ts.map +1 -0
- package/dist/assurance/capabilities.js +295 -0
- package/dist/assurance/capabilities.js.map +1 -0
- package/dist/assurance/cases.d.ts +14 -0
- package/dist/assurance/cases.d.ts.map +1 -0
- package/dist/assurance/cases.js +27 -0
- package/dist/assurance/cases.js.map +1 -0
- package/dist/assurance/generated-capabilities.d.ts +52 -0
- package/dist/assurance/generated-capabilities.d.ts.map +1 -0
- package/dist/assurance/generated-capabilities.js +329 -0
- package/dist/assurance/generated-capabilities.js.map +1 -0
- package/dist/assurance/index.d.ts +11 -0
- package/dist/assurance/index.d.ts.map +1 -0
- package/dist/assurance/index.js +9 -0
- package/dist/assurance/index.js.map +1 -0
- package/dist/assurance/runner.d.ts +3 -0
- package/dist/assurance/runner.d.ts.map +1 -0
- package/dist/assurance/runner.js +633 -0
- package/dist/assurance/runner.js.map +1 -0
- package/dist/assurance/tool-names.d.ts +4 -0
- package/dist/assurance/tool-names.d.ts.map +1 -0
- package/dist/assurance/tool-names.js +14 -0
- package/dist/assurance/tool-names.js.map +1 -0
- package/dist/assurance/tools.d.ts +19 -0
- package/dist/assurance/tools.d.ts.map +1 -0
- package/dist/assurance/tools.js +740 -0
- package/dist/assurance/tools.js.map +1 -0
- package/dist/assurance/types.d.ts +348 -0
- package/dist/assurance/types.d.ts.map +1 -0
- package/dist/assurance/types.js +7 -0
- package/dist/assurance/types.js.map +1 -0
- package/dist/assurance/validation.d.ts +8 -0
- package/dist/assurance/validation.d.ts.map +1 -0
- package/dist/assurance/validation.js +269 -0
- package/dist/assurance/validation.js.map +1 -0
- package/dist/bridge/client/bridge.d.ts +133 -0
- package/dist/bridge/client/bridge.d.ts.map +1 -0
- package/dist/bridge/client/bridge.js +429 -0
- package/dist/bridge/client/bridge.js.map +1 -0
- package/dist/bridge/client/dispatch.d.ts +41 -0
- package/dist/bridge/client/dispatch.d.ts.map +1 -0
- package/dist/bridge/client/dispatch.js +111 -0
- package/dist/bridge/client/dispatch.js.map +1 -0
- package/dist/bridge/client.d.ts +24 -0
- package/dist/bridge/client.d.ts.map +1 -0
- package/dist/bridge/client.js +26 -0
- package/dist/bridge/client.js.map +1 -0
- package/dist/bridge/protocol.d.ts +227 -0
- package/dist/bridge/protocol.d.ts.map +1 -0
- package/dist/bridge/protocol.js +131 -0
- package/dist/bridge/protocol.js.map +1 -0
- package/dist/bridge/server/audit.d.ts +19 -0
- package/dist/bridge/server/audit.d.ts.map +1 -0
- package/dist/bridge/server/audit.js +46 -0
- package/dist/bridge/server/audit.js.map +1 -0
- package/dist/bridge/server/bridge.d.ts +126 -0
- package/dist/bridge/server/bridge.d.ts.map +1 -0
- package/dist/bridge/server/bridge.js +383 -0
- package/dist/bridge/server/bridge.js.map +1 -0
- package/dist/bridge/server/headless.d.ts +36 -0
- package/dist/bridge/server/headless.d.ts.map +1 -0
- package/dist/bridge/server/headless.js +142 -0
- package/dist/bridge/server/headless.js.map +1 -0
- package/dist/bridge/server/json-schema-to-zod.d.ts +37 -0
- package/dist/bridge/server/json-schema-to-zod.d.ts.map +1 -0
- package/dist/bridge/server/json-schema-to-zod.js +93 -0
- package/dist/bridge/server/json-schema-to-zod.js.map +1 -0
- package/dist/bridge/server/local-bridge.d.ts +33 -0
- package/dist/bridge/server/local-bridge.d.ts.map +1 -0
- package/dist/bridge/server/local-bridge.js +41 -0
- package/dist/bridge/server/local-bridge.js.map +1 -0
- package/dist/bridge/server/logger.d.ts +28 -0
- package/dist/bridge/server/logger.d.ts.map +1 -0
- package/dist/bridge/server/logger.js +42 -0
- package/dist/bridge/server/logger.js.map +1 -0
- package/dist/bridge/server/mcp-contract.d.ts +21 -0
- package/dist/bridge/server/mcp-contract.d.ts.map +1 -0
- package/dist/bridge/server/mcp-contract.js +62 -0
- package/dist/bridge/server/mcp-contract.js.map +1 -0
- package/dist/bridge/server/mcp.d.ts +26 -0
- package/dist/bridge/server/mcp.d.ts.map +1 -0
- package/dist/bridge/server/mcp.js +102 -0
- package/dist/bridge/server/mcp.js.map +1 -0
- package/dist/bridge/server/peer.d.ts +39 -0
- package/dist/bridge/server/peer.d.ts.map +1 -0
- package/dist/bridge/server/peer.js +189 -0
- package/dist/bridge/server/peer.js.map +1 -0
- package/dist/bridge/server/standalone.d.ts +49 -0
- package/dist/bridge/server/standalone.d.ts.map +1 -0
- package/dist/bridge/server/standalone.js +267 -0
- package/dist/bridge/server/standalone.js.map +1 -0
- package/dist/bridge/server/tool-metadata.d.ts +38 -0
- package/dist/bridge/server/tool-metadata.d.ts.map +1 -0
- package/dist/bridge/server/tool-metadata.js +81 -0
- package/dist/bridge/server/tool-metadata.js.map +1 -0
- package/dist/bridge/server.d.ts +21 -0
- package/dist/bridge/server.d.ts.map +1 -0
- package/dist/bridge/server.js +18 -0
- package/dist/bridge/server.js.map +1 -0
- package/dist/cli/database-rules.d.ts +43 -0
- package/dist/cli/database-rules.d.ts.map +1 -0
- package/dist/cli/database-rules.js +261 -0
- package/dist/cli/database-rules.js.map +1 -0
- package/dist/cli/dev-runner.d.ts +112 -0
- package/dist/cli/dev-runner.d.ts.map +1 -0
- package/dist/cli/dev-runner.js +239 -0
- package/dist/cli/dev-runner.js.map +1 -0
- package/dist/cli/firebase-json.d.ts +66 -0
- package/dist/cli/firebase-json.d.ts.map +1 -0
- package/dist/cli/firebase-json.js +60 -0
- package/dist/cli/firebase-json.js.map +1 -0
- package/dist/cli/firestore-indexes.d.ts +21 -0
- package/dist/cli/firestore-indexes.d.ts.map +1 -0
- package/dist/cli/firestore-indexes.js +39 -0
- package/dist/cli/firestore-indexes.js.map +1 -0
- package/dist/cli/index.d.ts +56 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +379 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +50 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +182 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/mcp-proxy.d.ts +10 -0
- package/dist/cli/mcp-proxy.d.ts.map +1 -0
- package/dist/cli/mcp-proxy.js +129 -0
- package/dist/cli/mcp-proxy.js.map +1 -0
- package/dist/cli/parse-args.d.ts +20 -0
- package/dist/cli/parse-args.d.ts.map +1 -0
- package/dist/cli/parse-args.js +69 -0
- package/dist/cli/parse-args.js.map +1 -0
- package/dist/cli/rules.d.ts +55 -0
- package/dist/cli/rules.d.ts.map +1 -0
- package/dist/cli/rules.js +199 -0
- package/dist/cli/rules.js.map +1 -0
- package/dist/cli/scope.d.ts +12 -0
- package/dist/cli/scope.d.ts.map +1 -0
- package/dist/cli/scope.js +44 -0
- package/dist/cli/scope.js.map +1 -0
- package/dist/cli/serve.d.ts +122 -0
- package/dist/cli/serve.d.ts.map +1 -0
- package/dist/cli/serve.js +844 -0
- package/dist/cli/serve.js.map +1 -0
- package/dist/cli/service-commands.d.ts +8 -0
- package/dist/cli/service-commands.d.ts.map +1 -0
- package/dist/cli/service-commands.js +58 -0
- package/dist/cli/service-commands.js.map +1 -0
- package/dist/cli/snapshot.d.ts +22 -0
- package/dist/cli/snapshot.d.ts.map +1 -0
- package/dist/cli/snapshot.js +139 -0
- package/dist/cli/snapshot.js.map +1 -0
- package/dist/cli/storage-rules.d.ts +21 -0
- package/dist/cli/storage-rules.d.ts.map +1 -0
- package/dist/cli/storage-rules.js +121 -0
- package/dist/cli/storage-rules.js.map +1 -0
- package/dist/cli/verify.d.ts +23 -0
- package/dist/cli/verify.d.ts.map +1 -0
- package/dist/cli/verify.js +349 -0
- package/dist/cli/verify.js.map +1 -0
- package/dist/credentials/core/memoize-ttl.d.ts +58 -0
- package/dist/credentials/core/memoize-ttl.d.ts.map +1 -0
- package/dist/credentials/core/memoize-ttl.js +88 -0
- package/dist/credentials/core/memoize-ttl.js.map +1 -0
- package/dist/credentials/core/types.d.ts +11 -0
- package/dist/credentials/core/types.d.ts.map +1 -0
- package/dist/credentials/core/types.js +2 -0
- package/dist/credentials/core/types.js.map +1 -0
- package/dist/credentials/node/from-adc.d.ts +10 -0
- package/dist/credentials/node/from-adc.d.ts.map +1 -0
- package/dist/credentials/node/from-adc.js +76 -0
- package/dist/credentials/node/from-adc.js.map +1 -0
- package/dist/credentials/node/from-service-account.d.ts +24 -0
- package/dist/credentials/node/from-service-account.d.ts.map +1 -0
- package/dist/credentials/node/from-service-account.js +108 -0
- package/dist/credentials/node/from-service-account.js.map +1 -0
- package/dist/credentials/node/index.d.ts +7 -0
- package/dist/credentials/node/index.d.ts.map +1 -0
- package/dist/credentials/node/index.js +7 -0
- package/dist/credentials/node/index.js.map +1 -0
- package/dist/discover/concurrency.d.ts +42 -0
- package/dist/discover/concurrency.d.ts.map +1 -0
- package/dist/discover/concurrency.js +113 -0
- package/dist/discover/concurrency.js.map +1 -0
- package/dist/discover/crawler-adapter.d.ts +48 -0
- package/dist/discover/crawler-adapter.d.ts.map +1 -0
- package/dist/discover/crawler-adapter.js +92 -0
- package/dist/discover/crawler-adapter.js.map +1 -0
- package/dist/discover/crawler.d.ts +294 -0
- package/dist/discover/crawler.d.ts.map +1 -0
- package/dist/discover/crawler.js +764 -0
- package/dist/discover/crawler.js.map +1 -0
- package/dist/discover/credential-free.d.ts +19 -0
- package/dist/discover/credential-free.d.ts.map +1 -0
- package/dist/discover/credential-free.js +18 -0
- package/dist/discover/credential-free.js.map +1 -0
- package/dist/discover/findCollectionGroup.d.ts +44 -0
- package/dist/discover/findCollectionGroup.d.ts.map +1 -0
- package/dist/discover/findCollectionGroup.js +81 -0
- package/dist/discover/findCollectionGroup.js.map +1 -0
- package/dist/discover/firestore-source.d.ts +60 -0
- package/dist/discover/firestore-source.d.ts.map +1 -0
- package/dist/discover/firestore-source.js +11 -0
- package/dist/discover/firestore-source.js.map +1 -0
- package/dist/discover/index.d.ts +3 -0
- package/dist/discover/index.d.ts.map +1 -0
- package/dist/discover/index.js +5 -0
- package/dist/discover/index.js.map +1 -0
- package/dist/discover/merge.d.ts +108 -0
- package/dist/discover/merge.d.ts.map +1 -0
- package/dist/discover/merge.js +394 -0
- package/dist/discover/merge.js.map +1 -0
- package/dist/discover/session.d.ts +116 -0
- package/dist/discover/session.d.ts.map +1 -0
- package/dist/discover/session.js +331 -0
- package/dist/discover/session.js.map +1 -0
- package/dist/discover/tools.d.ts +58 -0
- package/dist/discover/tools.d.ts.map +1 -0
- package/dist/discover/tools.js +115 -0
- package/dist/discover/tools.js.map +1 -0
- package/dist/discover/types.d.ts +190 -0
- package/dist/discover/types.d.ts.map +1 -0
- package/dist/discover/types.js +12 -0
- package/dist/discover/types.js.map +1 -0
- package/dist/discover/wire.d.ts +70 -0
- package/dist/discover/wire.d.ts.map +1 -0
- package/dist/discover/wire.js +309 -0
- package/dist/discover/wire.js.map +1 -0
- package/dist/functions-rtdb/child.d.ts +52 -0
- package/dist/functions-rtdb/child.d.ts.map +1 -0
- package/dist/functions-rtdb/child.js +283 -0
- package/dist/functions-rtdb/child.js.map +1 -0
- package/dist/functions-rtdb/delivery.d.ts +4 -0
- package/dist/functions-rtdb/delivery.d.ts.map +1 -0
- package/dist/functions-rtdb/delivery.js +2 -0
- package/dist/functions-rtdb/delivery.js.map +1 -0
- package/dist/functions-rtdb/discovery.d.ts +41 -0
- package/dist/functions-rtdb/discovery.d.ts.map +1 -0
- package/dist/functions-rtdb/discovery.js +86 -0
- package/dist/functions-rtdb/discovery.js.map +1 -0
- package/dist/functions-rtdb/event.d.ts +20 -0
- package/dist/functions-rtdb/event.d.ts.map +1 -0
- package/dist/functions-rtdb/event.js +45 -0
- package/dist/functions-rtdb/event.js.map +1 -0
- package/dist/functions-rtdb/execution.d.ts +20 -0
- package/dist/functions-rtdb/execution.d.ts.map +1 -0
- package/dist/functions-rtdb/execution.js +70 -0
- package/dist/functions-rtdb/execution.js.map +1 -0
- package/dist/functions-rtdb/in-memory-delivery.d.ts +9 -0
- package/dist/functions-rtdb/in-memory-delivery.d.ts.map +1 -0
- package/dist/functions-rtdb/in-memory-delivery.js +36 -0
- package/dist/functions-rtdb/in-memory-delivery.js.map +1 -0
- package/dist/functions-rtdb/project.d.ts +7 -0
- package/dist/functions-rtdb/project.d.ts.map +1 -0
- package/dist/functions-rtdb/project.js +54 -0
- package/dist/functions-rtdb/project.js.map +1 -0
- package/dist/functions-rtdb/projection.d.ts +14 -0
- package/dist/functions-rtdb/projection.d.ts.map +1 -0
- package/dist/functions-rtdb/projection.js +65 -0
- package/dist/functions-rtdb/projection.js.map +1 -0
- package/dist/functions-rtdb/reference-pattern.d.ts +5 -0
- package/dist/functions-rtdb/reference-pattern.d.ts.map +1 -0
- package/dist/functions-rtdb/reference-pattern.js +14 -0
- package/dist/functions-rtdb/reference-pattern.js.map +1 -0
- package/dist/functions-rtdb/remote-delivery.d.ts +9 -0
- package/dist/functions-rtdb/remote-delivery.d.ts.map +1 -0
- package/dist/functions-rtdb/remote-delivery.js +11 -0
- package/dist/functions-rtdb/remote-delivery.js.map +1 -0
- package/dist/pkg-version.d.ts +2 -0
- package/dist/pkg-version.d.ts.map +1 -0
- package/dist/pkg-version.js +47 -0
- package/dist/pkg-version.js.map +1 -0
- package/dist/register/esm-exports.d.ts +26 -0
- package/dist/register/esm-exports.d.ts.map +1 -0
- package/dist/register/esm-exports.js +61 -0
- package/dist/register/esm-exports.js.map +1 -0
- package/dist/register/hooks.d.ts +13 -0
- package/dist/register/hooks.d.ts.map +1 -0
- package/dist/register/hooks.js +15 -0
- package/dist/register/hooks.js.map +1 -0
- package/dist/register/index.d.ts +5 -0
- package/dist/register/index.d.ts.map +1 -0
- package/dist/register/index.js +124 -0
- package/dist/register/index.js.map +1 -0
- package/dist/register/mapping.d.ts +19 -0
- package/dist/register/mapping.d.ts.map +1 -0
- package/dist/register/mapping.js +35 -0
- package/dist/register/mapping.js.map +1 -0
- package/dist/remote/index.d.ts +232 -0
- package/dist/remote/index.d.ts.map +1 -0
- package/dist/remote/index.js +720 -0
- package/dist/remote/index.js.map +1 -0
- package/dist/rtdb/crawl-snapshot.d.ts +17 -0
- package/dist/rtdb/crawl-snapshot.d.ts.map +1 -0
- package/dist/rtdb/crawl-snapshot.js +72 -0
- package/dist/rtdb/crawl-snapshot.js.map +1 -0
- package/dist/rtdb/inspection.d.ts +8 -0
- package/dist/rtdb/inspection.d.ts.map +1 -0
- package/dist/rtdb/inspection.js +111 -0
- package/dist/rtdb/inspection.js.map +1 -0
- package/dist/rtdb/load-rules-document.d.ts +25 -0
- package/dist/rtdb/load-rules-document.d.ts.map +1 -0
- package/dist/rtdb/load-rules-document.js +38 -0
- package/dist/rtdb/load-rules-document.js.map +1 -0
- package/dist/rtdb/rules-generation-tool.d.ts +4 -0
- package/dist/rtdb/rules-generation-tool.d.ts.map +1 -0
- package/dist/rtdb/rules-generation-tool.js +35 -0
- package/dist/rtdb/rules-generation-tool.js.map +1 -0
- package/dist/rtdb/rules-json.d.ts +8 -0
- package/dist/rtdb/rules-json.d.ts.map +1 -0
- package/dist/rtdb/rules-json.js +17 -0
- package/dist/rtdb/rules-json.js.map +1 -0
- package/dist/serve/bridge-mount.d.ts +36 -0
- package/dist/serve/bridge-mount.d.ts.map +1 -0
- package/dist/serve/bridge-mount.js +162 -0
- package/dist/serve/bridge-mount.js.map +1 -0
- package/dist/serve/bundler.d.ts +110 -0
- package/dist/serve/bundler.d.ts.map +1 -0
- package/dist/serve/bundler.js +432 -0
- package/dist/serve/bundler.js.map +1 -0
- package/dist/serve/capture-store.d.ts +27 -0
- package/dist/serve/capture-store.d.ts.map +1 -0
- package/dist/serve/capture-store.js +47 -0
- package/dist/serve/capture-store.js.map +1 -0
- package/dist/serve/discovery.d.ts +71 -0
- package/dist/serve/discovery.d.ts.map +1 -0
- package/dist/serve/discovery.js +158 -0
- package/dist/serve/discovery.js.map +1 -0
- package/dist/serve/docs-ui/_astro/_slug_.CQYSemvw.css +1 -0
- package/dist/serve/docs-ui/docs/_rhythm/index.html +99 -0
- package/dist/serve/docs-ui/docs/_rhythm.md +101 -0
- package/dist/serve/docs-ui/docs/api-reference/index.html +64 -0
- package/dist/serve/docs-ui/docs/api-reference.md +67 -0
- package/dist/serve/docs-ui/docs/audit-your-rules/index.html +34 -0
- package/dist/serve/docs-ui/docs/audit-your-rules.md +50 -0
- package/dist/serve/docs-ui/docs/create-pyric-reference-api/index.html +498 -0
- package/dist/serve/docs-ui/docs/create-pyric-reference-api.md +345 -0
- package/dist/serve/docs-ui/docs/firestore-rules-limits/index.html +59 -0
- package/dist/serve/docs-ui/docs/firestore-rules-limits.md +54 -0
- package/dist/serve/docs-ui/docs/how-the-swap-works/index.html +47 -0
- package/dist/serve/docs-ui/docs/how-the-swap-works.md +43 -0
- package/dist/serve/docs-ui/docs/how-we-know-it-matches-firebase/index.html +131 -0
- package/dist/serve/docs-ui/docs/how-we-know-it-matches-firebase.md +169 -0
- package/dist/serve/docs-ui/docs/index.html +2 -0
- package/dist/serve/docs-ui/docs/index.json +18637 -0
- package/dist/serve/docs-ui/docs/overview/index.html +23 -0
- package/dist/serve/docs-ui/docs/overview.md +40 -0
- package/dist/serve/docs-ui/docs/pyric-admin-app/index.html +19 -0
- package/dist/serve/docs-ui/docs/pyric-admin-app-reference-api/index.html +185 -0
- package/dist/serve/docs-ui/docs/pyric-admin-app-reference-api.md +206 -0
- package/dist/serve/docs-ui/docs/pyric-admin-app.md +27 -0
- package/dist/serve/docs-ui/docs/pyric-admin-auth/index.html +24 -0
- package/dist/serve/docs-ui/docs/pyric-admin-auth-reference-api/index.html +617 -0
- package/dist/serve/docs-ui/docs/pyric-admin-auth-reference-api.md +441 -0
- package/dist/serve/docs-ui/docs/pyric-admin-auth.md +29 -0
- package/dist/serve/docs-ui/docs/pyric-admin-database/index.html +26 -0
- package/dist/serve/docs-ui/docs/pyric-admin-database-reference-api/index.html +583 -0
- package/dist/serve/docs-ui/docs/pyric-admin-database-reference-api.md +597 -0
- package/dist/serve/docs-ui/docs/pyric-admin-database.md +31 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore/index.html +38 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-explanation-error-translation/index.html +57 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-explanation-error-translation.md +95 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-explanation-per-call-delegate/index.html +58 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-explanation-per-call-delegate.md +94 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-explanation-why-mirror-admin-shape/index.html +59 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-explanation-why-mirror-admin-shape.md +88 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-run-a-transaction/index.html +53 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-run-a-transaction.md +76 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-seed-and-set-rules/index.html +62 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-seed-and-set-rules.md +96 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-translate-denials/index.html +80 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-translate-denials.md +98 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-use-onsnapshot/index.html +57 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-use-onsnapshot.md +88 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-write-a-batch/index.html +50 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-how-to-write-a-batch.md +73 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-api/index.html +32 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-api.md +30 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-onsnapshot/index.html +68 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-onsnapshot.md +81 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-re-exported-types/index.html +76 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-re-exported-types.md +103 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-sandbox-firestore/index.html +40 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-sandbox-firestore.md +77 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-tutorials-01-first-admin-session/index.html +118 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore-tutorials-01-first-admin-session.md +166 -0
- package/dist/serve/docs-ui/docs/pyric-admin-firestore.md +53 -0
- package/dist/serve/docs-ui/docs/pyric-admin-storage/index.html +25 -0
- package/dist/serve/docs-ui/docs/pyric-admin-storage-reference-api/index.html +317 -0
- package/dist/serve/docs-ui/docs/pyric-admin-storage-reference-api.md +285 -0
- package/dist/serve/docs-ui/docs/pyric-admin-storage.md +30 -0
- package/dist/serve/docs-ui/docs/pyric-ai-compat/index.html +436 -0
- package/dist/serve/docs-ui/docs/pyric-ai-compat.md +471 -0
- package/dist/serve/docs-ui/docs/pyric-ai-reference-api/index.html +5831 -0
- package/dist/serve/docs-ui/docs/pyric-ai-reference-api.md +5440 -0
- package/dist/serve/docs-ui/docs/pyric-ai-scripting-reference-api/index.html +159 -0
- package/dist/serve/docs-ui/docs/pyric-ai-scripting-reference-api.md +122 -0
- package/dist/serve/docs-ui/docs/pyric-app-compat/index.html +180 -0
- package/dist/serve/docs-ui/docs/pyric-app-compat.md +199 -0
- package/dist/serve/docs-ui/docs/pyric-app-reference-api/index.html +420 -0
- package/dist/serve/docs-ui/docs/pyric-app-reference-api.md +326 -0
- package/dist/serve/docs-ui/docs/pyric-auth/index.html +59 -0
- package/dist/serve/docs-ui/docs/pyric-auth-compat/index.html +804 -0
- package/dist/serve/docs-ui/docs/pyric-auth-compat.md +847 -0
- package/dist/serve/docs-ui/docs/pyric-auth-reference-api/index.html +5452 -0
- package/dist/serve/docs-ui/docs/pyric-auth-reference-api.md +5271 -0
- package/dist/serve/docs-ui/docs/pyric-auth-reference-feature-matrix/index.html +781 -0
- package/dist/serve/docs-ui/docs/pyric-auth-reference-feature-matrix.md +198 -0
- package/dist/serve/docs-ui/docs/pyric-auth-reference-sandbox-test-driver/index.html +71 -0
- package/dist/serve/docs-ui/docs/pyric-auth-reference-sandbox-test-driver.md +108 -0
- package/dist/serve/docs-ui/docs/pyric-auth.md +86 -0
- package/dist/serve/docs-ui/docs/pyric-cli/index.html +40 -0
- package/dist/serve/docs-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +98 -0
- package/dist/serve/docs-ui/docs/pyric-cli-assurance-browser-reference-api.md +88 -0
- package/dist/serve/docs-ui/docs/pyric-cli-assurance-reference-api/index.html +2355 -0
- package/dist/serve/docs-ui/docs/pyric-cli-assurance-reference-api.md +1554 -0
- package/dist/serve/docs-ui/docs/pyric-cli-bridge/index.html +69 -0
- package/dist/serve/docs-ui/docs/pyric-cli-bridge-client-reference-api/index.html +546 -0
- package/dist/serve/docs-ui/docs/pyric-cli-bridge-client-reference-api.md +485 -0
- package/dist/serve/docs-ui/docs/pyric-cli-bridge-reference-api/index.html +506 -0
- package/dist/serve/docs-ui/docs/pyric-cli-bridge-reference-api.md +419 -0
- package/dist/serve/docs-ui/docs/pyric-cli-bridge.md +99 -0
- package/dist/serve/docs-ui/docs/pyric-cli-credentials-node-reference-api/index.html +67 -0
- package/dist/serve/docs-ui/docs/pyric-cli-credentials-node-reference-api.md +59 -0
- package/dist/serve/docs-ui/docs/pyric-cli-discover-reference-api/index.html +2355 -0
- package/dist/serve/docs-ui/docs/pyric-cli-discover-reference-api.md +2036 -0
- package/dist/serve/docs-ui/docs/pyric-cli-functions-rtdb-compat/index.html +112 -0
- package/dist/serve/docs-ui/docs/pyric-cli-functions-rtdb-compat.md +124 -0
- package/dist/serve/docs-ui/docs/pyric-cli-how-to-build-a-standalone-binary/index.html +91 -0
- package/dist/serve/docs-ui/docs/pyric-cli-how-to-build-a-standalone-binary.md +105 -0
- package/dist/serve/docs-ui/docs/pyric-cli-how-to-promote-sandbox-state-to-a-fixture/index.html +52 -0
- package/dist/serve/docs-ui/docs/pyric-cli-how-to-promote-sandbox-state-to-a-fixture.md +98 -0
- package/dist/serve/docs-ui/docs/pyric-cli-how-to-run-rtdb-onvaluecreated/index.html +66 -0
- package/dist/serve/docs-ui/docs/pyric-cli-how-to-run-rtdb-onvaluecreated.md +100 -0
- package/dist/serve/docs-ui/docs/pyric-cli-how-to-serve-persistence-and-multi-tab/index.html +228 -0
- package/dist/serve/docs-ui/docs/pyric-cli-how-to-serve-persistence-and-multi-tab.md +179 -0
- package/dist/serve/docs-ui/docs/pyric-cli-how-to-use-the-vite-plugin/index.html +341 -0
- package/dist/serve/docs-ui/docs/pyric-cli-how-to-use-the-vite-plugin.md +309 -0
- package/dist/serve/docs-ui/docs/pyric-cli-how-to-verify-against-a-captured-session/index.html +128 -0
- package/dist/serve/docs-ui/docs/pyric-cli-how-to-verify-against-a-captured-session.md +207 -0
- package/dist/serve/docs-ui/docs/pyric-cli-reference-cli/index.html +404 -0
- package/dist/serve/docs-ui/docs/pyric-cli-reference-cli.md +249 -0
- package/dist/serve/docs-ui/docs/pyric-cli-reference-package-and-resolution/index.html +93 -0
- package/dist/serve/docs-ui/docs/pyric-cli-reference-package-and-resolution.md +65 -0
- package/dist/serve/docs-ui/docs/pyric-cli-reference-verify/index.html +81 -0
- package/dist/serve/docs-ui/docs/pyric-cli-reference-verify.md +110 -0
- package/dist/serve/docs-ui/docs/pyric-cli-register-reference-api/index.html +10 -0
- package/dist/serve/docs-ui/docs/pyric-cli-register-reference-api.md +16 -0
- package/dist/serve/docs-ui/docs/pyric-cli-remote-reference-api/index.html +1044 -0
- package/dist/serve/docs-ui/docs/pyric-cli-remote-reference-api.md +952 -0
- package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api/index.html +5041 -0
- package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api.md +4739 -0
- package/dist/serve/docs-ui/docs/pyric-cli-tutorials-server-adoption/index.html +219 -0
- package/dist/serve/docs-ui/docs/pyric-cli-tutorials-server-adoption.md +251 -0
- package/dist/serve/docs-ui/docs/pyric-cli-tutorials-wire-claude-code/index.html +136 -0
- package/dist/serve/docs-ui/docs/pyric-cli-tutorials-wire-claude-code.md +217 -0
- package/dist/serve/docs-ui/docs/pyric-cli-verify-reference-api/index.html +926 -0
- package/dist/serve/docs-ui/docs/pyric-cli-verify-reference-api.md +586 -0
- package/dist/serve/docs-ui/docs/pyric-cli-vite-reference-api/index.html +102 -0
- package/dist/serve/docs-ui/docs/pyric-cli-vite-reference-api.md +76 -0
- package/dist/serve/docs-ui/docs/pyric-cli.md +42 -0
- package/dist/serve/docs-ui/docs/pyric-conformance-scores/index.html +180 -0
- package/dist/serve/docs-ui/docs/pyric-conformance-scores.md +184 -0
- package/dist/serve/docs-ui/docs/pyric-database/index.html +43 -0
- package/dist/serve/docs-ui/docs/pyric-database-compat/index.html +1224 -0
- package/dist/serve/docs-ui/docs/pyric-database-compat.md +1289 -0
- package/dist/serve/docs-ui/docs/pyric-database-explanation-rules-authoring-and-deploy-are-separate/index.html +16 -0
- package/dist/serve/docs-ui/docs/pyric-database-explanation-rules-authoring-and-deploy-are-separate.md +23 -0
- package/dist/serve/docs-ui/docs/pyric-database-reference-api/index.html +1851 -0
- package/dist/serve/docs-ui/docs/pyric-database-reference-api.md +1842 -0
- package/dist/serve/docs-ui/docs/pyric-database-reference-constraints/index.html +381 -0
- package/dist/serve/docs-ui/docs/pyric-database-reference-constraints.md +168 -0
- package/dist/serve/docs-ui/docs/pyric-database-reference-rules-tooling/index.html +218 -0
- package/dist/serve/docs-ui/docs/pyric-database-reference-rules-tooling.md +303 -0
- package/dist/serve/docs-ui/docs/pyric-database-tutorials-01-author-rtdb-rules-with-constraints/index.html +125 -0
- package/dist/serve/docs-ui/docs/pyric-database-tutorials-01-author-rtdb-rules-with-constraints.md +171 -0
- package/dist/serve/docs-ui/docs/pyric-database.md +26 -0
- package/dist/serve/docs-ui/docs/pyric-explanation-versioning-and-compatibility/index.html +40 -0
- package/dist/serve/docs-ui/docs/pyric-explanation-versioning-and-compatibility.md +68 -0
- package/dist/serve/docs-ui/docs/pyric-firestore/index.html +48 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-compat/index.html +868 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-compat.md +939 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-explanation-rules-tooling-is-separate/index.html +92 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-explanation-rules-tooling-is-separate.md +70 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-explanation-target-symbol-opacity/index.html +59 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-explanation-target-symbol-opacity.md +91 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-explanation-two-backends-one-surface/index.html +43 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-explanation-two-backends-one-surface.md +58 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-migrate-from-firebase-firestore/index.html +58 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-migrate-from-firebase-firestore.md +86 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-pick-a-backend/index.html +52 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-pick-a-backend.md +83 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-run-a-transaction/index.html +42 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-run-a-transaction.md +59 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-use-onsnapshot/index.html +66 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-use-onsnapshot.md +96 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-use-sandbox-ops/index.html +61 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-how-to-use-sandbox-ops.md +92 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-api/index.html +3623 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-api.md +3399 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-feature-matrix/index.html +80 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-feature-matrix.md +66 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-getfirestore/index.html +46 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-getfirestore.md +73 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-query-constraints/index.html +80 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-query-constraints.md +129 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-sandbox-ops/index.html +58 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-sandbox-ops.md +88 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-tool-factories/index.html +51 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-reference-tool-factories.md +71 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-tutorials-01-write-a-sandbox-demo/index.html +130 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-tutorials-01-write-a-sandbox-demo.md +180 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-tutorials-02-swap-to-prod-backend/index.html +59 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-tutorials-02-swap-to-prod-backend.md +92 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api/index.html +30 -0
- package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api.md +30 -0
- package/dist/serve/docs-ui/docs/pyric-firestore.md +72 -0
- package/dist/serve/docs-ui/docs/pyric-messaging-compat/index.html +300 -0
- package/dist/serve/docs-ui/docs/pyric-messaging-compat.md +321 -0
- package/dist/serve/docs-ui/docs/pyric-messaging-reference-api/index.html +508 -0
- package/dist/serve/docs-ui/docs/pyric-messaging-reference-api.md +374 -0
- package/dist/serve/docs-ui/docs/pyric-messaging-sw-reference-api/index.html +482 -0
- package/dist/serve/docs-ui/docs/pyric-messaging-sw-reference-api.md +348 -0
- package/dist/serve/docs-ui/docs/pyric-rules/index.html +87 -0
- package/dist/serve/docs-ui/docs/pyric-rules-compat/index.html +328 -0
- package/dist/serve/docs-ui/docs/pyric-rules-compat.md +347 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-agent-failure-modes/index.html +50 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-agent-failure-modes.md +78 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-lint-vs-validate-vs-simulate-vs-test/index.html +79 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-lint-vs-validate-vs-simulate-vs-test.md +69 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-runtime-budget-and-shared-gates/index.html +67 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-runtime-budget-and-shared-gates.md +75 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-sentinel-expression-engine/index.html +49 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-sentinel-expression-engine.md +74 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-simulator-vs-rules-test-api/index.html +95 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-simulator-vs-rules-test-api.md +80 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-the-2-plus-modules-extension/index.html +58 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-the-2-plus-modules-extension.md +79 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-value-wrappers-design/index.html +63 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-value-wrappers-design.md +84 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-why-this-package-exists/index.html +34 -0
- package/dist/serve/docs-ui/docs/pyric-rules-explanation-why-this-package-exists.md +43 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-compare-rulesets-for-weakening/index.html +55 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-compare-rulesets-for-weakening.md +77 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-inspect-rules-via-the-ast/index.html +90 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-inspect-rules-via-the-ast.md +129 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-lint-rules-source/index.html +55 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-lint-rules-source.md +84 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-pin-request-time/index.html +49 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-pin-request-time.md +64 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-register-tools-with-an-agent/index.html +61 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-register-tools-with-an-agent.md +87 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-resolve-module-imports/index.html +93 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-resolve-module-imports.md +105 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-simulate-rules-locally/index.html +89 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-simulate-rules-locally.md +134 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-test-rules-against-firebase/index.html +66 -0
- package/dist/serve/docs-ui/docs/pyric-rules-how-to-test-rules-against-firebase.md +102 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-api/index.html +2629 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-api.md +2213 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-ast/index.html +85 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-ast.md +121 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-conformance-gaps/index.html +277 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-conformance-gaps.md +360 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-errors/index.html +76 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-errors.md +123 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-lint-rules/index.html +148 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-lint-rules.md +159 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-simulator-context/index.html +66 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-simulator-context.md +104 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-stdlib-modules/index.html +241 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-stdlib-modules.md +143 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-test-case-schema/index.html +94 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-test-case-schema.md +121 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-validator-findings/index.html +87 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-validator-findings.md +117 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-value-wrappers/index.html +102 -0
- package/dist/serve/docs-ui/docs/pyric-rules-reference-value-wrappers.md +152 -0
- package/dist/serve/docs-ui/docs/pyric-rules.md +93 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox/index.html +67 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-database-reference-api/index.html +120 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-database-reference-api.md +110 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-every-op-is-a-request/index.html +141 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-every-op-is-a-request.md +161 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-identity-is-a-context/index.html +66 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-identity-is-a-context.md +110 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-internal-adapter-protocol/index.html +71 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-internal-adapter-protocol.md +111 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-listener-re-evaluation/index.html +56 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-listener-re-evaluation.md +82 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-local-backend-vs-firestore-offline/index.html +64 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-local-backend-vs-firestore-offline.md +56 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-why-adapters-are-siblings/index.html +92 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-why-adapters-are-siblings.md +90 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-why-this-package-exists/index.html +69 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-explanation-why-this-package-exists.md +57 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-firestore-reference-api/index.html +202 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-firestore-reference-api.md +134 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-multiple-isolated-sandboxes/index.html +63 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-multiple-isolated-sandboxes.md +89 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-observe-events/index.html +159 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-observe-events.md +168 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-pick-an-adapter/index.html +79 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-pick-an-adapter.md +75 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-replay-events/index.html +88 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-replay-events.md +92 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-reset-between-tests/index.html +68 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-reset-between-tests.md +92 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-seed-data-and-rules/index.html +91 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-seed-data-and-rules.md +122 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-switch-users/index.html +50 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-switch-users.md +78 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-use-admin-reads/index.html +54 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-how-to-use-admin-reads.md +85 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api/index.html +5019 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api.md +4060 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-divergences/index.html +125 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-divergences.md +151 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-error-codes/index.html +110 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-error-codes.md +118 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-internal-protocol/index.html +72 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-internal-protocol.md +109 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-sandbox-and-context/index.html +90 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-sandbox-and-context.md +140 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-sandbox-event/index.html +146 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-sandbox-event.md +204 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-snapshot-and-admin/index.html +53 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-reference-snapshot-and-admin.md +89 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-tutorials-01-your-first-sandbox-session/index.html +115 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox-tutorials-01-your-first-sandbox-session.md +176 -0
- package/dist/serve/docs-ui/docs/pyric-sandbox.md +69 -0
- package/dist/serve/docs-ui/docs/pyric-storage/index.html +65 -0
- package/dist/serve/docs-ui/docs/pyric-storage-compat/index.html +676 -0
- package/dist/serve/docs-ui/docs/pyric-storage-compat.md +699 -0
- package/dist/serve/docs-ui/docs/pyric-storage-explanation-implementation-scope/index.html +52 -0
- package/dist/serve/docs-ui/docs/pyric-storage-explanation-implementation-scope.md +85 -0
- package/dist/serve/docs-ui/docs/pyric-storage-explanation-session-archive-use-case/index.html +58 -0
- package/dist/serve/docs-ui/docs/pyric-storage-explanation-session-archive-use-case.md +82 -0
- package/dist/serve/docs-ui/docs/pyric-storage-explanation-why-indexeddb/index.html +50 -0
- package/dist/serve/docs-ui/docs/pyric-storage-explanation-why-indexeddb.md +82 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-enforce-rules/index.html +120 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-enforce-rules.md +127 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-list-and-delete/index.html +53 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-list-and-delete.md +86 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-switch-backends/index.html +43 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-switch-backends.md +65 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-test-rule-expressions/index.html +70 -0
- package/dist/serve/docs-ui/docs/pyric-storage-how-to-test-rule-expressions.md +88 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-api/index.html +2120 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-api.md +1687 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-conformance-gaps/index.html +137 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-conformance-gaps.md +171 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-error-codes/index.html +37 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-error-codes.md +57 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-rules-subset/index.html +96 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-rules-subset.md +134 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-storage-options/index.html +39 -0
- package/dist/serve/docs-ui/docs/pyric-storage-reference-storage-options.md +61 -0
- package/dist/serve/docs-ui/docs/pyric-storage.md +67 -0
- package/dist/serve/docs-ui/docs/pyric-ui-agents-reference-api/index.html +638 -0
- package/dist/serve/docs-ui/docs/pyric-ui-agents-reference-api.md +430 -0
- package/dist/serve/docs-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +813 -0
- package/dist/serve/docs-ui/docs/pyric-ui-auth-hooks-reference-api.md +634 -0
- package/dist/serve/docs-ui/docs/pyric-ui-auth-reference-api/index.html +1708 -0
- package/dist/serve/docs-ui/docs/pyric-ui-auth-reference-api.md +1300 -0
- package/dist/serve/docs-ui/docs/pyric-ui-events-hooks-reference-api/index.html +177 -0
- package/dist/serve/docs-ui/docs/pyric-ui-events-hooks-reference-api.md +111 -0
- package/dist/serve/docs-ui/docs/pyric-ui-events-reference-api/index.html +1542 -0
- package/dist/serve/docs-ui/docs/pyric-ui-events-reference-api.md +903 -0
- package/dist/serve/docs-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +1024 -0
- package/dist/serve/docs-ui/docs/pyric-ui-firestore-hooks-reference-api.md +640 -0
- package/dist/serve/docs-ui/docs/pyric-ui-firestore-reference-api/index.html +2753 -0
- package/dist/serve/docs-ui/docs/pyric-ui-firestore-reference-api.md +2171 -0
- package/dist/serve/docs-ui/docs/pyric-ui-primitives-reference-api/index.html +1005 -0
- package/dist/serve/docs-ui/docs/pyric-ui-primitives-reference-api.md +693 -0
- package/dist/serve/docs-ui/docs/pyric-ui-rtdb-reference-api/index.html +1388 -0
- package/dist/serve/docs-ui/docs/pyric-ui-rtdb-reference-api.md +1340 -0
- package/dist/serve/docs-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +131 -0
- package/dist/serve/docs-ui/docs/pyric-ui-rules-hooks-reference-api.md +76 -0
- package/dist/serve/docs-ui/docs/pyric-ui-rules-reference-api/index.html +648 -0
- package/dist/serve/docs-ui/docs/pyric-ui-rules-reference-api.md +508 -0
- package/dist/serve/docs-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +1457 -0
- package/dist/serve/docs-ui/docs/pyric-ui-storage-hooks-reference-api.md +1029 -0
- package/dist/serve/docs-ui/docs/pyric-ui-storage-reference-api/index.html +2476 -0
- package/dist/serve/docs-ui/docs/pyric-ui-storage-reference-api.md +1919 -0
- package/dist/serve/docs-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +1241 -0
- package/dist/serve/docs-ui/docs/pyric-ui-traffic-hooks-reference-api.md +817 -0
- package/dist/serve/docs-ui/docs/pyric-ui-traffic-reference-api/index.html +2289 -0
- package/dist/serve/docs-ui/docs/pyric-ui-traffic-reference-api.md +1489 -0
- package/dist/serve/docs-ui/docs/read-a-denial/index.html +40 -0
- package/dist/serve/docs-ui/docs/read-a-denial.md +62 -0
- package/dist/serve/docs-ui/docs/receive-messages/index.html +28 -0
- package/dist/serve/docs-ui/docs/receive-messages.md +43 -0
- package/dist/serve/docs-ui/docs/rtdb-rules-in-typescript/index.html +67 -0
- package/dist/serve/docs-ui/docs/rtdb-rules-in-typescript.md +101 -0
- package/dist/serve/docs-ui/docs/rules-patterns/index.html +68 -0
- package/dist/serve/docs-ui/docs/rules-patterns.md +104 -0
- package/dist/serve/docs-ui/docs/rules-standard-library/index.html +87 -0
- package/dist/serve/docs-ui/docs/rules-standard-library.md +93 -0
- package/dist/serve/docs-ui/docs/run-ai-logic-locally/index.html +27 -0
- package/dist/serve/docs-ui/docs/run-ai-logic-locally.md +43 -0
- package/dist/serve/docs-ui/docs/secure-it-with-rules/index.html +69 -0
- package/dist/serve/docs-ui/docs/secure-it-with-rules.md +101 -0
- package/dist/serve/docs-ui/docs/see-whats-happening/index.html +73 -0
- package/dist/serve/docs-ui/docs/see-whats-happening.md +77 -0
- package/dist/serve/docs-ui/docs/set-up-the-project/index.html +14 -0
- package/dist/serve/docs-ui/docs/set-up-the-project.md +19 -0
- package/dist/serve/docs-ui/docs/set-up-your-agent/index.html +42 -0
- package/dist/serve/docs-ui/docs/set-up-your-agent.md +86 -0
- package/dist/serve/docs-ui/docs/shape-your-data/index.html +44 -0
- package/dist/serve/docs-ui/docs/shape-your-data.md +88 -0
- package/dist/serve/docs-ui/docs/ship-to-production/index.html +36 -0
- package/dist/serve/docs-ui/docs/ship-to-production.md +80 -0
- package/dist/serve/docs-ui/docs/sign-in-and-manage-users/index.html +31 -0
- package/dist/serve/docs-ui/docs/sign-in-and-manage-users.md +50 -0
- package/dist/serve/docs-ui/docs/simulate-and-lint/index.html +95 -0
- package/dist/serve/docs-ui/docs/simulate-and-lint.md +99 -0
- package/dist/serve/docs-ui/docs/skills/index.html +20 -0
- package/dist/serve/docs-ui/docs/skills.md +34 -0
- package/dist/serve/docs-ui/docs/start-building/index.html +32 -0
- package/dist/serve/docs-ui/docs/start-building.md +64 -0
- package/dist/serve/docs-ui/docs/store-and-query-data/index.html +16 -0
- package/dist/serve/docs-ui/docs/store-and-query-data.md +33 -0
- package/dist/serve/docs-ui/docs/store-files/index.html +13 -0
- package/dist/serve/docs-ui/docs/store-files.md +25 -0
- package/dist/serve/docs-ui/docs/sync-realtime-data/index.html +15 -0
- package/dist/serve/docs-ui/docs/sync-realtime-data.md +27 -0
- package/dist/serve/docs-ui/docs/test-in-node/index.html +74 -0
- package/dist/serve/docs-ui/docs/test-in-node.md +100 -0
- package/dist/serve/docs-ui/docs/ui/index.html +76 -0
- package/dist/serve/docs-ui/docs/ui-auth-authsigninhelper/index.html +194 -0
- package/dist/serve/docs-ui/docs/ui-auth-authsigninhelper.md +114 -0
- package/dist/serve/docs-ui/docs/ui-auth-authusers/index.html +263 -0
- package/dist/serve/docs-ui/docs/ui-auth-authusers.md +183 -0
- package/dist/serve/docs-ui/docs/ui-firestore-collectionlist/index.html +92 -0
- package/dist/serve/docs-ui/docs/ui-firestore-collectionlist.md +79 -0
- package/dist/serve/docs-ui/docs/ui-firestore-deletewithconfirm/index.html +128 -0
- package/dist/serve/docs-ui/docs/ui-firestore-deletewithconfirm.md +104 -0
- package/dist/serve/docs-ui/docs/ui-firestore-documenteditor/index.html +154 -0
- package/dist/serve/docs-ui/docs/ui-firestore-documenteditor.md +117 -0
- package/dist/serve/docs-ui/docs/ui-firestore-documentlist/index.html +132 -0
- package/dist/serve/docs-ui/docs/ui-firestore-documentlist.md +92 -0
- package/dist/serve/docs-ui/docs/ui-firestore-documentpreview/index.html +159 -0
- package/dist/serve/docs-ui/docs/ui-firestore-documentpreview.md +84 -0
- package/dist/serve/docs-ui/docs/ui-firestore-querybuilder/index.html +104 -0
- package/dist/serve/docs-ui/docs/ui-firestore-querybuilder.md +103 -0
- package/dist/serve/docs-ui/docs/ui-firestore-referencepicker/index.html +113 -0
- package/dist/serve/docs-ui/docs/ui-firestore-referencepicker.md +93 -0
- package/dist/serve/docs-ui/docs/ui-primitives-badge/index.html +56 -0
- package/dist/serve/docs-ui/docs/ui-primitives-badge.md +40 -0
- package/dist/serve/docs-ui/docs/ui-primitives-confirmdialog/index.html +140 -0
- package/dist/serve/docs-ui/docs/ui-primitives-confirmdialog.md +108 -0
- package/dist/serve/docs-ui/docs/ui-primitives-copybutton/index.html +58 -0
- package/dist/serve/docs-ui/docs/ui-primitives-copybutton.md +37 -0
- package/dist/serve/docs-ui/docs/ui-primitives-jsonview/index.html +58 -0
- package/dist/serve/docs-ui/docs/ui-primitives-jsonview.md +47 -0
- package/dist/serve/docs-ui/docs/ui-primitives-segmentedcontrol/index.html +70 -0
- package/dist/serve/docs-ui/docs/ui-primitives-segmentedcontrol.md +50 -0
- package/dist/serve/docs-ui/docs/ui-primitives-toast/index.html +87 -0
- package/dist/serve/docs-ui/docs/ui-primitives-toast.md +82 -0
- package/dist/serve/docs-ui/docs/ui-primitives-virtuallist/index.html +85 -0
- package/dist/serve/docs-ui/docs/ui-primitives-virtuallist.md +54 -0
- package/dist/serve/docs-ui/docs/ui-storage/index.html +150 -0
- package/dist/serve/docs-ui/docs/ui-storage-deleteselectionwithconfirm/index.html +126 -0
- package/dist/serve/docs-ui/docs/ui-storage-deleteselectionwithconfirm.md +88 -0
- package/dist/serve/docs-ui/docs/ui-storage-objectbrowser/index.html +137 -0
- package/dist/serve/docs-ui/docs/ui-storage-objectbrowser.md +90 -0
- package/dist/serve/docs-ui/docs/ui-storage-objectinspector/index.html +139 -0
- package/dist/serve/docs-ui/docs/ui-storage-objectinspector.md +93 -0
- package/dist/serve/docs-ui/docs/ui-storage-pathbreadcrumb/index.html +72 -0
- package/dist/serve/docs-ui/docs/ui-storage-pathbreadcrumb.md +57 -0
- package/dist/serve/docs-ui/docs/ui-storage-rules-aware-affordances/index.html +60 -0
- package/dist/serve/docs-ui/docs/ui-storage-rules-aware-affordances.md +52 -0
- package/dist/serve/docs-ui/docs/ui-storage-uploaddropzone/index.html +93 -0
- package/dist/serve/docs-ui/docs/ui-storage-uploaddropzone.md +78 -0
- package/dist/serve/docs-ui/docs/ui-storage-usestoragerulesgate/index.html +144 -0
- package/dist/serve/docs-ui/docs/ui-storage-usestoragerulesgate.md +101 -0
- package/dist/serve/docs-ui/docs/ui-storage.md +165 -0
- package/dist/serve/docs-ui/docs/ui-traffic/index.html +88 -0
- package/dist/serve/docs-ui/docs/ui-traffic-ruleheatmap/index.html +79 -0
- package/dist/serve/docs-ui/docs/ui-traffic-ruleheatmap.md +60 -0
- package/dist/serve/docs-ui/docs/ui-traffic-trafficdetail/index.html +78 -0
- package/dist/serve/docs-ui/docs/ui-traffic-trafficdetail.md +59 -0
- package/dist/serve/docs-ui/docs/ui-traffic-trafficlog/index.html +118 -0
- package/dist/serve/docs-ui/docs/ui-traffic-trafficlog.md +69 -0
- package/dist/serve/docs-ui/docs/ui-traffic-trafficstats/index.html +51 -0
- package/dist/serve/docs-ui/docs/ui-traffic-trafficstats.md +46 -0
- package/dist/serve/docs-ui/docs/ui-traffic.md +102 -0
- package/dist/serve/docs-ui/docs/ui.md +90 -0
- package/dist/serve/docs-ui/docs/watch-and-review/index.html +25 -0
- package/dist/serve/docs-ui/docs/watch-and-review.md +40 -0
- package/dist/serve/docs-ui/docs/what-your-agent-can-do/index.html +81 -0
- package/dist/serve/docs-ui/docs/what-your-agent-can-do.md +78 -0
- package/dist/serve/docs-ui/docs/whats-experimental/index.html +22 -0
- package/dist/serve/docs-ui/docs/whats-experimental.md +33 -0
- package/dist/serve/docs-ui/docs/whats-possible/index.html +63 -0
- package/dist/serve/docs-ui/docs/whats-possible.md +53 -0
- package/dist/serve/docs-ui/docs/which-data-service/index.html +8 -0
- package/dist/serve/docs-ui/docs/which-data-service.md +11 -0
- package/dist/serve/docs-ui/docs/write-a-rules-test-suite/index.html +85 -0
- package/dist/serve/docs-ui/docs/write-a-rules-test-suite.md +119 -0
- package/dist/serve/docs-ui/index.html +1 -0
- package/dist/serve/docs-ui/llms.txt +308 -0
- package/dist/serve/entries/ai.d.ts +4 -0
- package/dist/serve/entries/ai.d.ts.map +1 -0
- package/dist/serve/entries/ai.js +184 -0
- package/dist/serve/entries/ai.js.map +1 -0
- package/dist/serve/entries/app-backend.d.ts +2 -0
- package/dist/serve/entries/app-backend.d.ts.map +1 -0
- package/dist/serve/entries/app-backend.js +4 -0
- package/dist/serve/entries/app-backend.js.map +1 -0
- package/dist/serve/entries/app-client.d.ts +5 -0
- package/dist/serve/entries/app-client.d.ts.map +1 -0
- package/dist/serve/entries/app-client.js +23 -0
- package/dist/serve/entries/app-client.js.map +1 -0
- package/dist/serve/entries/app-session-store.d.ts +14 -0
- package/dist/serve/entries/app-session-store.d.ts.map +1 -0
- package/dist/serve/entries/app-session-store.js +37 -0
- package/dist/serve/entries/app-session-store.js.map +1 -0
- package/dist/serve/entries/app.d.ts +2 -0
- package/dist/serve/entries/app.d.ts.map +1 -0
- package/dist/serve/entries/app.js +10 -0
- package/dist/serve/entries/app.js.map +1 -0
- package/dist/serve/entries/auth-helper-core.d.ts +52 -0
- package/dist/serve/entries/auth-helper-core.d.ts.map +1 -0
- package/dist/serve/entries/auth-helper-core.js +118 -0
- package/dist/serve/entries/auth-helper-core.js.map +1 -0
- package/dist/serve/entries/auth-helper-dom.d.ts +14 -0
- package/dist/serve/entries/auth-helper-dom.d.ts.map +1 -0
- package/dist/serve/entries/auth-helper-dom.js +116 -0
- package/dist/serve/entries/auth-helper-dom.js.map +1 -0
- package/dist/serve/entries/auth-helper-runtime.d.ts +5 -0
- package/dist/serve/entries/auth-helper-runtime.d.ts.map +1 -0
- package/dist/serve/entries/auth-helper-runtime.js +11 -0
- package/dist/serve/entries/auth-helper-runtime.js.map +1 -0
- package/dist/serve/entries/auth.d.ts +77 -0
- package/dist/serve/entries/auth.d.ts.map +1 -0
- package/dist/serve/entries/auth.js +201 -0
- package/dist/serve/entries/auth.js.map +1 -0
- package/dist/serve/entries/bridge-url.d.ts +25 -0
- package/dist/serve/entries/bridge-url.d.ts.map +1 -0
- package/dist/serve/entries/bridge-url.js +30 -0
- package/dist/serve/entries/bridge-url.js.map +1 -0
- package/dist/serve/entries/database.d.ts +46 -0
- package/dist/serve/entries/database.d.ts.map +1 -0
- package/dist/serve/entries/database.js +80 -0
- package/dist/serve/entries/database.js.map +1 -0
- package/dist/serve/entries/firestore.d.ts +104 -0
- package/dist/serve/entries/firestore.d.ts.map +1 -0
- package/dist/serve/entries/firestore.js +202 -0
- package/dist/serve/entries/firestore.js.map +1 -0
- package/dist/serve/entries/init.d.ts +2 -0
- package/dist/serve/entries/init.d.ts.map +1 -0
- package/dist/serve/entries/init.js +40 -0
- package/dist/serve/entries/init.js.map +1 -0
- package/dist/serve/entries/keepalive.d.ts +20 -0
- package/dist/serve/entries/keepalive.d.ts.map +1 -0
- package/dist/serve/entries/keepalive.js +38 -0
- package/dist/serve/entries/keepalive.js.map +1 -0
- package/dist/serve/entries/messaging-sw.d.ts +10 -0
- package/dist/serve/entries/messaging-sw.d.ts.map +1 -0
- package/dist/serve/entries/messaging-sw.js +36 -0
- package/dist/serve/entries/messaging-sw.js.map +1 -0
- package/dist/serve/entries/messaging.d.ts +11 -0
- package/dist/serve/entries/messaging.d.ts.map +1 -0
- package/dist/serve/entries/messaging.js +53 -0
- package/dist/serve/entries/messaging.js.map +1 -0
- package/dist/serve/entries/runtime.d.ts +46 -0
- package/dist/serve/entries/runtime.d.ts.map +1 -0
- package/dist/serve/entries/runtime.js +435 -0
- package/dist/serve/entries/runtime.js.map +1 -0
- package/dist/serve/entries/session-store.d.ts +48 -0
- package/dist/serve/entries/session-store.d.ts.map +1 -0
- package/dist/serve/entries/session-store.js +82 -0
- package/dist/serve/entries/session-store.js.map +1 -0
- package/dist/serve/entries/storage.d.ts +25 -0
- package/dist/serve/entries/storage.d.ts.map +1 -0
- package/dist/serve/entries/storage.js +61 -0
- package/dist/serve/entries/storage.js.map +1 -0
- package/dist/serve/entries/tab-sync-wiring.d.ts +88 -0
- package/dist/serve/entries/tab-sync-wiring.d.ts.map +1 -0
- package/dist/serve/entries/tab-sync-wiring.js +217 -0
- package/dist/serve/entries/tab-sync-wiring.js.map +1 -0
- package/dist/serve/entries/worker-runtime.d.ts +10 -0
- package/dist/serve/entries/worker-runtime.d.ts.map +1 -0
- package/dist/serve/entries/worker-runtime.js +59 -0
- package/dist/serve/entries/worker-runtime.js.map +1 -0
- package/dist/serve/init-payload.d.ts +21 -0
- package/dist/serve/init-payload.d.ts.map +1 -0
- package/dist/serve/init-payload.js +2 -0
- package/dist/serve/init-payload.js.map +1 -0
- package/dist/serve/namespace.d.ts +73 -0
- package/dist/serve/namespace.d.ts.map +1 -0
- package/dist/serve/namespace.js +470 -0
- package/dist/serve/namespace.js.map +1 -0
- package/dist/serve/open-browser.d.ts +23 -0
- package/dist/serve/open-browser.d.ts.map +1 -0
- package/dist/serve/open-browser.js +58 -0
- package/dist/serve/open-browser.js.map +1 -0
- package/dist/serve/rules.d.ts +77 -0
- package/dist/serve/rules.d.ts.map +1 -0
- package/dist/serve/rules.js +202 -0
- package/dist/serve/rules.js.map +1 -0
- package/dist/serve/sandbox-marker.d.ts +9 -0
- package/dist/serve/sandbox-marker.d.ts.map +1 -0
- package/dist/serve/sandbox-marker.js +31 -0
- package/dist/serve/sandbox-marker.js.map +1 -0
- package/dist/serve/server.d.ts +135 -0
- package/dist/serve/server.d.ts.map +1 -0
- package/dist/serve/server.js +328 -0
- package/dist/serve/server.js.map +1 -0
- package/dist/serve/standalone-assets.d.ts +67 -0
- package/dist/serve/standalone-assets.d.ts.map +1 -0
- package/dist/serve/standalone-assets.js +134 -0
- package/dist/serve/standalone-assets.js.map +1 -0
- package/dist/serve/state-store.d.ts +45 -0
- package/dist/serve/state-store.d.ts.map +1 -0
- package/dist/serve/state-store.js +120 -0
- package/dist/serve/state-store.js.map +1 -0
- package/dist/serve/studio/disk-project-store.d.ts +9 -0
- package/dist/serve/studio/disk-project-store.d.ts.map +1 -0
- package/dist/serve/studio/disk-project-store.js +173 -0
- package/dist/serve/studio/disk-project-store.js.map +1 -0
- package/dist/serve/studio/disk-workspace.d.ts +14 -0
- package/dist/serve/studio/disk-workspace.d.ts.map +1 -0
- package/dist/serve/studio/disk-workspace.js +152 -0
- package/dist/serve/studio/disk-workspace.js.map +1 -0
- package/dist/serve/studio/index.d.ts +10 -0
- package/dist/serve/studio/index.d.ts.map +1 -0
- package/dist/serve/studio/index.js +9 -0
- package/dist/serve/studio/index.js.map +1 -0
- package/dist/serve/studio/routes.d.ts +40 -0
- package/dist/serve/studio/routes.d.ts.map +1 -0
- package/dist/serve/studio/routes.js +182 -0
- package/dist/serve/studio/routes.js.map +1 -0
- package/dist/serve/studio/store-types.d.ts +45 -0
- package/dist/serve/studio/store-types.d.ts.map +1 -0
- package/dist/serve/studio/store-types.js +11 -0
- package/dist/serve/studio/store-types.js.map +1 -0
- package/dist/serve/studio-ui/assets/RulesCodeEditor-BZpD57II.js +23 -0
- package/dist/serve/studio-ui/assets/index-Bsa-TQNK.css +1 -0
- package/dist/serve/studio-ui/assets/index-DGaVuOhE.js +1211 -0
- package/dist/serve/studio-ui/assets/seed-CTmn6YuO.js +2 -0
- package/dist/serve/studio-ui/index.html +32 -0
- package/dist/serve/studio-ui/pyric-logo.svg +76 -0
- package/dist/serve/vite-plugin.d.ts +57 -0
- package/dist/serve/vite-plugin.d.ts.map +1 -0
- package/dist/serve/vite-plugin.js +658 -0
- package/dist/serve/vite-plugin.js.map +1 -0
- package/dist/serve/worker/client/admin-firestore.d.ts +18 -0
- package/dist/serve/worker/client/admin-firestore.d.ts.map +1 -0
- package/dist/serve/worker/client/admin-firestore.js +26 -0
- package/dist/serve/worker/client/admin-firestore.js.map +1 -0
- package/dist/serve/worker/client/ai.d.ts +31 -0
- package/dist/serve/worker/client/ai.d.ts.map +1 -0
- package/dist/serve/worker/client/ai.js +89 -0
- package/dist/serve/worker/client/ai.js.map +1 -0
- package/dist/serve/worker/client/auth.d.ts +168 -0
- package/dist/serve/worker/client/auth.d.ts.map +1 -0
- package/dist/serve/worker/client/auth.js +322 -0
- package/dist/serve/worker/client/auth.js.map +1 -0
- package/dist/serve/worker/client/connection.d.ts +80 -0
- package/dist/serve/worker/client/connection.d.ts.map +1 -0
- package/dist/serve/worker/client/connection.js +148 -0
- package/dist/serve/worker/client/connection.js.map +1 -0
- package/dist/serve/worker/client/core.d.ts +109 -0
- package/dist/serve/worker/client/core.d.ts.map +1 -0
- package/dist/serve/worker/client/core.js +248 -0
- package/dist/serve/worker/client/core.js.map +1 -0
- package/dist/serve/worker/client/disconnect.d.ts +7 -0
- package/dist/serve/worker/client/disconnect.d.ts.map +1 -0
- package/dist/serve/worker/client/disconnect.js +26 -0
- package/dist/serve/worker/client/disconnect.js.map +1 -0
- package/dist/serve/worker/client/firestore-reads.d.ts +49 -0
- package/dist/serve/worker/client/firestore-reads.d.ts.map +1 -0
- package/dist/serve/worker/client/firestore-reads.js +139 -0
- package/dist/serve/worker/client/firestore-reads.js.map +1 -0
- package/dist/serve/worker/client/firestore-refs.d.ts +54 -0
- package/dist/serve/worker/client/firestore-refs.d.ts.map +1 -0
- package/dist/serve/worker/client/firestore-refs.js +167 -0
- package/dist/serve/worker/client/firestore-refs.js.map +1 -0
- package/dist/serve/worker/client/firestore-writes.d.ts +70 -0
- package/dist/serve/worker/client/firestore-writes.d.ts.map +1 -0
- package/dist/serve/worker/client/firestore-writes.js +169 -0
- package/dist/serve/worker/client/firestore-writes.js.map +1 -0
- package/dist/serve/worker/client/handles.d.ts +73 -0
- package/dist/serve/worker/client/handles.d.ts.map +1 -0
- package/dist/serve/worker/client/handles.js +4 -0
- package/dist/serve/worker/client/handles.js.map +1 -0
- package/dist/serve/worker/client/messaging.d.ts +16 -0
- package/dist/serve/worker/client/messaging.d.ts.map +1 -0
- package/dist/serve/worker/client/messaging.js +60 -0
- package/dist/serve/worker/client/messaging.js.map +1 -0
- package/dist/serve/worker/client/presence.d.ts +43 -0
- package/dist/serve/worker/client/presence.d.ts.map +1 -0
- package/dist/serve/worker/client/presence.js +132 -0
- package/dist/serve/worker/client/presence.js.map +1 -0
- package/dist/serve/worker/client/rtdb.d.ts +36 -0
- package/dist/serve/worker/client/rtdb.d.ts.map +1 -0
- package/dist/serve/worker/client/rtdb.js +241 -0
- package/dist/serve/worker/client/rtdb.js.map +1 -0
- package/dist/serve/worker/client/rules.d.ts +24 -0
- package/dist/serve/worker/client/rules.d.ts.map +1 -0
- package/dist/serve/worker/client/rules.js +44 -0
- package/dist/serve/worker/client/rules.js.map +1 -0
- package/dist/serve/worker/client/service-worker-connection.d.ts +3 -0
- package/dist/serve/worker/client/service-worker-connection.d.ts.map +1 -0
- package/dist/serve/worker/client/service-worker-connection.js +53 -0
- package/dist/serve/worker/client/service-worker-connection.js.map +1 -0
- package/dist/serve/worker/client/snapshots.d.ts +32 -0
- package/dist/serve/worker/client/snapshots.d.ts.map +1 -0
- package/dist/serve/worker/client/snapshots.js +46 -0
- package/dist/serve/worker/client/snapshots.js.map +1 -0
- package/dist/serve/worker/client/storage.d.ts +64 -0
- package/dist/serve/worker/client/storage.d.ts.map +1 -0
- package/dist/serve/worker/client/storage.js +125 -0
- package/dist/serve/worker/client/storage.js.map +1 -0
- package/dist/serve/worker/client/studio.d.ts +32 -0
- package/dist/serve/worker/client/studio.d.ts.map +1 -0
- package/dist/serve/worker/client/studio.js +61 -0
- package/dist/serve/worker/client/studio.js.map +1 -0
- package/dist/serve/worker/client.d.ts +43 -0
- package/dist/serve/worker/client.d.ts.map +1 -0
- package/dist/serve/worker/client.js +44 -0
- package/dist/serve/worker/client.js.map +1 -0
- package/dist/serve/worker/entry.d.ts +40 -0
- package/dist/serve/worker/entry.d.ts.map +1 -0
- package/dist/serve/worker/entry.js +144 -0
- package/dist/serve/worker/entry.js.map +1 -0
- package/dist/serve/worker/host/admin-firestore.d.ts +17 -0
- package/dist/serve/worker/host/admin-firestore.d.ts.map +1 -0
- package/dist/serve/worker/host/admin-firestore.js +92 -0
- package/dist/serve/worker/host/admin-firestore.js.map +1 -0
- package/dist/serve/worker/host/connection.d.ts +40 -0
- package/dist/serve/worker/host/connection.d.ts.map +1 -0
- package/dist/serve/worker/host/connection.js +153 -0
- package/dist/serve/worker/host/connection.js.map +1 -0
- package/dist/serve/worker/host/core.d.ts +159 -0
- package/dist/serve/worker/host/core.d.ts.map +1 -0
- package/dist/serve/worker/host/core.js +296 -0
- package/dist/serve/worker/host/core.js.map +1 -0
- package/dist/serve/worker/host/dispatch.d.ts +34 -0
- package/dist/serve/worker/host/dispatch.d.ts.map +1 -0
- package/dist/serve/worker/host/dispatch.js +267 -0
- package/dist/serve/worker/host/dispatch.js.map +1 -0
- package/dist/serve/worker/host/firestore-reads.d.ts +17 -0
- package/dist/serve/worker/host/firestore-reads.d.ts.map +1 -0
- package/dist/serve/worker/host/firestore-reads.js +108 -0
- package/dist/serve/worker/host/firestore-reads.js.map +1 -0
- package/dist/serve/worker/host/firestore-writes.d.ts +37 -0
- package/dist/serve/worker/host/firestore-writes.d.ts.map +1 -0
- package/dist/serve/worker/host/firestore-writes.js +409 -0
- package/dist/serve/worker/host/firestore-writes.js.map +1 -0
- package/dist/serve/worker/host/presence.d.ts +38 -0
- package/dist/serve/worker/host/presence.d.ts.map +1 -0
- package/dist/serve/worker/host/presence.js +280 -0
- package/dist/serve/worker/host/presence.js.map +1 -0
- package/dist/serve/worker/host/rtdb.d.ts +18 -0
- package/dist/serve/worker/host/rtdb.d.ts.map +1 -0
- package/dist/serve/worker/host/rtdb.js +128 -0
- package/dist/serve/worker/host/rtdb.js.map +1 -0
- package/dist/serve/worker/host/rules.d.ts +17 -0
- package/dist/serve/worker/host/rules.d.ts.map +1 -0
- package/dist/serve/worker/host/rules.js +118 -0
- package/dist/serve/worker/host/rules.js.map +1 -0
- package/dist/serve/worker/host/storage.d.ts +19 -0
- package/dist/serve/worker/host/storage.d.ts.map +1 -0
- package/dist/serve/worker/host/storage.js +260 -0
- package/dist/serve/worker/host/storage.js.map +1 -0
- package/dist/serve/worker/host/studio.d.ts +13 -0
- package/dist/serve/worker/host/studio.d.ts.map +1 -0
- package/dist/serve/worker/host/studio.js +30 -0
- package/dist/serve/worker/host/studio.js.map +1 -0
- package/dist/serve/worker/host/subscriptions.d.ts +21 -0
- package/dist/serve/worker/host/subscriptions.d.ts.map +1 -0
- package/dist/serve/worker/host/subscriptions.js +162 -0
- package/dist/serve/worker/host/subscriptions.js.map +1 -0
- package/dist/serve/worker/host-ai.d.ts +59 -0
- package/dist/serve/worker/host-ai.d.ts.map +1 -0
- package/dist/serve/worker/host-ai.js +158 -0
- package/dist/serve/worker/host-ai.js.map +1 -0
- package/dist/serve/worker/host-auth.d.ts +47 -0
- package/dist/serve/worker/host-auth.d.ts.map +1 -0
- package/dist/serve/worker/host-auth.js +464 -0
- package/dist/serve/worker/host-auth.js.map +1 -0
- package/dist/serve/worker/host-context.d.ts +220 -0
- package/dist/serve/worker/host-context.d.ts.map +1 -0
- package/dist/serve/worker/host-context.js +45 -0
- package/dist/serve/worker/host-context.js.map +1 -0
- package/dist/serve/worker/host-events.d.ts +21 -0
- package/dist/serve/worker/host-events.d.ts.map +1 -0
- package/dist/serve/worker/host-events.js +87 -0
- package/dist/serve/worker/host-events.js.map +1 -0
- package/dist/serve/worker/host-messaging.d.ts +60 -0
- package/dist/serve/worker/host-messaging.d.ts.map +1 -0
- package/dist/serve/worker/host-messaging.js +226 -0
- package/dist/serve/worker/host-messaging.js.map +1 -0
- package/dist/serve/worker/host.d.ts +36 -0
- package/dist/serve/worker/host.d.ts.map +1 -0
- package/dist/serve/worker/host.js +39 -0
- package/dist/serve/worker/host.js.map +1 -0
- package/dist/serve/worker/index.d.ts +22 -0
- package/dist/serve/worker/index.d.ts.map +1 -0
- package/dist/serve/worker/index.js +61 -0
- package/dist/serve/worker/index.js.map +1 -0
- package/dist/serve/worker/presence-timing.d.ts +14 -0
- package/dist/serve/worker/presence-timing.d.ts.map +1 -0
- package/dist/serve/worker/presence-timing.js +14 -0
- package/dist/serve/worker/presence-timing.js.map +1 -0
- package/dist/serve/worker/protocol.d.ts +1150 -0
- package/dist/serve/worker/protocol.d.ts.map +1 -0
- package/dist/serve/worker/protocol.js +228 -0
- package/dist/serve/worker/protocol.js.map +1 -0
- package/dist/serve/worker/serve-init.d.ts +201 -0
- package/dist/serve/worker/serve-init.d.ts.map +1 -0
- package/dist/serve/worker/serve-init.js +579 -0
- package/dist/serve/worker/serve-init.js.map +1 -0
- package/dist/serve/worker/service-worker-channel.d.ts +23 -0
- package/dist/serve/worker/service-worker-channel.d.ts.map +1 -0
- package/dist/serve/worker/service-worker-channel.js +9 -0
- package/dist/serve/worker/service-worker-channel.js.map +1 -0
- package/dist/serve/worker/service-worker-relay.d.ts +22 -0
- package/dist/serve/worker/service-worker-relay.d.ts.map +1 -0
- package/dist/serve/worker/service-worker-relay.js +63 -0
- package/dist/serve/worker/service-worker-relay.js.map +1 -0
- package/dist/serve/writer-lock.d.ts +32 -0
- package/dist/serve/writer-lock.d.ts.map +1 -0
- package/dist/serve/writer-lock.js +43 -0
- package/dist/serve/writer-lock.js.map +1 -0
- package/dist/verify/cases.d.ts +37 -0
- package/dist/verify/cases.d.ts.map +1 -0
- package/dist/verify/cases.js +173 -0
- package/dist/verify/cases.js.map +1 -0
- package/dist/verify/fixture.d.ts +100 -0
- package/dist/verify/fixture.d.ts.map +1 -0
- package/dist/verify/fixture.js +156 -0
- package/dist/verify/fixture.js.map +1 -0
- package/dist/verify/index.d.ts +102 -0
- package/dist/verify/index.d.ts.map +1 -0
- package/dist/verify/index.js +318 -0
- package/dist/verify/index.js.map +1 -0
- package/dist/verify/tools.d.ts +7 -0
- package/dist/verify/tools.d.ts.map +1 -0
- package/dist/verify/tools.js +83 -0
- package/dist/verify/tools.js.map +1 -0
- package/dist/version/compat-target.d.ts +18 -0
- package/dist/version/compat-target.d.ts.map +1 -0
- package/dist/version/compat-target.js +18 -0
- package/dist/version/compat-target.js.map +1 -0
- package/dist/vite.d.ts +12 -0
- package/dist/vite.d.ts.map +1 -0
- package/dist/vite.js +16 -0
- package/dist/vite.js.map +1 -0
- package/package.json +133 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<!DOCTYPE html><html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Agent failure modes the linter catches · Pyric Studio</title><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet"><link rel="stylesheet" href="/__pyric/ui/_astro/_slug_.CQYSemvw.css"></head> <body> <header class="studio__bar"> <div class="studio__bar-inner"> <a class="studio__brand" href="/__pyric/ui/" aria-label="Pyric Studio">Pyric</a> <nav class="studio__nav" aria-label="Studio tabs"> <a class="studio__nav-tab" href="/__pyric/ui/"> Home </a><a class="studio__nav-tab" href="/__pyric/ui/firestore"> Firestore </a><a class="studio__nav-tab" href="/__pyric/ui/auth"> Auth </a><a class="studio__nav-tab" href="/__pyric/ui/rtdb"> RTDB </a><a class="studio__nav-tab" href="/__pyric/ui/storage"> Storage </a><a class="studio__nav-tab" href="/__pyric/ui/traffic"> Traffic </a><a class="studio__nav-tab" href="/__pyric/ui/settings"> Settings </a><a class="studio__nav-tab" href="/__pyric/ui/docs" aria-current="page"> Docs </a> </nav> </div> </header> <div class="docs-shell"> <details class="docs-nav-drawer"> <summary>Navigate</summary> <nav class="docs-nav" aria-label="Documentation"> <div class="docs-search" data-index-url="/__pyric/ui/docs/index.json"> <div class="docs-search-field"> <svg class="docs-search-icon" viewBox="0 0 16 16" width="14" height="14" aria-hidden="true"> <path d="M11.5 11.5 15 15M13 7A6 6 0 1 1 1 7a6 6 0 0 1 12 0Z" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"></path> </svg> <input type="text" class="docs-search-input" placeholder="Search docs" aria-label="Search docs" autocomplete="off" spellcheck="false"> <kbd class="docs-search-kbd">⌘K</kbd> </div> <ul class="docs-search-results" hidden></ul> </div> <script type="module">let i=null;function d(t){return i||(i=fetch(t).then(e=>e.json())),i}function l(t,e){return t.title.toLowerCase().includes(e)||t.excerpt.toLowerCase().includes(e)?!0:t.headings.some(r=>r.text.toLowerCase().includes(e))}function u(t,e,r){if(e.innerHTML="",t.length===0){e.hidden=!1;{const n=document.createElement("li");n.className="docs-search-empty",n.textContent="No matches",e.appendChild(n)}return}e.hidden=!1;for(const n of t.slice(0,8)){const s=document.createElement("li"),c=document.createElement("a");c.href=n.path;const o=document.createElement("span");o.className="docs-search-result-title",o.textContent=n.title;const a=document.createElement("span");a.className="docs-search-result-meta",a.textContent=[n.group,n.section].filter(Boolean).join(" / "),c.append(o,a),s.appendChild(c),e.appendChild(s)}}document.querySelectorAll(".docs-search").forEach(t=>{const e=t.dataset.indexUrl,r=t.querySelector(".docs-search-input"),n=t.querySelector(".docs-search-results");r.addEventListener("input",async()=>{const s=r.value.trim().toLowerCase();if(!s){n.hidden=!0,n.innerHTML="";return}const{pages:c}=await d(e);r.value.trim().toLowerCase()===s&&u(c.filter(o=>l(o,s)),n)}),r.addEventListener("focus",()=>{d(e),n.childElementCount>0&&(n.hidden=!1)}),r.addEventListener("keydown",s=>{s.key==="Escape"&&(r.value="",n.hidden=!0,n.innerHTML="",r.blur())}),r.addEventListener("blur",()=>{window.setTimeout(()=>{n.hidden=!0},150)})});document.addEventListener("keydown",t=>{if(!(t.metaKey||t.ctrlKey)||t.key.toLowerCase()!=="k")return;const e=[...document.querySelectorAll(".docs-search-input")].find(r=>r.offsetParent!==null);e&&(t.preventDefault(),e.focus(),e.select())});</script> <a class="docs-nav-toplink" href="/__pyric/ui/docs/overview/"> Overview </a><details class="docs-nav-group"> <summary>Run locally</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/start-building/"> Quickstart </a> </li><li> <a href="/__pyric/ui/docs/how-the-swap-works/"> How the swap works </a> </li><li> <a href="/__pyric/ui/docs/set-up-your-agent/"> Connect an agent </a> </li><li> <a href="/__pyric/ui/docs/test-in-node/"> Test in Node </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Develop with Firebase APIs</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/sign-in-and-manage-users/"> Sign in and manage users </a> </li><li> <a href="/__pyric/ui/docs/store-and-query-data/"> Store and query data </a> </li><li> <a href="/__pyric/ui/docs/sync-realtime-data/"> Sync realtime data </a> </li><li> <a href="/__pyric/ui/docs/store-files/"> Store files </a> </li><li> <a href="/__pyric/ui/docs/receive-messages/"> Receive messages </a> </li><li> <a href="/__pyric/ui/docs/run-ai-logic-locally/"> Run AI Logic locally </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-how-to-run-rtdb-onvaluecreated/"> Run an RTDB function locally </a> </li><li> <a href="/__pyric/ui/docs/which-data-service/"> Which data service? </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Inspect and correct</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <h2 class="docs-nav-heading"> Inspect the sandbox </h2> <ul> <li> <a href="/__pyric/ui/docs/see-whats-happening/"> Traffic & rule verdicts </a> </li><li> <a href="/__pyric/ui/docs/read-a-denial/"> Read a denial and understand it </a> </li><li> <a href="/__pyric/ui/docs/shape-your-data/"> Seed, snapshot, replay </a> </li><li> <a href="/__pyric/ui/docs/watch-and-review/"> Review agent activity </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Correct Security Rules </h2> <ul> <li> <a href="/__pyric/ui/docs/secure-it-with-rules/"> Security Rules </a> </li><li> <a href="/__pyric/ui/docs/simulate-and-lint/"> Simulate and lint before you deploy </a> </li><li> <a href="/__pyric/ui/docs/rules-patterns/"> Rules patterns </a> </li><li> <a href="/__pyric/ui/docs/rules-standard-library/"> The rules standard library </a> </li><li> <a href="/__pyric/ui/docs/rtdb-rules-in-typescript/"> RTDB rules in TypeScript </a> </li><li> <a href="/__pyric/ui/docs/firestore-rules-limits/"> Rules limits </a> </li><li> <a href="/__pyric/ui/docs/whats-possible/"> Case studies </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Work with an agent </h2> <ul> <li> <a href="/__pyric/ui/docs/what-your-agent-can-do/"> Work through an agent </a> </li><li> <a href="/__pyric/ui/docs/skills/"> Agent skills </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Verify the boundary</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-cli-how-to-verify-against-a-captured-session/"> Verify a captured session </a> </li><li> <a href="/__pyric/ui/docs/write-a-rules-test-suite/"> Write a rules test suite </a> </li><li> <a href="/__pyric/ui/docs/audit-your-rules/"> Audit rules and data </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Ship unchanged</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/ship-to-production/"> Ship to production </a> </li><li> <a href="/__pyric/ui/docs/set-up-the-project/"> Set up the Firebase project </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Conformance</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/how-we-know-it-matches-firebase/"> Conformance </a> </li><li> <a href="/__pyric/ui/docs/whats-experimental/"> What's experimental </a> </li><li> <a href="/__pyric/ui/docs/pyric-conformance-scores/"> Conformance scores </a> </li><li> <a href="/__pyric/ui/docs/pyric-app-compat/"> App </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-compat/"> Firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-auth-compat/"> Auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-database-compat/"> Realtime Database </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-compat/"> Storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-compat/"> Rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-messaging-compat/"> Messaging </a> </li><li> <a href="/__pyric/ui/docs/pyric-ai-compat/"> AI Logic </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-functions-rtdb-compat/"> Functions · RTDB </a> </li> </ul> </div> </div> </details> <details class="docs-nav-group" open> <summary>Reference</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-cli/"> @pyric/cli </a> </li><li> <a href="/__pyric/ui/docs/pyric-explanation-versioning-and-compatibility/"> pyric </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore/"> pyric / firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules/" aria-current="true"> pyric / rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox/"> pyric / sandbox </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage/"> pyric / storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-auth/"> pyric / auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-database/"> pyric / database </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-app/"> pyric-admin / app </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore/"> pyric-admin / firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-auth/"> pyric-admin / auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-database/"> pyric-admin / database </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-storage/"> pyric-admin / storage </a> </li><li> <a href="/__pyric/ui/docs/ui/"> @pyric/ui </a> </li><li> <a href="/__pyric/ui/docs/api-reference/"> API reference </a> </li> </ul> </div> </div> </details> </nav> </details> <nav class="docs-nav" aria-label="Documentation"> <div class="docs-search" data-index-url="/__pyric/ui/docs/index.json"> <div class="docs-search-field"> <svg class="docs-search-icon" viewBox="0 0 16 16" width="14" height="14" aria-hidden="true"> <path d="M11.5 11.5 15 15M13 7A6 6 0 1 1 1 7a6 6 0 0 1 12 0Z" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"></path> </svg> <input type="text" class="docs-search-input" placeholder="Search docs" aria-label="Search docs" autocomplete="off" spellcheck="false"> <kbd class="docs-search-kbd">⌘K</kbd> </div> <ul class="docs-search-results" hidden></ul> </div> <a class="docs-nav-toplink" href="/__pyric/ui/docs/overview/" id="nav-group-overview"> Overview </a><details class="docs-nav-group" id="nav-group-run-locally"> <summary>Run locally</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/start-building/"> Quickstart </a> </li><li> <a href="/__pyric/ui/docs/how-the-swap-works/"> How the swap works </a> </li><li> <a href="/__pyric/ui/docs/set-up-your-agent/"> Connect an agent </a> </li><li> <a href="/__pyric/ui/docs/test-in-node/"> Test in Node </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-develop-with-firebase-apis"> <summary>Develop with Firebase APIs</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/sign-in-and-manage-users/"> Sign in and manage users </a> </li><li> <a href="/__pyric/ui/docs/store-and-query-data/"> Store and query data </a> </li><li> <a href="/__pyric/ui/docs/sync-realtime-data/"> Sync realtime data </a> </li><li> <a href="/__pyric/ui/docs/store-files/"> Store files </a> </li><li> <a href="/__pyric/ui/docs/receive-messages/"> Receive messages </a> </li><li> <a href="/__pyric/ui/docs/run-ai-logic-locally/"> Run AI Logic locally </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-how-to-run-rtdb-onvaluecreated/"> Run an RTDB function locally </a> </li><li> <a href="/__pyric/ui/docs/which-data-service/"> Which data service? </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-inspect-and-correct"> <summary>Inspect and correct</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-inspect-and-correct-inspect-the-sandbox"> Inspect the sandbox </h2> <ul> <li> <a href="/__pyric/ui/docs/see-whats-happening/"> Traffic & rule verdicts </a> </li><li> <a href="/__pyric/ui/docs/read-a-denial/"> Read a denial and understand it </a> </li><li> <a href="/__pyric/ui/docs/shape-your-data/"> Seed, snapshot, replay </a> </li><li> <a href="/__pyric/ui/docs/watch-and-review/"> Review agent activity </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-inspect-and-correct-correct-security-rules"> Correct Security Rules </h2> <ul> <li> <a href="/__pyric/ui/docs/secure-it-with-rules/"> Security Rules </a> </li><li> <a href="/__pyric/ui/docs/simulate-and-lint/"> Simulate and lint before you deploy </a> </li><li> <a href="/__pyric/ui/docs/rules-patterns/"> Rules patterns </a> </li><li> <a href="/__pyric/ui/docs/rules-standard-library/"> The rules standard library </a> </li><li> <a href="/__pyric/ui/docs/rtdb-rules-in-typescript/"> RTDB rules in TypeScript </a> </li><li> <a href="/__pyric/ui/docs/firestore-rules-limits/"> Rules limits </a> </li><li> <a href="/__pyric/ui/docs/whats-possible/"> Case studies </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-inspect-and-correct-work-with-an-agent"> Work with an agent </h2> <ul> <li> <a href="/__pyric/ui/docs/what-your-agent-can-do/"> Work through an agent </a> </li><li> <a href="/__pyric/ui/docs/skills/"> Agent skills </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-verify-the-boundary"> <summary>Verify the boundary</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-cli-how-to-verify-against-a-captured-session/"> Verify a captured session </a> </li><li> <a href="/__pyric/ui/docs/write-a-rules-test-suite/"> Write a rules test suite </a> </li><li> <a href="/__pyric/ui/docs/audit-your-rules/"> Audit rules and data </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-ship-unchanged"> <summary>Ship unchanged</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/ship-to-production/"> Ship to production </a> </li><li> <a href="/__pyric/ui/docs/set-up-the-project/"> Set up the Firebase project </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-conformance"> <summary>Conformance</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/how-we-know-it-matches-firebase/"> Conformance </a> </li><li> <a href="/__pyric/ui/docs/whats-experimental/"> What's experimental </a> </li><li> <a href="/__pyric/ui/docs/pyric-conformance-scores/"> Conformance scores </a> </li><li> <a href="/__pyric/ui/docs/pyric-app-compat/"> App </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-compat/"> Firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-auth-compat/"> Auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-database-compat/"> Realtime Database </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-compat/"> Storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-compat/"> Rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-messaging-compat/"> Messaging </a> </li><li> <a href="/__pyric/ui/docs/pyric-ai-compat/"> AI Logic </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-functions-rtdb-compat/"> Functions · RTDB </a> </li> </ul> </div> </div> </details> <details class="docs-nav-group" id="nav-group-reference" open> <summary>Reference</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-cli/"> @pyric/cli </a> </li><li> <a href="/__pyric/ui/docs/pyric-explanation-versioning-and-compatibility/"> pyric </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore/"> pyric / firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules/" aria-current="true"> pyric / rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox/"> pyric / sandbox </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage/"> pyric / storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-auth/"> pyric / auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-database/"> pyric / database </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-app/"> pyric-admin / app </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore/"> pyric-admin / firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-auth/"> pyric-admin / auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-database/"> pyric-admin / database </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-storage/"> pyric-admin / storage </a> </li><li> <a href="/__pyric/ui/docs/ui/"> @pyric/ui </a> </li><li> <a href="/__pyric/ui/docs/api-reference/"> API reference </a> </li> </ul> </div> </div> </details> </nav> <main class="doc-main"> <nav class="docs-breadcrumbs" aria-label="Breadcrumb"> <ol> <li> <a href="/__pyric/ui/docs/pyric-rules/">pyric / rules</a> </li><li> <span class="docs-breadcrumbs-sep" aria-hidden="true">/</span> <span>Explanation</span> </li><li> <span class="docs-breadcrumbs-sep" aria-hidden="true">/</span> <span aria-current="page">Agent failure modes</span> </li> </ol> </nav> <article class="prose"> <h1 id="agent-failure-modes-the-linter-catches">Agent failure modes the linter catches</h1>
|
|
2
|
+
<p>Most of the linter’s compilation and budget rules came from production: we hit the limit, learned the number, encoded it. A separate set of rules came from somewhere different. We watched LLM-driven agents try to write rules and fail in characteristic ways.</p>
|
|
3
|
+
<p>These rules are advisory in nature but defensive in posture. Each one exists because an agent shipped the same broken pattern more than once in our playground sessions. This page tells the stories.</p>
|
|
4
|
+
<h2 id="escaping-a-denial-with-if-true">Escaping a denial with <code>if true</code></h2>
|
|
5
|
+
<p>The most common failure mode. The agent writes a rule with a careful predicate. A test case denies when the agent expected it to allow. The agent doesn’t understand why, can’t reproduce the rule’s mental model, and replaces the predicate with <code>if true</code> to make the test pass.</p>
|
|
6
|
+
<p>The deploy ships. The collection is now publicly writable.</p>
|
|
7
|
+
<p>The linter catches this with two rules:</p>
|
|
8
|
+
<ul>
|
|
9
|
+
<li><strong><code>PERMISSIVE_RULE</code></strong>: any write rule whose predicate folds to constant <code>true</code>. The fold handles boolean literals, <code>&&</code> / <code>||</code> of booleans, <code>!</code> of a boolean. It does not try to prove <code>1 == 1</code> or follow function calls; a few false negatives are acceptable, a single false positive would block a legitimate deploy.</li>
|
|
10
|
+
<li><strong><code>RECURSIVE_WILDCARD_OPEN</code></strong>: a match path with <code>{document=**}</code> combined with an always-true predicate. The recursive wildcard makes the open-rule especially dangerous because it overrides every specific rule beneath it. Separate from <code>PERMISSIVE_RULE</code> so the diagnostic names the specific anti-pattern.</li>
|
|
11
|
+
</ul>
|
|
12
|
+
<p>Both are <code>severity: 'error'</code>. The deploy path refuses to swap a ruleset that contains either.</p>
|
|
13
|
+
<p>The fix isn’t to relax the linter. It’s to give the agent a real diagnostic for the original denial. Each <code>CaseResult</code>’s <code>trace</code> array shows exactly which rule decided; <code>explainCase</code> renders it into a readable string. If the agent learns to read that trace, the escape doesn’t happen.</p>
|
|
14
|
+
<h2 id="silently-removing-predicates">Silently removing predicates</h2>
|
|
15
|
+
<p>A subtler variant. The agent writes:</p>
|
|
16
|
+
<pre class="astro-code one-dark-pro" style="background-color:#282c34;color:#abb2bf; overflow-x: auto;" tabindex="0" data-language="rules"><code><span class="line"><span style="color:#C678DD">allow</span><span style="color:#61AFEF"> update</span><span style="color:#ABB2BF">: </span><span style="color:#C678DD">if</span><span style="color:#E5C07B"> request</span><span style="color:#ABB2BF">.auth.uid == </span><span style="color:#E5C07B">resource</span><span style="color:#ABB2BF">.data.ownerId</span></span>
|
|
17
|
+
<span class="line"><span style="color:#ABB2BF"> && status == </span><span style="color:#98C379">'open'</span><span style="color:#ABB2BF">;</span></span></code></pre>
|
|
18
|
+
<p>A test case fails because the test set <code>status</code> to <code>'closed'</code>. The agent doesn’t update the test data. It removes the <code>status == 'open'</code> conjunct from the rule. The test passes. The deploy ships. Updates against closed records are no longer gated.</p>
|
|
19
|
+
<p><code>RULES_WEAKENED</code> exists for this. When you pass the previously-deployed source to the linter (via the engine-internal <code>lintFirestoreRules</code> on <code>pyric/rules/internal</code>, since the public <code>lint</code> and <code>firestoreRules(source).lint()</code> take no options):</p>
|
|
20
|
+
<pre class="astro-code one-dark-pro" style="background-color:#282c34;color:#abb2bf; overflow-x: auto;" tabindex="0" data-language="ts"><code><span class="line"><span style="color:#61AFEF">lintFirestoreRules</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">newSource</span><span style="color:#ABB2BF">, { </span><span style="color:#E06C75">previousSource</span><span style="color:#ABB2BF">: </span><span style="color:#E06C75">oldSource</span><span style="color:#ABB2BF"> });</span></span></code></pre>
|
|
21
|
+
<p>…the linter normalises every match path, finds the corresponding allow rule by op-set, extracts the top-level conjuncts of each predicate (split only on <code>&&</code>, never <code>||</code>), and reports every conjunct that existed before and is missing now.</p>
|
|
22
|
+
<p><code>RULES_WEAKENED</code> is <code>warning</code>, not <code>error</code>. There are real reasons to delete a predicate: a refactor, a dedupe, an intentional broadening. The signal is “review this”, not “refuse the deploy”. A human (or a more careful agent) decides whether the removal is intentional.</p>
|
|
23
|
+
<h2 id="javascript-hallucinations">JavaScript hallucinations</h2>
|
|
24
|
+
<p>LLMs trained primarily on JavaScript will write <code>.filter()</code>, <code>.map()</code>, <code>.toLowerCase()</code>, <code>===</code>, <code>?.</code>, <code>??</code> in rules sources. None of these exist in the Firestore rules DSL. They either fail to parse (with an unhelpful “expected <code>)</code>” message) or parse and then fail at runtime (silently denying every request).</p>
|
|
25
|
+
<p>The pre-parse syntax-hint pass fires on the raw source, before the parser runs, so the diagnostic is precise even when the file is unparseable:</p>
|
|
26
|
+
<ul>
|
|
27
|
+
<li><strong><code>INVALID_OPERATOR</code></strong>: <code>===</code>, <code>!==</code>, <code>?.</code>, <code>??</code>, backtick template literals. Each gets a specific message naming the JS operator and the Firestore-equivalent (or absence of one).</li>
|
|
28
|
+
</ul>
|
|
29
|
+
<p>The post-parse hallucination pass walks the AST for syntactically-valid-but-semantically-wrong calls:</p>
|
|
30
|
+
<ul>
|
|
31
|
+
<li><strong><code>HALLUCINATED_METHOD</code></strong>: method calls that don’t exist in the rules surface.</li>
|
|
32
|
+
<li><strong><code>HALLUCINATED_GLOBAL</code></strong>: references to globals the engine doesn’t expose (<code>Math</code>, <code>JSON</code>, <code>Date</code>).</li>
|
|
33
|
+
<li><strong><code>WRONG_CONTEXT_PATH</code></strong>: <code>get(...)</code> calls whose path doesn’t begin with <code>/databases/$(database)/documents/</code>.</li>
|
|
34
|
+
<li><strong><code>LENGTH_PROPERTY</code></strong>: <code>.length</code> access on a string or list (the rules surface uses <code>.size()</code>).</li>
|
|
35
|
+
<li><strong><code>INVALID_PATH_INTERPOLATION</code></strong>: match-style <code>{ident}</code> used inside a path literal where Firestore requires <code>$(ident)</code>.</li>
|
|
36
|
+
<li><strong><code>METHOD_MISSING_PARENS</code></strong>: an identifier in expression position that looks like a method name without parens.</li>
|
|
37
|
+
</ul>
|
|
38
|
+
<p>Each rule produces a fix string when possible. The agent gets “you wrote <code>.length</code>, Firestore wants <code>.size()</code>” instead of a generic syntax error.</p>
|
|
39
|
+
<h2 id="time-dependent-flakiness">Time-dependent flakiness</h2>
|
|
40
|
+
<p>A rule reads <code>request.time</code> (a date-gated discount window, a trial-period check, an audit-log retention rule). The agent’s test case doesn’t pin <code>requestTime</code>, so the simulator falls back to wallclock. The test passes today, fails three months later when the rule’s date threshold has rolled past wallclock. CI starts going red intermittently.</p>
|
|
41
|
+
<p><code>REQUEST_TIME_NOT_PINNED</code> activates when <code>options.testCases</code> is passed to the linter. For each rule that transitively reads <code>request.time</code>, the linter emits one warning per test case that targets the rule and doesn’t set <code>requestTime</code>. The fix is mechanical: add the ISO-8601 string. The diagnostic is precise: it names the rule, the test case, the path.</p>
|
|
42
|
+
<p>This is the only lint rule that depends on a test suite, and the dependency is opt-in (<code>options.testCases</code> defaults to undefined). Source-only calls to the internal <code>lintFirestoreRules(source)</code> (or the public <code>lint(source)</code> / <code>firestoreRules(source).lint()</code>, which never take a test suite at all) behave as they always did.</p>
|
|
43
|
+
<h2 id="the-shape-of-these-rules">The shape of these rules</h2>
|
|
44
|
+
<p>Every rule on this page shares three properties:</p>
|
|
45
|
+
<ul>
|
|
46
|
+
<li><strong>It came from observation, not specification.</strong> No one sat down to design <code>RULES_WEAKENED</code>; we watched it ship a regression and added the check the next day.</li>
|
|
47
|
+
<li><strong>It targets the agent, not the language.</strong> A careful human reading the source would catch most of these on review. The point is to surface them automatically.</li>
|
|
48
|
+
<li><strong>It carries a precise fix.</strong> “Your rule is wrong” is a useless diagnostic for an agent looping on the linter’s output. “Replace <code>if true</code> with <code>request.auth.uid == resource.data.ownerId</code>” is something the agent can act on directly.</li>
|
|
49
|
+
</ul>
|
|
50
|
+
<p>The list is not closed. As we watch new failure modes emerge (typically when a model architecture changes, or a new playground scenario surfaces a recurring mistake), new rules join it.</p> </article> </main> <aside class="doc-toc" aria-label="On this page"> <h2 class="doc-toc-heading">On this page</h2> <ul> <li data-depth="2"> <a href="#escaping-a-denial-with-if-true">Escaping a denial with if true</a> </li><li data-depth="2"> <a href="#silently-removing-predicates">Silently removing predicates</a> </li><li data-depth="2"> <a href="#javascript-hallucinations">JavaScript hallucinations</a> </li><li data-depth="2"> <a href="#time-dependent-flakiness">Time-dependent flakiness</a> </li><li data-depth="2"> <a href="#the-shape-of-these-rules">The shape of these rules</a> </li> </ul> </aside> </div> <script type="module">const a=document.querySelector("[data-api-symbol-filter]"),d=[...document.querySelectorAll("[data-api-symbol-group]")],n=document.querySelector("[data-api-symbol-empty]");a?.addEventListener("input",()=>{const t=a.value.trim().toLowerCase();let o=0;for(const i of d){let e=0;i.querySelectorAll("[data-api-symbol]").forEach(l=>{const r=!t||(l.dataset.apiSymbol??"").includes(t);l.hidden=!r,r&&e++}),i.hidden=e===0,o+=e}n&&(n.hidden=o>0)});</script> <script type="module">const s=new Map;document.querySelectorAll('.doc-toc a[href^="#"]').forEach(t=>s.set(decodeURIComponent(t.hash.slice(1)),t));if(s.size>0){const t=new Set,n=()=>{let o=null;for(const e of s.keys())if(t.has(e)){o=e;break}s.forEach((e,c)=>e.classList.toggle("active",c===o))},r=new IntersectionObserver(o=>{for(const e of o)e.isIntersecting?t.add(e.target.id):t.delete(e.target.id);n()},{rootMargin:"-72px 0px -60% 0px"});s.forEach((o,e)=>{const c=document.getElementById(e);c&&r.observe(c)})}</script> <script type="module">document.querySelector('.studio__nav [aria-current="page"]')?.scrollIntoView({block:"nearest",inline:"center"});</script> </body> </html>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Agent failure modes the linter catches
|
|
2
|
+
|
|
3
|
+
Most of the linter's compilation and budget rules came from production: we hit the limit, learned the number, encoded it. A separate set of rules came from somewhere different. We watched LLM-driven agents try to write rules and fail in characteristic ways.
|
|
4
|
+
|
|
5
|
+
These rules are advisory in nature but defensive in posture. Each one exists because an agent shipped the same broken pattern more than once in our playground sessions. This page tells the stories.
|
|
6
|
+
|
|
7
|
+
## Escaping a denial with `if true`
|
|
8
|
+
|
|
9
|
+
The most common failure mode. The agent writes a rule with a careful predicate. A test case denies when the agent expected it to allow. The agent doesn't understand why, can't reproduce the rule's mental model, and replaces the predicate with `if true` to make the test pass.
|
|
10
|
+
|
|
11
|
+
The deploy ships. The collection is now publicly writable.
|
|
12
|
+
|
|
13
|
+
The linter catches this with two rules:
|
|
14
|
+
|
|
15
|
+
- **`PERMISSIVE_RULE`**: any write rule whose predicate folds to constant `true`. The fold handles boolean literals, `&&` / `||` of booleans, `!` of a boolean. It does not try to prove `1 == 1` or follow function calls; a few false negatives are acceptable, a single false positive would block a legitimate deploy.
|
|
16
|
+
- **`RECURSIVE_WILDCARD_OPEN`**: a match path with `{document=**}` combined with an always-true predicate. The recursive wildcard makes the open-rule especially dangerous because it overrides every specific rule beneath it. Separate from `PERMISSIVE_RULE` so the diagnostic names the specific anti-pattern.
|
|
17
|
+
|
|
18
|
+
Both are `severity: 'error'`. The deploy path refuses to swap a ruleset that contains either.
|
|
19
|
+
|
|
20
|
+
The fix isn't to relax the linter. It's to give the agent a real diagnostic for the original denial. Each `CaseResult`'s `trace` array shows exactly which rule decided; `explainCase` renders it into a readable string. If the agent learns to read that trace, the escape doesn't happen.
|
|
21
|
+
|
|
22
|
+
## Silently removing predicates
|
|
23
|
+
|
|
24
|
+
A subtler variant. The agent writes:
|
|
25
|
+
|
|
26
|
+
```rules
|
|
27
|
+
allow update: if request.auth.uid == resource.data.ownerId
|
|
28
|
+
&& status == 'open';
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
A test case fails because the test set `status` to `'closed'`. The agent doesn't update the test data. It removes the `status == 'open'` conjunct from the rule. The test passes. The deploy ships. Updates against closed records are no longer gated.
|
|
32
|
+
|
|
33
|
+
`RULES_WEAKENED` exists for this. When you pass the previously-deployed source to the linter (via the engine-internal `lintFirestoreRules` on `pyric/rules/internal`, since the public `lint` and `firestoreRules(source).lint()` take no options):
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
lintFirestoreRules(newSource, { previousSource: oldSource });
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
…the linter normalises every match path, finds the corresponding allow rule by op-set, extracts the top-level conjuncts of each predicate (split only on `&&`, never `||`), and reports every conjunct that existed before and is missing now.
|
|
40
|
+
|
|
41
|
+
`RULES_WEAKENED` is `warning`, not `error`. There are real reasons to delete a predicate: a refactor, a dedupe, an intentional broadening. The signal is "review this", not "refuse the deploy". A human (or a more careful agent) decides whether the removal is intentional.
|
|
42
|
+
|
|
43
|
+
## JavaScript hallucinations
|
|
44
|
+
|
|
45
|
+
LLMs trained primarily on JavaScript will write `.filter()`, `.map()`, `.toLowerCase()`, `===`, `?.`, `??` in rules sources. None of these exist in the Firestore rules DSL. They either fail to parse (with an unhelpful "expected `)`" message) or parse and then fail at runtime (silently denying every request).
|
|
46
|
+
|
|
47
|
+
The pre-parse syntax-hint pass fires on the raw source, before the parser runs, so the diagnostic is precise even when the file is unparseable:
|
|
48
|
+
|
|
49
|
+
- **`INVALID_OPERATOR`**: `===`, `!==`, `?.`, `??`, backtick template literals. Each gets a specific message naming the JS operator and the Firestore-equivalent (or absence of one).
|
|
50
|
+
|
|
51
|
+
The post-parse hallucination pass walks the AST for syntactically-valid-but-semantically-wrong calls:
|
|
52
|
+
|
|
53
|
+
- **`HALLUCINATED_METHOD`**: method calls that don't exist in the rules surface.
|
|
54
|
+
- **`HALLUCINATED_GLOBAL`**: references to globals the engine doesn't expose (`Math`, `JSON`, `Date`).
|
|
55
|
+
- **`WRONG_CONTEXT_PATH`**: `get(...)` calls whose path doesn't begin with `/databases/$(database)/documents/`.
|
|
56
|
+
- **`LENGTH_PROPERTY`**: `.length` access on a string or list (the rules surface uses `.size()`).
|
|
57
|
+
- **`INVALID_PATH_INTERPOLATION`**: match-style `{ident}` used inside a path literal where Firestore requires `$(ident)`.
|
|
58
|
+
- **`METHOD_MISSING_PARENS`**: an identifier in expression position that looks like a method name without parens.
|
|
59
|
+
|
|
60
|
+
Each rule produces a fix string when possible. The agent gets "you wrote `.length`, Firestore wants `.size()`" instead of a generic syntax error.
|
|
61
|
+
|
|
62
|
+
## Time-dependent flakiness
|
|
63
|
+
|
|
64
|
+
A rule reads `request.time` (a date-gated discount window, a trial-period check, an audit-log retention rule). The agent's test case doesn't pin `requestTime`, so the simulator falls back to wallclock. The test passes today, fails three months later when the rule's date threshold has rolled past wallclock. CI starts going red intermittently.
|
|
65
|
+
|
|
66
|
+
`REQUEST_TIME_NOT_PINNED` activates when `options.testCases` is passed to the linter. For each rule that transitively reads `request.time`, the linter emits one warning per test case that targets the rule and doesn't set `requestTime`. The fix is mechanical: add the ISO-8601 string. The diagnostic is precise: it names the rule, the test case, the path.
|
|
67
|
+
|
|
68
|
+
This is the only lint rule that depends on a test suite, and the dependency is opt-in (`options.testCases` defaults to undefined). Source-only calls to the internal `lintFirestoreRules(source)` (or the public `lint(source)` / `firestoreRules(source).lint()`, which never take a test suite at all) behave as they always did.
|
|
69
|
+
|
|
70
|
+
## The shape of these rules
|
|
71
|
+
|
|
72
|
+
Every rule on this page shares three properties:
|
|
73
|
+
|
|
74
|
+
- **It came from observation, not specification.** No one sat down to design `RULES_WEAKENED`; we watched it ship a regression and added the check the next day.
|
|
75
|
+
- **It targets the agent, not the language.** A careful human reading the source would catch most of these on review. The point is to surface them automatically.
|
|
76
|
+
- **It carries a precise fix.** "Your rule is wrong" is a useless diagnostic for an agent looping on the linter's output. "Replace `if true` with `request.auth.uid == resource.data.ownerId`" is something the agent can act on directly.
|
|
77
|
+
|
|
78
|
+
The list is not closed. As we watch new failure modes emerge (typically when a model architecture changes, or a new playground scenario surfaces a recurring mistake), new rules join it.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<!DOCTYPE html><html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Lint vs validate vs simulate vs test · Pyric Studio</title><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet"><link rel="stylesheet" href="/__pyric/ui/_astro/_slug_.CQYSemvw.css"></head> <body> <header class="studio__bar"> <div class="studio__bar-inner"> <a class="studio__brand" href="/__pyric/ui/" aria-label="Pyric Studio">Pyric</a> <nav class="studio__nav" aria-label="Studio tabs"> <a class="studio__nav-tab" href="/__pyric/ui/"> Home </a><a class="studio__nav-tab" href="/__pyric/ui/firestore"> Firestore </a><a class="studio__nav-tab" href="/__pyric/ui/auth"> Auth </a><a class="studio__nav-tab" href="/__pyric/ui/rtdb"> RTDB </a><a class="studio__nav-tab" href="/__pyric/ui/storage"> Storage </a><a class="studio__nav-tab" href="/__pyric/ui/traffic"> Traffic </a><a class="studio__nav-tab" href="/__pyric/ui/settings"> Settings </a><a class="studio__nav-tab" href="/__pyric/ui/docs" aria-current="page"> Docs </a> </nav> </div> </header> <div class="docs-shell"> <details class="docs-nav-drawer"> <summary>Navigate</summary> <nav class="docs-nav" aria-label="Documentation"> <div class="docs-search" data-index-url="/__pyric/ui/docs/index.json"> <div class="docs-search-field"> <svg class="docs-search-icon" viewBox="0 0 16 16" width="14" height="14" aria-hidden="true"> <path d="M11.5 11.5 15 15M13 7A6 6 0 1 1 1 7a6 6 0 0 1 12 0Z" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"></path> </svg> <input type="text" class="docs-search-input" placeholder="Search docs" aria-label="Search docs" autocomplete="off" spellcheck="false"> <kbd class="docs-search-kbd">⌘K</kbd> </div> <ul class="docs-search-results" hidden></ul> </div> <script type="module">let i=null;function d(t){return i||(i=fetch(t).then(e=>e.json())),i}function l(t,e){return t.title.toLowerCase().includes(e)||t.excerpt.toLowerCase().includes(e)?!0:t.headings.some(r=>r.text.toLowerCase().includes(e))}function u(t,e,r){if(e.innerHTML="",t.length===0){e.hidden=!1;{const n=document.createElement("li");n.className="docs-search-empty",n.textContent="No matches",e.appendChild(n)}return}e.hidden=!1;for(const n of t.slice(0,8)){const s=document.createElement("li"),c=document.createElement("a");c.href=n.path;const o=document.createElement("span");o.className="docs-search-result-title",o.textContent=n.title;const a=document.createElement("span");a.className="docs-search-result-meta",a.textContent=[n.group,n.section].filter(Boolean).join(" / "),c.append(o,a),s.appendChild(c),e.appendChild(s)}}document.querySelectorAll(".docs-search").forEach(t=>{const e=t.dataset.indexUrl,r=t.querySelector(".docs-search-input"),n=t.querySelector(".docs-search-results");r.addEventListener("input",async()=>{const s=r.value.trim().toLowerCase();if(!s){n.hidden=!0,n.innerHTML="";return}const{pages:c}=await d(e);r.value.trim().toLowerCase()===s&&u(c.filter(o=>l(o,s)),n)}),r.addEventListener("focus",()=>{d(e),n.childElementCount>0&&(n.hidden=!1)}),r.addEventListener("keydown",s=>{s.key==="Escape"&&(r.value="",n.hidden=!0,n.innerHTML="",r.blur())}),r.addEventListener("blur",()=>{window.setTimeout(()=>{n.hidden=!0},150)})});document.addEventListener("keydown",t=>{if(!(t.metaKey||t.ctrlKey)||t.key.toLowerCase()!=="k")return;const e=[...document.querySelectorAll(".docs-search-input")].find(r=>r.offsetParent!==null);e&&(t.preventDefault(),e.focus(),e.select())});</script> <a class="docs-nav-toplink" href="/__pyric/ui/docs/overview/"> Overview </a><details class="docs-nav-group"> <summary>Run locally</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/start-building/"> Quickstart </a> </li><li> <a href="/__pyric/ui/docs/how-the-swap-works/"> How the swap works </a> </li><li> <a href="/__pyric/ui/docs/set-up-your-agent/"> Connect an agent </a> </li><li> <a href="/__pyric/ui/docs/test-in-node/"> Test in Node </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Develop with Firebase APIs</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/sign-in-and-manage-users/"> Sign in and manage users </a> </li><li> <a href="/__pyric/ui/docs/store-and-query-data/"> Store and query data </a> </li><li> <a href="/__pyric/ui/docs/sync-realtime-data/"> Sync realtime data </a> </li><li> <a href="/__pyric/ui/docs/store-files/"> Store files </a> </li><li> <a href="/__pyric/ui/docs/receive-messages/"> Receive messages </a> </li><li> <a href="/__pyric/ui/docs/run-ai-logic-locally/"> Run AI Logic locally </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-how-to-run-rtdb-onvaluecreated/"> Run an RTDB function locally </a> </li><li> <a href="/__pyric/ui/docs/which-data-service/"> Which data service? </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Inspect and correct</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <h2 class="docs-nav-heading"> Inspect the sandbox </h2> <ul> <li> <a href="/__pyric/ui/docs/see-whats-happening/"> Traffic & rule verdicts </a> </li><li> <a href="/__pyric/ui/docs/read-a-denial/"> Read a denial and understand it </a> </li><li> <a href="/__pyric/ui/docs/shape-your-data/"> Seed, snapshot, replay </a> </li><li> <a href="/__pyric/ui/docs/watch-and-review/"> Review agent activity </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Correct Security Rules </h2> <ul> <li> <a href="/__pyric/ui/docs/secure-it-with-rules/"> Security Rules </a> </li><li> <a href="/__pyric/ui/docs/simulate-and-lint/"> Simulate and lint before you deploy </a> </li><li> <a href="/__pyric/ui/docs/rules-patterns/"> Rules patterns </a> </li><li> <a href="/__pyric/ui/docs/rules-standard-library/"> The rules standard library </a> </li><li> <a href="/__pyric/ui/docs/rtdb-rules-in-typescript/"> RTDB rules in TypeScript </a> </li><li> <a href="/__pyric/ui/docs/firestore-rules-limits/"> Rules limits </a> </li><li> <a href="/__pyric/ui/docs/whats-possible/"> Case studies </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Work with an agent </h2> <ul> <li> <a href="/__pyric/ui/docs/what-your-agent-can-do/"> Work through an agent </a> </li><li> <a href="/__pyric/ui/docs/skills/"> Agent skills </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Verify the boundary</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-cli-how-to-verify-against-a-captured-session/"> Verify a captured session </a> </li><li> <a href="/__pyric/ui/docs/write-a-rules-test-suite/"> Write a rules test suite </a> </li><li> <a href="/__pyric/ui/docs/audit-your-rules/"> Audit rules and data </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Ship unchanged</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/ship-to-production/"> Ship to production </a> </li><li> <a href="/__pyric/ui/docs/set-up-the-project/"> Set up the Firebase project </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Conformance</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/how-we-know-it-matches-firebase/"> Conformance </a> </li><li> <a href="/__pyric/ui/docs/whats-experimental/"> What's experimental </a> </li><li> <a href="/__pyric/ui/docs/pyric-conformance-scores/"> Conformance scores </a> </li><li> <a href="/__pyric/ui/docs/pyric-app-compat/"> App </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-compat/"> Firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-auth-compat/"> Auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-database-compat/"> Realtime Database </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-compat/"> Storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-compat/"> Rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-messaging-compat/"> Messaging </a> </li><li> <a href="/__pyric/ui/docs/pyric-ai-compat/"> AI Logic </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-functions-rtdb-compat/"> Functions · RTDB </a> </li> </ul> </div> </div> </details> <details class="docs-nav-group" open> <summary>Reference</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-cli/"> @pyric/cli </a> </li><li> <a href="/__pyric/ui/docs/pyric-explanation-versioning-and-compatibility/"> pyric </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore/"> pyric / firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules/" aria-current="true"> pyric / rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox/"> pyric / sandbox </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage/"> pyric / storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-auth/"> pyric / auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-database/"> pyric / database </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-app/"> pyric-admin / app </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore/"> pyric-admin / firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-auth/"> pyric-admin / auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-database/"> pyric-admin / database </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-storage/"> pyric-admin / storage </a> </li><li> <a href="/__pyric/ui/docs/ui/"> @pyric/ui </a> </li><li> <a href="/__pyric/ui/docs/api-reference/"> API reference </a> </li> </ul> </div> </div> </details> </nav> </details> <nav class="docs-nav" aria-label="Documentation"> <div class="docs-search" data-index-url="/__pyric/ui/docs/index.json"> <div class="docs-search-field"> <svg class="docs-search-icon" viewBox="0 0 16 16" width="14" height="14" aria-hidden="true"> <path d="M11.5 11.5 15 15M13 7A6 6 0 1 1 1 7a6 6 0 0 1 12 0Z" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"></path> </svg> <input type="text" class="docs-search-input" placeholder="Search docs" aria-label="Search docs" autocomplete="off" spellcheck="false"> <kbd class="docs-search-kbd">⌘K</kbd> </div> <ul class="docs-search-results" hidden></ul> </div> <a class="docs-nav-toplink" href="/__pyric/ui/docs/overview/" id="nav-group-overview"> Overview </a><details class="docs-nav-group" id="nav-group-run-locally"> <summary>Run locally</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/start-building/"> Quickstart </a> </li><li> <a href="/__pyric/ui/docs/how-the-swap-works/"> How the swap works </a> </li><li> <a href="/__pyric/ui/docs/set-up-your-agent/"> Connect an agent </a> </li><li> <a href="/__pyric/ui/docs/test-in-node/"> Test in Node </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-develop-with-firebase-apis"> <summary>Develop with Firebase APIs</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/sign-in-and-manage-users/"> Sign in and manage users </a> </li><li> <a href="/__pyric/ui/docs/store-and-query-data/"> Store and query data </a> </li><li> <a href="/__pyric/ui/docs/sync-realtime-data/"> Sync realtime data </a> </li><li> <a href="/__pyric/ui/docs/store-files/"> Store files </a> </li><li> <a href="/__pyric/ui/docs/receive-messages/"> Receive messages </a> </li><li> <a href="/__pyric/ui/docs/run-ai-logic-locally/"> Run AI Logic locally </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-how-to-run-rtdb-onvaluecreated/"> Run an RTDB function locally </a> </li><li> <a href="/__pyric/ui/docs/which-data-service/"> Which data service? </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-inspect-and-correct"> <summary>Inspect and correct</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-inspect-and-correct-inspect-the-sandbox"> Inspect the sandbox </h2> <ul> <li> <a href="/__pyric/ui/docs/see-whats-happening/"> Traffic & rule verdicts </a> </li><li> <a href="/__pyric/ui/docs/read-a-denial/"> Read a denial and understand it </a> </li><li> <a href="/__pyric/ui/docs/shape-your-data/"> Seed, snapshot, replay </a> </li><li> <a href="/__pyric/ui/docs/watch-and-review/"> Review agent activity </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-inspect-and-correct-correct-security-rules"> Correct Security Rules </h2> <ul> <li> <a href="/__pyric/ui/docs/secure-it-with-rules/"> Security Rules </a> </li><li> <a href="/__pyric/ui/docs/simulate-and-lint/"> Simulate and lint before you deploy </a> </li><li> <a href="/__pyric/ui/docs/rules-patterns/"> Rules patterns </a> </li><li> <a href="/__pyric/ui/docs/rules-standard-library/"> The rules standard library </a> </li><li> <a href="/__pyric/ui/docs/rtdb-rules-in-typescript/"> RTDB rules in TypeScript </a> </li><li> <a href="/__pyric/ui/docs/firestore-rules-limits/"> Rules limits </a> </li><li> <a href="/__pyric/ui/docs/whats-possible/"> Case studies </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-inspect-and-correct-work-with-an-agent"> Work with an agent </h2> <ul> <li> <a href="/__pyric/ui/docs/what-your-agent-can-do/"> Work through an agent </a> </li><li> <a href="/__pyric/ui/docs/skills/"> Agent skills </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-verify-the-boundary"> <summary>Verify the boundary</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-cli-how-to-verify-against-a-captured-session/"> Verify a captured session </a> </li><li> <a href="/__pyric/ui/docs/write-a-rules-test-suite/"> Write a rules test suite </a> </li><li> <a href="/__pyric/ui/docs/audit-your-rules/"> Audit rules and data </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-ship-unchanged"> <summary>Ship unchanged</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/ship-to-production/"> Ship to production </a> </li><li> <a href="/__pyric/ui/docs/set-up-the-project/"> Set up the Firebase project </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-conformance"> <summary>Conformance</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/how-we-know-it-matches-firebase/"> Conformance </a> </li><li> <a href="/__pyric/ui/docs/whats-experimental/"> What's experimental </a> </li><li> <a href="/__pyric/ui/docs/pyric-conformance-scores/"> Conformance scores </a> </li><li> <a href="/__pyric/ui/docs/pyric-app-compat/"> App </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-compat/"> Firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-auth-compat/"> Auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-database-compat/"> Realtime Database </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-compat/"> Storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-compat/"> Rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-messaging-compat/"> Messaging </a> </li><li> <a href="/__pyric/ui/docs/pyric-ai-compat/"> AI Logic </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-functions-rtdb-compat/"> Functions · RTDB </a> </li> </ul> </div> </div> </details> <details class="docs-nav-group" id="nav-group-reference" open> <summary>Reference</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-cli/"> @pyric/cli </a> </li><li> <a href="/__pyric/ui/docs/pyric-explanation-versioning-and-compatibility/"> pyric </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore/"> pyric / firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules/" aria-current="true"> pyric / rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox/"> pyric / sandbox </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage/"> pyric / storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-auth/"> pyric / auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-database/"> pyric / database </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-app/"> pyric-admin / app </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore/"> pyric-admin / firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-auth/"> pyric-admin / auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-database/"> pyric-admin / database </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-storage/"> pyric-admin / storage </a> </li><li> <a href="/__pyric/ui/docs/ui/"> @pyric/ui </a> </li><li> <a href="/__pyric/ui/docs/api-reference/"> API reference </a> </li> </ul> </div> </div> </details> </nav> <main class="doc-main"> <nav class="docs-breadcrumbs" aria-label="Breadcrumb"> <ol> <li> <a href="/__pyric/ui/docs/pyric-rules/">pyric / rules</a> </li><li> <span class="docs-breadcrumbs-sep" aria-hidden="true">/</span> <span>Explanation</span> </li><li> <span class="docs-breadcrumbs-sep" aria-hidden="true">/</span> <span aria-current="page">Lint vs validate vs test</span> </li> </ol> </nav> <article class="prose"> <h1 id="lint-vs-validate-vs-simulate-vs-test">Lint vs validate vs simulate vs test</h1>
|
|
2
|
+
<p>The package offers four distinct ways to look at a rules source. Their names suggest they overlap. They don’t, and the distinction matters when you’re building a CI pipeline or an agent loop.</p>
|
|
3
|
+
<h2 id="lint-structural-risks">Lint: structural risks</h2>
|
|
4
|
+
<p><code>lint(source)</code> (or <code>firestoreRules(source).lint()</code>), both public, answer: <em>“will this ruleset compile? and if it does, will it survive at runtime?”</em> Both are built on the engine-internal linter, <code>lintFirestoreRules</code> (<code>pyric/rules/internal</code>); the public functions fold its output into <code>RuleIssue</code>s with <code>origin: 'lint'</code>.</p>
|
|
5
|
+
<p>The linter walks the AST counting things (chain depths, let bindings, function-call depths, <code>get()</code> counts, expression tree sizes) and compares those numbers to thresholds it learned from production. Some thresholds are exact: 256 KB source size, 98 chain depth, 11 lets per function. Others are bands derived from observing the runtime budget’s behaviour in the flaky zone (40 / 60 / 100 nodes depending on call count).</p>
|
|
6
|
+
<p>The linter also catches a small but high-value set of <em>known agent failure modes</em>: <code>PERMISSIVE_RULE</code>, <code>RECURSIVE_WILDCARD_OPEN</code>, <code>RULES_WEAKENED</code>, <code>HALLUCINATED_METHOD</code>, <code>INVALID_OPERATOR</code>. These were not in the original linter spec. They were added after watching agents repeatedly ship the same broken patterns. See <a href="../pyric-rules-explanation-agent-failure-modes/">Agent failure modes</a> for the stories behind them.</p>
|
|
7
|
+
<p>What linting does <strong>not</strong> tell you: whether your rules behave the way you intend. A rule that compiles, fits the budget, and avoids every agent footgun can still permit something it shouldn’t. That question is for the simulator and the test API.</p>
|
|
8
|
+
<h2 id="validate-security-and-quality-findings">Validate: security and quality findings</h2>
|
|
9
|
+
<p>The engine-internal <code>validateFirestoreRules(ast)</code> (<code>pyric/rules/internal</code>) answers: <em>“would a careful human reviewer flag anything here?”</em> On the public surface its findings arrive folded into the same <code>RuleIssue</code> list as the linter’s, tagged <code>origin: 'validate'</code>. Both <code>lint(source)</code> and <code>firestoreRules(source).lint()</code> run the validator internally, so most callers never call it directly.</p>
|
|
10
|
+
<p>The validator runs structural checks: public writes, unauthenticated writes, missing default-deny, write-without-data-validation, duplicate function names, overlapping match paths. Its findings carry a four-level severity (<code>critical</code> / <code>high</code> / <code>medium</code> / <code>low</code>) and a code (<code>SEC-1</code>, <code>SEM-2</code>, <code>QUA-3</code>, <code>STR-1</code>).</p>
|
|
11
|
+
<p>The validator’s coverage overlaps the linter’s at the edges. <code>QUA-1</code> (hardcoded <code>true</code>) is reported by both, for instance. The two surfaces exist because:</p>
|
|
12
|
+
<ul>
|
|
13
|
+
<li>The linter focuses on <em>operational</em> concerns: will this deploy? will it run within budget? does it look like JavaScript when it shouldn’t?</li>
|
|
14
|
+
<li>The validator focuses on <em>review</em> concerns: is this safe? is this clean? is this consistent?</li>
|
|
15
|
+
</ul>
|
|
16
|
+
<p>In practice, run both. Their findings union without redundancy in most cases.</p>
|
|
17
|
+
<h2 id="simulate-does-the-rule-decide-correctly-locally">Simulate: does the rule decide correctly, locally?</h2>
|
|
18
|
+
<p><code>firestoreRules(source).simulate(cases)</code> answers: <em>“given these requests, what does the rule decide?”</em></p>
|
|
19
|
+
<p>The simulator parses the rules, builds a <code>SimulationContext</code> from each case, walks every expression with a hand-written evaluator, and produces an <code>ALLOW</code> / <code>DENY</code> decision (or reports the case as unsupported if it doesn’t yet model some feature). You compare the decision to your expectation and learn whether your rule does the right thing for the inputs you care about.</p>
|
|
20
|
+
<p>The simulator is sub-millisecond per case once parsed. It is the right surface for:</p>
|
|
21
|
+
<ul>
|
|
22
|
+
<li>Agent loops that iterate on a rule and need fast feedback.</li>
|
|
23
|
+
<li>CI checks that exercise hundreds of test cases on every PR.</li>
|
|
24
|
+
<li>Local development without a Firebase project.</li>
|
|
25
|
+
</ul>
|
|
26
|
+
<p>It is <strong>not</strong> the right surface when:</p>
|
|
27
|
+
<ul>
|
|
28
|
+
<li>A case comes back unsupported and you need a verdict the simulator can’t give you.</li>
|
|
29
|
+
<li>You’re shipping rules that must behave exactly like production. The simulator is close to bit-for-bit parity, but not bit-for-bit.</li>
|
|
30
|
+
</ul>
|
|
31
|
+
<h2 id="test-does-the-live-firestore-engine-agree">Test: does the live Firestore engine agree?</h2>
|
|
32
|
+
<p>The engine-internal <code>TestFirestoreRulesHandler.execute(scope, source, testCases)</code> (<code>pyric/rules/internal</code>) answers: <em>“would production decide the same way?”</em> There’s no public front-door equivalent yet.</p>
|
|
33
|
+
<p>This calls Google’s Firebase Rules Test API. The request goes to Google’s servers, the rules are evaluated in the production engine, and you get pass/fail per case. The test API never deploys anything (it’s a pure evaluation surface), but it costs HTTP latency and requires a service-account credential.</p>
|
|
34
|
+
<p>Use it when:</p>
|
|
35
|
+
<ul>
|
|
36
|
+
<li>You’re about to deploy and want certainty.</li>
|
|
37
|
+
<li>The simulator returned <code>UNSUPPORTED</code> and you need a verdict.</li>
|
|
38
|
+
<li>You’re investigating a discrepancy between local and production behaviour.</li>
|
|
39
|
+
</ul>
|
|
40
|
+
<h2 id="which-surface-for-which-question">Which surface for which question</h2>
|
|
41
|
+
<div class="table-scroll">
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
<table><thead><tr><th>Question</th><th>Surface</th></tr></thead><tbody><tr><td>Will this compile?</td><td>Lint (<code>SOURCE_SIZE</code>, <code>CHAIN_DEPTH</code>, <code>LET_LIMIT</code>)</td></tr><tr><td>Will this survive the runtime budget?</td><td>Lint (<code>EXPRESSION_BUDGET</code>, <code>CALL_DEPTH</code>, <code>GET_COUNT</code>, <code>SHARED_GATE</code>)</td></tr><tr><td>Did the agent open the database again?</td><td>Lint (<code>PERMISSIVE_RULE</code>, <code>RECURSIVE_WILDCARD_OPEN</code>)</td></tr><tr><td>Did anyone silently weaken security?</td><td>Lint with <code>previousSource</code> (<code>RULES_WEAKENED</code>)</td></tr><tr><td>Would a reviewer flag this?</td><td>Validate (<code>SEC</code> / <code>SEM</code> / <code>QUA</code> / <code>STR</code>)</td></tr><tr><td>Does the rule decide what I think it does?</td><td>Simulate</td></tr><tr><td>Does the production engine agree?</td><td>Test</td></tr></tbody></table></div>
|
|
79
|
+
<p>A complete pipeline tends to look like: validate + lint (block on errors), simulate (verify intended behaviour locally), test (parity check before deploy, or when simulator abstains).</p> </article> </main> <aside class="doc-toc" aria-label="On this page"> <h2 class="doc-toc-heading">On this page</h2> <ul> <li data-depth="2"> <a href="#lint-structural-risks">Lint: structural risks</a> </li><li data-depth="2"> <a href="#validate-security-and-quality-findings">Validate: security and quality findings</a> </li><li data-depth="2"> <a href="#simulate-does-the-rule-decide-correctly-locally">Simulate: does the rule decide correctly, locally?</a> </li><li data-depth="2"> <a href="#test-does-the-live-firestore-engine-agree">Test: does the live Firestore engine agree?</a> </li><li data-depth="2"> <a href="#which-surface-for-which-question">Which surface for which question</a> </li> </ul> </aside> </div> <script type="module">const a=document.querySelector("[data-api-symbol-filter]"),d=[...document.querySelectorAll("[data-api-symbol-group]")],n=document.querySelector("[data-api-symbol-empty]");a?.addEventListener("input",()=>{const t=a.value.trim().toLowerCase();let o=0;for(const i of d){let e=0;i.querySelectorAll("[data-api-symbol]").forEach(l=>{const r=!t||(l.dataset.apiSymbol??"").includes(t);l.hidden=!r,r&&e++}),i.hidden=e===0,o+=e}n&&(n.hidden=o>0)});</script> <script type="module">const s=new Map;document.querySelectorAll('.doc-toc a[href^="#"]').forEach(t=>s.set(decodeURIComponent(t.hash.slice(1)),t));if(s.size>0){const t=new Set,n=()=>{let o=null;for(const e of s.keys())if(t.has(e)){o=e;break}s.forEach((e,c)=>e.classList.toggle("active",c===o))},r=new IntersectionObserver(o=>{for(const e of o)e.isIntersecting?t.add(e.target.id):t.delete(e.target.id);n()},{rootMargin:"-72px 0px -60% 0px"});s.forEach((o,e)=>{const c=document.getElementById(e);c&&r.observe(c)})}</script> <script type="module">document.querySelector('.studio__nav [aria-current="page"]')?.scrollIntoView({block:"nearest",inline:"center"});</script> </body> </html>
|
package/dist/serve/docs-ui/docs/pyric-rules-explanation-lint-vs-validate-vs-simulate-vs-test.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Lint vs validate vs simulate vs test
|
|
2
|
+
|
|
3
|
+
The package offers four distinct ways to look at a rules source. Their names suggest they overlap. They don't, and the distinction matters when you're building a CI pipeline or an agent loop.
|
|
4
|
+
|
|
5
|
+
## Lint: structural risks
|
|
6
|
+
|
|
7
|
+
`lint(source)` (or `firestoreRules(source).lint()`), both public, answer: *"will this ruleset compile? and if it does, will it survive at runtime?"* Both are built on the engine-internal linter, `lintFirestoreRules` (`pyric/rules/internal`); the public functions fold its output into `RuleIssue`s with `origin: 'lint'`.
|
|
8
|
+
|
|
9
|
+
The linter walks the AST counting things (chain depths, let bindings, function-call depths, `get()` counts, expression tree sizes) and compares those numbers to thresholds it learned from production. Some thresholds are exact: 256 KB source size, 98 chain depth, 11 lets per function. Others are bands derived from observing the runtime budget's behaviour in the flaky zone (40 / 60 / 100 nodes depending on call count).
|
|
10
|
+
|
|
11
|
+
The linter also catches a small but high-value set of *known agent failure modes*: `PERMISSIVE_RULE`, `RECURSIVE_WILDCARD_OPEN`, `RULES_WEAKENED`, `HALLUCINATED_METHOD`, `INVALID_OPERATOR`. These were not in the original linter spec. They were added after watching agents repeatedly ship the same broken patterns. See [Agent failure modes](../pyric-rules-explanation-agent-failure-modes/) for the stories behind them.
|
|
12
|
+
|
|
13
|
+
What linting does **not** tell you: whether your rules behave the way you intend. A rule that compiles, fits the budget, and avoids every agent footgun can still permit something it shouldn't. That question is for the simulator and the test API.
|
|
14
|
+
|
|
15
|
+
## Validate: security and quality findings
|
|
16
|
+
|
|
17
|
+
The engine-internal `validateFirestoreRules(ast)` (`pyric/rules/internal`) answers: *"would a careful human reviewer flag anything here?"* On the public surface its findings arrive folded into the same `RuleIssue` list as the linter's, tagged `origin: 'validate'`. Both `lint(source)` and `firestoreRules(source).lint()` run the validator internally, so most callers never call it directly.
|
|
18
|
+
|
|
19
|
+
The validator runs structural checks: public writes, unauthenticated writes, missing default-deny, write-without-data-validation, duplicate function names, overlapping match paths. Its findings carry a four-level severity (`critical` / `high` / `medium` / `low`) and a code (`SEC-1`, `SEM-2`, `QUA-3`, `STR-1`).
|
|
20
|
+
|
|
21
|
+
The validator's coverage overlaps the linter's at the edges. `QUA-1` (hardcoded `true`) is reported by both, for instance. The two surfaces exist because:
|
|
22
|
+
|
|
23
|
+
- The linter focuses on *operational* concerns: will this deploy? will it run within budget? does it look like JavaScript when it shouldn't?
|
|
24
|
+
- The validator focuses on *review* concerns: is this safe? is this clean? is this consistent?
|
|
25
|
+
|
|
26
|
+
In practice, run both. Their findings union without redundancy in most cases.
|
|
27
|
+
|
|
28
|
+
## Simulate: does the rule decide correctly, locally?
|
|
29
|
+
|
|
30
|
+
`firestoreRules(source).simulate(cases)` answers: *"given these requests, what does the rule decide?"*
|
|
31
|
+
|
|
32
|
+
The simulator parses the rules, builds a `SimulationContext` from each case, walks every expression with a hand-written evaluator, and produces an `ALLOW` / `DENY` decision (or reports the case as unsupported if it doesn't yet model some feature). You compare the decision to your expectation and learn whether your rule does the right thing for the inputs you care about.
|
|
33
|
+
|
|
34
|
+
The simulator is sub-millisecond per case once parsed. It is the right surface for:
|
|
35
|
+
|
|
36
|
+
- Agent loops that iterate on a rule and need fast feedback.
|
|
37
|
+
- CI checks that exercise hundreds of test cases on every PR.
|
|
38
|
+
- Local development without a Firebase project.
|
|
39
|
+
|
|
40
|
+
It is **not** the right surface when:
|
|
41
|
+
|
|
42
|
+
- A case comes back unsupported and you need a verdict the simulator can't give you.
|
|
43
|
+
- You're shipping rules that must behave exactly like production. The simulator is close to bit-for-bit parity, but not bit-for-bit.
|
|
44
|
+
|
|
45
|
+
## Test: does the live Firestore engine agree?
|
|
46
|
+
|
|
47
|
+
The engine-internal `TestFirestoreRulesHandler.execute(scope, source, testCases)` (`pyric/rules/internal`) answers: *"would production decide the same way?"* There's no public front-door equivalent yet.
|
|
48
|
+
|
|
49
|
+
This calls Google's Firebase Rules Test API. The request goes to Google's servers, the rules are evaluated in the production engine, and you get pass/fail per case. The test API never deploys anything (it's a pure evaluation surface), but it costs HTTP latency and requires a service-account credential.
|
|
50
|
+
|
|
51
|
+
Use it when:
|
|
52
|
+
|
|
53
|
+
- You're about to deploy and want certainty.
|
|
54
|
+
- The simulator returned `UNSUPPORTED` and you need a verdict.
|
|
55
|
+
- You're investigating a discrepancy between local and production behaviour.
|
|
56
|
+
|
|
57
|
+
## Which surface for which question
|
|
58
|
+
|
|
59
|
+
| Question | Surface |
|
|
60
|
+
|---|---|
|
|
61
|
+
| Will this compile? | Lint (`SOURCE_SIZE`, `CHAIN_DEPTH`, `LET_LIMIT`) |
|
|
62
|
+
| Will this survive the runtime budget? | Lint (`EXPRESSION_BUDGET`, `CALL_DEPTH`, `GET_COUNT`, `SHARED_GATE`) |
|
|
63
|
+
| Did the agent open the database again? | Lint (`PERMISSIVE_RULE`, `RECURSIVE_WILDCARD_OPEN`) |
|
|
64
|
+
| Did anyone silently weaken security? | Lint with `previousSource` (`RULES_WEAKENED`) |
|
|
65
|
+
| Would a reviewer flag this? | Validate (`SEC` / `SEM` / `QUA` / `STR`) |
|
|
66
|
+
| Does the rule decide what I think it does? | Simulate |
|
|
67
|
+
| Does the production engine agree? | Test |
|
|
68
|
+
|
|
69
|
+
A complete pipeline tends to look like: validate + lint (block on errors), simulate (verify intended behaviour locally), test (parity check before deploy, or when simulator abstains).
|
package/dist/serve/docs-ui/docs/pyric-rules-explanation-runtime-budget-and-shared-gates/index.html
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<!DOCTYPE html><html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>The runtime budget and shared gates · Pyric Studio</title><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet"><link rel="stylesheet" href="/__pyric/ui/_astro/_slug_.CQYSemvw.css"></head> <body> <header class="studio__bar"> <div class="studio__bar-inner"> <a class="studio__brand" href="/__pyric/ui/" aria-label="Pyric Studio">Pyric</a> <nav class="studio__nav" aria-label="Studio tabs"> <a class="studio__nav-tab" href="/__pyric/ui/"> Home </a><a class="studio__nav-tab" href="/__pyric/ui/firestore"> Firestore </a><a class="studio__nav-tab" href="/__pyric/ui/auth"> Auth </a><a class="studio__nav-tab" href="/__pyric/ui/rtdb"> RTDB </a><a class="studio__nav-tab" href="/__pyric/ui/storage"> Storage </a><a class="studio__nav-tab" href="/__pyric/ui/traffic"> Traffic </a><a class="studio__nav-tab" href="/__pyric/ui/settings"> Settings </a><a class="studio__nav-tab" href="/__pyric/ui/docs" aria-current="page"> Docs </a> </nav> </div> </header> <div class="docs-shell"> <details class="docs-nav-drawer"> <summary>Navigate</summary> <nav class="docs-nav" aria-label="Documentation"> <div class="docs-search" data-index-url="/__pyric/ui/docs/index.json"> <div class="docs-search-field"> <svg class="docs-search-icon" viewBox="0 0 16 16" width="14" height="14" aria-hidden="true"> <path d="M11.5 11.5 15 15M13 7A6 6 0 1 1 1 7a6 6 0 0 1 12 0Z" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"></path> </svg> <input type="text" class="docs-search-input" placeholder="Search docs" aria-label="Search docs" autocomplete="off" spellcheck="false"> <kbd class="docs-search-kbd">⌘K</kbd> </div> <ul class="docs-search-results" hidden></ul> </div> <script type="module">let i=null;function d(t){return i||(i=fetch(t).then(e=>e.json())),i}function l(t,e){return t.title.toLowerCase().includes(e)||t.excerpt.toLowerCase().includes(e)?!0:t.headings.some(r=>r.text.toLowerCase().includes(e))}function u(t,e,r){if(e.innerHTML="",t.length===0){e.hidden=!1;{const n=document.createElement("li");n.className="docs-search-empty",n.textContent="No matches",e.appendChild(n)}return}e.hidden=!1;for(const n of t.slice(0,8)){const s=document.createElement("li"),c=document.createElement("a");c.href=n.path;const o=document.createElement("span");o.className="docs-search-result-title",o.textContent=n.title;const a=document.createElement("span");a.className="docs-search-result-meta",a.textContent=[n.group,n.section].filter(Boolean).join(" / "),c.append(o,a),s.appendChild(c),e.appendChild(s)}}document.querySelectorAll(".docs-search").forEach(t=>{const e=t.dataset.indexUrl,r=t.querySelector(".docs-search-input"),n=t.querySelector(".docs-search-results");r.addEventListener("input",async()=>{const s=r.value.trim().toLowerCase();if(!s){n.hidden=!0,n.innerHTML="";return}const{pages:c}=await d(e);r.value.trim().toLowerCase()===s&&u(c.filter(o=>l(o,s)),n)}),r.addEventListener("focus",()=>{d(e),n.childElementCount>0&&(n.hidden=!1)}),r.addEventListener("keydown",s=>{s.key==="Escape"&&(r.value="",n.hidden=!0,n.innerHTML="",r.blur())}),r.addEventListener("blur",()=>{window.setTimeout(()=>{n.hidden=!0},150)})});document.addEventListener("keydown",t=>{if(!(t.metaKey||t.ctrlKey)||t.key.toLowerCase()!=="k")return;const e=[...document.querySelectorAll(".docs-search-input")].find(r=>r.offsetParent!==null);e&&(t.preventDefault(),e.focus(),e.select())});</script> <a class="docs-nav-toplink" href="/__pyric/ui/docs/overview/"> Overview </a><details class="docs-nav-group"> <summary>Run locally</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/start-building/"> Quickstart </a> </li><li> <a href="/__pyric/ui/docs/how-the-swap-works/"> How the swap works </a> </li><li> <a href="/__pyric/ui/docs/set-up-your-agent/"> Connect an agent </a> </li><li> <a href="/__pyric/ui/docs/test-in-node/"> Test in Node </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Develop with Firebase APIs</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/sign-in-and-manage-users/"> Sign in and manage users </a> </li><li> <a href="/__pyric/ui/docs/store-and-query-data/"> Store and query data </a> </li><li> <a href="/__pyric/ui/docs/sync-realtime-data/"> Sync realtime data </a> </li><li> <a href="/__pyric/ui/docs/store-files/"> Store files </a> </li><li> <a href="/__pyric/ui/docs/receive-messages/"> Receive messages </a> </li><li> <a href="/__pyric/ui/docs/run-ai-logic-locally/"> Run AI Logic locally </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-how-to-run-rtdb-onvaluecreated/"> Run an RTDB function locally </a> </li><li> <a href="/__pyric/ui/docs/which-data-service/"> Which data service? </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Inspect and correct</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <h2 class="docs-nav-heading"> Inspect the sandbox </h2> <ul> <li> <a href="/__pyric/ui/docs/see-whats-happening/"> Traffic & rule verdicts </a> </li><li> <a href="/__pyric/ui/docs/read-a-denial/"> Read a denial and understand it </a> </li><li> <a href="/__pyric/ui/docs/shape-your-data/"> Seed, snapshot, replay </a> </li><li> <a href="/__pyric/ui/docs/watch-and-review/"> Review agent activity </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Correct Security Rules </h2> <ul> <li> <a href="/__pyric/ui/docs/secure-it-with-rules/"> Security Rules </a> </li><li> <a href="/__pyric/ui/docs/simulate-and-lint/"> Simulate and lint before you deploy </a> </li><li> <a href="/__pyric/ui/docs/rules-patterns/"> Rules patterns </a> </li><li> <a href="/__pyric/ui/docs/rules-standard-library/"> The rules standard library </a> </li><li> <a href="/__pyric/ui/docs/rtdb-rules-in-typescript/"> RTDB rules in TypeScript </a> </li><li> <a href="/__pyric/ui/docs/firestore-rules-limits/"> Rules limits </a> </li><li> <a href="/__pyric/ui/docs/whats-possible/"> Case studies </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading"> Work with an agent </h2> <ul> <li> <a href="/__pyric/ui/docs/what-your-agent-can-do/"> Work through an agent </a> </li><li> <a href="/__pyric/ui/docs/skills/"> Agent skills </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Verify the boundary</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-cli-how-to-verify-against-a-captured-session/"> Verify a captured session </a> </li><li> <a href="/__pyric/ui/docs/write-a-rules-test-suite/"> Write a rules test suite </a> </li><li> <a href="/__pyric/ui/docs/audit-your-rules/"> Audit rules and data </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Ship unchanged</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/ship-to-production/"> Ship to production </a> </li><li> <a href="/__pyric/ui/docs/set-up-the-project/"> Set up the Firebase project </a> </li> </ul> </div> </div> </details><details class="docs-nav-group"> <summary>Conformance</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/how-we-know-it-matches-firebase/"> Conformance </a> </li><li> <a href="/__pyric/ui/docs/whats-experimental/"> What's experimental </a> </li><li> <a href="/__pyric/ui/docs/pyric-conformance-scores/"> Conformance scores </a> </li><li> <a href="/__pyric/ui/docs/pyric-app-compat/"> App </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-compat/"> Firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-auth-compat/"> Auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-database-compat/"> Realtime Database </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-compat/"> Storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-compat/"> Rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-messaging-compat/"> Messaging </a> </li><li> <a href="/__pyric/ui/docs/pyric-ai-compat/"> AI Logic </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-functions-rtdb-compat/"> Functions · RTDB </a> </li> </ul> </div> </div> </details> <details class="docs-nav-group" open> <summary>Reference</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-cli/"> @pyric/cli </a> </li><li> <a href="/__pyric/ui/docs/pyric-explanation-versioning-and-compatibility/"> pyric </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore/"> pyric / firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules/" aria-current="true"> pyric / rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox/"> pyric / sandbox </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage/"> pyric / storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-auth/"> pyric / auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-database/"> pyric / database </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-app/"> pyric-admin / app </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore/"> pyric-admin / firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-auth/"> pyric-admin / auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-database/"> pyric-admin / database </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-storage/"> pyric-admin / storage </a> </li><li> <a href="/__pyric/ui/docs/ui/"> @pyric/ui </a> </li><li> <a href="/__pyric/ui/docs/api-reference/"> API reference </a> </li> </ul> </div> </div> </details> </nav> </details> <nav class="docs-nav" aria-label="Documentation"> <div class="docs-search" data-index-url="/__pyric/ui/docs/index.json"> <div class="docs-search-field"> <svg class="docs-search-icon" viewBox="0 0 16 16" width="14" height="14" aria-hidden="true"> <path d="M11.5 11.5 15 15M13 7A6 6 0 1 1 1 7a6 6 0 0 1 12 0Z" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"></path> </svg> <input type="text" class="docs-search-input" placeholder="Search docs" aria-label="Search docs" autocomplete="off" spellcheck="false"> <kbd class="docs-search-kbd">⌘K</kbd> </div> <ul class="docs-search-results" hidden></ul> </div> <a class="docs-nav-toplink" href="/__pyric/ui/docs/overview/" id="nav-group-overview"> Overview </a><details class="docs-nav-group" id="nav-group-run-locally"> <summary>Run locally</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/start-building/"> Quickstart </a> </li><li> <a href="/__pyric/ui/docs/how-the-swap-works/"> How the swap works </a> </li><li> <a href="/__pyric/ui/docs/set-up-your-agent/"> Connect an agent </a> </li><li> <a href="/__pyric/ui/docs/test-in-node/"> Test in Node </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-develop-with-firebase-apis"> <summary>Develop with Firebase APIs</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/sign-in-and-manage-users/"> Sign in and manage users </a> </li><li> <a href="/__pyric/ui/docs/store-and-query-data/"> Store and query data </a> </li><li> <a href="/__pyric/ui/docs/sync-realtime-data/"> Sync realtime data </a> </li><li> <a href="/__pyric/ui/docs/store-files/"> Store files </a> </li><li> <a href="/__pyric/ui/docs/receive-messages/"> Receive messages </a> </li><li> <a href="/__pyric/ui/docs/run-ai-logic-locally/"> Run AI Logic locally </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-how-to-run-rtdb-onvaluecreated/"> Run an RTDB function locally </a> </li><li> <a href="/__pyric/ui/docs/which-data-service/"> Which data service? </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-inspect-and-correct"> <summary>Inspect and correct</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-inspect-and-correct-inspect-the-sandbox"> Inspect the sandbox </h2> <ul> <li> <a href="/__pyric/ui/docs/see-whats-happening/"> Traffic & rule verdicts </a> </li><li> <a href="/__pyric/ui/docs/read-a-denial/"> Read a denial and understand it </a> </li><li> <a href="/__pyric/ui/docs/shape-your-data/"> Seed, snapshot, replay </a> </li><li> <a href="/__pyric/ui/docs/watch-and-review/"> Review agent activity </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-inspect-and-correct-correct-security-rules"> Correct Security Rules </h2> <ul> <li> <a href="/__pyric/ui/docs/secure-it-with-rules/"> Security Rules </a> </li><li> <a href="/__pyric/ui/docs/simulate-and-lint/"> Simulate and lint before you deploy </a> </li><li> <a href="/__pyric/ui/docs/rules-patterns/"> Rules patterns </a> </li><li> <a href="/__pyric/ui/docs/rules-standard-library/"> The rules standard library </a> </li><li> <a href="/__pyric/ui/docs/rtdb-rules-in-typescript/"> RTDB rules in TypeScript </a> </li><li> <a href="/__pyric/ui/docs/firestore-rules-limits/"> Rules limits </a> </li><li> <a href="/__pyric/ui/docs/whats-possible/"> Case studies </a> </li> </ul> </div><div class="docs-nav-section"> <h2 class="docs-nav-heading" id="nav-section-inspect-and-correct-work-with-an-agent"> Work with an agent </h2> <ul> <li> <a href="/__pyric/ui/docs/what-your-agent-can-do/"> Work through an agent </a> </li><li> <a href="/__pyric/ui/docs/skills/"> Agent skills </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-verify-the-boundary"> <summary>Verify the boundary</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-cli-how-to-verify-against-a-captured-session/"> Verify a captured session </a> </li><li> <a href="/__pyric/ui/docs/write-a-rules-test-suite/"> Write a rules test suite </a> </li><li> <a href="/__pyric/ui/docs/audit-your-rules/"> Audit rules and data </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-ship-unchanged"> <summary>Ship unchanged</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/ship-to-production/"> Ship to production </a> </li><li> <a href="/__pyric/ui/docs/set-up-the-project/"> Set up the Firebase project </a> </li> </ul> </div> </div> </details><details class="docs-nav-group" id="nav-group-conformance"> <summary>Conformance</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/how-we-know-it-matches-firebase/"> Conformance </a> </li><li> <a href="/__pyric/ui/docs/whats-experimental/"> What's experimental </a> </li><li> <a href="/__pyric/ui/docs/pyric-conformance-scores/"> Conformance scores </a> </li><li> <a href="/__pyric/ui/docs/pyric-app-compat/"> App </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore-compat/"> Firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-auth-compat/"> Auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-database-compat/"> Realtime Database </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage-compat/"> Storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules-compat/"> Rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-messaging-compat/"> Messaging </a> </li><li> <a href="/__pyric/ui/docs/pyric-ai-compat/"> AI Logic </a> </li><li> <a href="/__pyric/ui/docs/pyric-cli-functions-rtdb-compat/"> Functions · RTDB </a> </li> </ul> </div> </div> </details> <details class="docs-nav-group" id="nav-group-reference" open> <summary>Reference</summary> <div class="docs-nav-group-body"> <div class="docs-nav-section"> <ul> <li> <a href="/__pyric/ui/docs/pyric-cli/"> @pyric/cli </a> </li><li> <a href="/__pyric/ui/docs/pyric-explanation-versioning-and-compatibility/"> pyric </a> </li><li> <a href="/__pyric/ui/docs/pyric-firestore/"> pyric / firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-rules/" aria-current="true"> pyric / rules </a> </li><li> <a href="/__pyric/ui/docs/pyric-sandbox/"> pyric / sandbox </a> </li><li> <a href="/__pyric/ui/docs/pyric-storage/"> pyric / storage </a> </li><li> <a href="/__pyric/ui/docs/pyric-auth/"> pyric / auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-database/"> pyric / database </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-app/"> pyric-admin / app </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-firestore/"> pyric-admin / firestore </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-auth/"> pyric-admin / auth </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-database/"> pyric-admin / database </a> </li><li> <a href="/__pyric/ui/docs/pyric-admin-storage/"> pyric-admin / storage </a> </li><li> <a href="/__pyric/ui/docs/ui/"> @pyric/ui </a> </li><li> <a href="/__pyric/ui/docs/api-reference/"> API reference </a> </li> </ul> </div> </div> </details> </nav> <main class="doc-main"> <nav class="docs-breadcrumbs" aria-label="Breadcrumb"> <ol> <li> <a href="/__pyric/ui/docs/pyric-rules/">pyric / rules</a> </li><li> <span class="docs-breadcrumbs-sep" aria-hidden="true">/</span> <span>Explanation</span> </li><li> <span class="docs-breadcrumbs-sep" aria-hidden="true">/</span> <span aria-current="page">Runtime budget and gates</span> </li> </ol> </nav> <article class="prose"> <h1 id="the-runtime-budget-and-shared-gates">The runtime budget and shared gates</h1>
|
|
2
|
+
<p>Firestore rules have two kinds of limits. Compilation limits fail loudly: a <code>400 INVALID_ARGUMENT</code> at deploy. The runtime evaluation budget fails silently: a <code>403 PERMISSION_DENIED</code> that looks identical to a denied rule.</p>
|
|
3
|
+
<p>The compile-time limits have exact values. The runtime limits do not. Everything on this page is researched and observed behavior discovered by Pyric’s tooling, and it explains why the linter’s thresholds look the way they do.</p>
|
|
4
|
+
<h2 id="the-exact-limits">The exact limits</h2>
|
|
5
|
+
<p>Three hard caps that Firebase enforces at deploy time:</p>
|
|
6
|
+
<ul>
|
|
7
|
+
<li><strong>256 KB source.</strong> Exact byte limit. Anything longer is rejected outright.</li>
|
|
8
|
+
<li><strong>Chain depth 98.</strong> A flat <code>a && b && c && … && z</code> chain of length 99 or more refuses to compile. The limit is on chain depth, not total nodes: <code>(a && b) && (c && d)</code> has chain depth 1 of <code>&&</code>-of-<code>&&</code>s. Wrapping reduces depth.</li>
|
|
9
|
+
<li><strong>11 let bindings per function.</strong> A function with 12 lets fails to compile.</li>
|
|
10
|
+
</ul>
|
|
11
|
+
<p>These were verified in production by deliberately building rulesets that crossed each threshold by one. The linter encodes the exact values; you get a clear error when you approach or hit them.</p>
|
|
12
|
+
<h2 id="the-hard-limit">The hard limit</h2>
|
|
13
|
+
<p>Beyond those three caps, every rule evaluation runs against a runtime budget. If the budget is exhausted, the engine denies the request with no diagnostic. The request looks identical to one your <code>allow</code> rule rejected. The exhaustion is silent, and silent failures are the worst kind to debug.</p>
|
|
14
|
+
<p>The budget is not a simple “you can evaluate N expressions” rule. Empirically:</p>
|
|
15
|
+
<ul>
|
|
16
|
+
<li><strong>One function call with 98 expressions</strong> passes reliably (5/5 in our production tests).</li>
|
|
17
|
+
<li><strong>Two function calls with 120 total expressions</strong> passes reliably (5/5).</li>
|
|
18
|
+
<li><strong>Two function calls with 130 total</strong> is <strong>flaky</strong> (2/5 pass).</li>
|
|
19
|
+
<li><strong>Three function calls with 60 total expressions</strong> is <strong>flaky</strong> (2/5 pass).</li>
|
|
20
|
+
<li><strong>Three function calls with 90 total</strong> is mostly stable (4/5).</li>
|
|
21
|
+
</ul>
|
|
22
|
+
<p>The pattern: function-call overhead dominates. Each call eats a non-trivial chunk of the budget. Three thin calls can fail where one fat call would succeed.</p>
|
|
23
|
+
<p>Reverse-engineering: <code>available = base − (call_count × call_overhead)</code>. We don’t know <code>base</code> or <code>call_overhead</code> exactly. Firestore’s evaluation has a non-deterministic flaky zone where the same ruleset will sometimes pass and sometimes fail. The linter’s thresholds are deliberately conservative inside the flaky zone:</p>
|
|
24
|
+
<div class="table-scroll">
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
<table><thead><tr><th>Function calls in rule</th><th>Warn at</th><th>Error at</th></tr></thead><tbody><tr><td>1 or 2</td><td>100 expressions</td><td>120</td></tr><tr><td>3</td><td>60</td><td>90</td></tr><tr><td>4+</td><td>40</td><td>60</td></tr></tbody></table></div>
|
|
50
|
+
<p>These over-flag. Some rules in the flaky zone work in practice. The alternative is under-flagging and shipping rules that work in dev and fail under load.</p>
|
|
51
|
+
<h2 id="shared-gates">Shared gates</h2>
|
|
52
|
+
<p>Even with a single rule sitting comfortably inside its budget, two rules in the same match block can collectively blow it. This is the “shared gate” problem, and the linter’s <code>SHARED_GATE</code> warning exists because it took an entire weekend of chess debugging to figure out.</p>
|
|
53
|
+
<p>The scenario: two <code>allow update</code> rules whose conditions both start with the same first expression, say <code>request.auth.uid == resource.data.host</code>. The engine evaluates each rule against the request. Even though only one rule actually applies, the prefix evaluation happens in both. If each rule’s body is near the budget on its own, their combined evaluation crosses the line.</p>
|
|
54
|
+
<p>The fix is to give each rule a unique first expression, a discriminator. Instead of:</p>
|
|
55
|
+
<pre class="astro-code one-dark-pro" style="background-color:#282c34;color:#abb2bf; overflow-x: auto;" tabindex="0" data-language="rules"><code><span class="line"><span style="color:#C678DD">allow</span><span style="color:#61AFEF"> update</span><span style="color:#ABB2BF">: </span><span style="color:#C678DD">if</span><span style="color:#E5C07B"> request</span><span style="color:#ABB2BF">.auth.uid == </span><span style="color:#E5C07B">resource</span><span style="color:#ABB2BF">.data.host && validBigCheckA();</span></span>
|
|
56
|
+
<span class="line"><span style="color:#C678DD">allow</span><span style="color:#61AFEF"> update</span><span style="color:#ABB2BF">: </span><span style="color:#C678DD">if</span><span style="color:#E5C07B"> request</span><span style="color:#ABB2BF">.auth.uid == </span><span style="color:#E5C07B">resource</span><span style="color:#ABB2BF">.data.host && validBigCheckB();</span></span></code></pre>
|
|
57
|
+
<p>route on something distinct:</p>
|
|
58
|
+
<pre class="astro-code one-dark-pro" style="background-color:#282c34;color:#abb2bf; overflow-x: auto;" tabindex="0" data-language="rules"><code><span class="line"><span style="color:#C678DD">allow</span><span style="color:#61AFEF"> update</span><span style="color:#ABB2BF">: </span><span style="color:#C678DD">if</span><span style="color:#E5C07B"> request</span><span style="color:#ABB2BF">.</span><span style="color:#E5C07B">resource</span><span style="color:#ABB2BF">.data.moveType == </span><span style="color:#98C379">'A'</span><span style="color:#ABB2BF"> && validBigCheckA();</span></span>
|
|
59
|
+
<span class="line"><span style="color:#C678DD">allow</span><span style="color:#61AFEF"> update</span><span style="color:#ABB2BF">: </span><span style="color:#C678DD">if</span><span style="color:#E5C07B"> request</span><span style="color:#ABB2BF">.</span><span style="color:#E5C07B">resource</span><span style="color:#ABB2BF">.data.moveType == </span><span style="color:#98C379">'B'</span><span style="color:#ABB2BF"> && validBigCheckB();</span></span></code></pre>
|
|
60
|
+
<p>Now each rule short-circuits before its heavy body runs, and the engine doesn’t end up evaluating both bodies in parallel.</p>
|
|
61
|
+
<p>The linter detects <code>SHARED_GATE</code> by computing a structural fingerprint of every rule’s first expression and grouping by fingerprint. Two or more rules with the same fingerprint produce a warning.</p>
|
|
62
|
+
<h2 id="get-call-costs">Get-call costs</h2>
|
|
63
|
+
<p>A separate hard limit applies to document reads from rules (<code>get(...)</code> and <code>exists(...)</code>): 10 per rule. The linter’s <code>GET_COUNT</code> rule warns at 5 and errors at 10. Firestore caches same-path calls within a single rule evaluation, but only for the same path: <code>get(users/$(uid))</code> and <code>get(users/$(otherUid))</code> are two reads, not one.</p>
|
|
64
|
+
<p><code>GET_DUPLICATION</code> catches a related agent failure mode: a helper function that internally calls <code>get()</code>, invoked multiple times from the same rule. The agent thinks it’s calling a tidy abstraction; the engine sees N reads. The fix is to wrap the calls in a function that caches via a <code>let</code>.</p>
|
|
65
|
+
<h2 id="why-the-linter-sometimes-blocks-the-deploy">Why the linter sometimes blocks the deploy</h2>
|
|
66
|
+
<p>Most lint warnings are advisory. A handful are not: <code>SOURCE_SIZE</code>, <code>CHAIN_DEPTH</code> (above the band), <code>LET_LIMIT</code>, <code>GET_COUNT</code> (above 10), <code>PERMISSIVE_RULE</code>, <code>RECURSIVE_WILDCARD_OPEN</code>, <code>HALLUCINATED_METHOD</code>, <code>INVALID_OPERATOR</code>. Treat <code>severity: 'error'</code> as a hard gate before <code>firebase deploy</code>. The choice is deliberate: these are the categories where the cost of shipping the bad rule is high (a deploy that fails compilation; a publicly-readable database) and the cost of demanding a fix is low (the linter tells you exactly what’s wrong).</p>
|
|
67
|
+
<p><code>RULES_WEAKENED</code> is <code>warning</code>, not <code>error</code>. There are legitimate reasons to remove a predicate: a refactor, a dedupe, an intentional broadening. The signal is “review this”, not “block the deploy”.</p> </article> </main> <aside class="doc-toc" aria-label="On this page"> <h2 class="doc-toc-heading">On this page</h2> <ul> <li data-depth="2"> <a href="#the-exact-limits">The exact limits</a> </li><li data-depth="2"> <a href="#the-hard-limit">The hard limit</a> </li><li data-depth="2"> <a href="#shared-gates">Shared gates</a> </li><li data-depth="2"> <a href="#get-call-costs">Get-call costs</a> </li><li data-depth="2"> <a href="#why-the-linter-sometimes-blocks-the-deploy">Why the linter sometimes blocks the deploy</a> </li> </ul> </aside> </div> <script type="module">const a=document.querySelector("[data-api-symbol-filter]"),d=[...document.querySelectorAll("[data-api-symbol-group]")],n=document.querySelector("[data-api-symbol-empty]");a?.addEventListener("input",()=>{const t=a.value.trim().toLowerCase();let o=0;for(const i of d){let e=0;i.querySelectorAll("[data-api-symbol]").forEach(l=>{const r=!t||(l.dataset.apiSymbol??"").includes(t);l.hidden=!r,r&&e++}),i.hidden=e===0,o+=e}n&&(n.hidden=o>0)});</script> <script type="module">const s=new Map;document.querySelectorAll('.doc-toc a[href^="#"]').forEach(t=>s.set(decodeURIComponent(t.hash.slice(1)),t));if(s.size>0){const t=new Set,n=()=>{let o=null;for(const e of s.keys())if(t.has(e)){o=e;break}s.forEach((e,c)=>e.classList.toggle("active",c===o))},r=new IntersectionObserver(o=>{for(const e of o)e.isIntersecting?t.add(e.target.id):t.delete(e.target.id);n()},{rootMargin:"-72px 0px -60% 0px"});s.forEach((o,e)=>{const c=document.getElementById(e);c&&r.observe(c)})}</script> <script type="module">document.querySelector('.studio__nav [aria-current="page"]')?.scrollIntoView({block:"nearest",inline:"center"});</script> </body> </html>
|