@pyric/cli 0.1.0-alpha.10 → 0.1.0-alpha.12

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.
Files changed (498) hide show
  1. package/README.md.orig +2 -2
  2. package/dist/assurance/.generated/conformance-verdicts.d.ts +16 -0
  3. package/dist/assurance/.generated/conformance-verdicts.d.ts.map +1 -1
  4. package/dist/assurance/.generated/conformance-verdicts.js +16 -0
  5. package/dist/assurance/.generated/conformance-verdicts.js.map +1 -1
  6. package/dist/bridge/server/peer.d.ts +1 -1
  7. package/dist/bridge/server.d.ts +1 -1
  8. package/dist/bridge/server.js +1 -1
  9. package/dist/cli/index.d.ts +11 -0
  10. package/dist/cli/index.d.ts.map +1 -1
  11. package/dist/cli/index.js +13 -1
  12. package/dist/cli/index.js.map +1 -1
  13. package/dist/cli/init.d.ts +3 -3
  14. package/dist/cli/init.d.ts.map +1 -1
  15. package/dist/cli/init.js +5 -5
  16. package/dist/cli/init.js.map +1 -1
  17. package/dist/cli/serve.d.ts.map +1 -1
  18. package/dist/cli/serve.js +8 -2
  19. package/dist/cli/serve.js.map +1 -1
  20. package/dist/conformance/.generated/can-i-use-browser.d.ts.map +1 -1
  21. package/dist/conformance/.generated/can-i-use-browser.js +1 -1
  22. package/dist/conformance/.generated/can-i-use-browser.js.map +1 -1
  23. package/dist/conformance/.generated/can-i-use.d.ts.map +1 -1
  24. package/dist/conformance/.generated/can-i-use.js +2 -2
  25. package/dist/conformance/.generated/can-i-use.js.map +1 -1
  26. package/dist/conformance/.generated/conformance-docs.d.ts +12 -0
  27. package/dist/conformance/.generated/conformance-docs.d.ts.map +1 -0
  28. package/dist/conformance/.generated/conformance-docs.js +2 -0
  29. package/dist/conformance/.generated/conformance-docs.js.map +1 -0
  30. package/dist/conformance/docs.d.ts +6 -0
  31. package/dist/conformance/docs.d.ts.map +1 -0
  32. package/dist/conformance/docs.js +6 -0
  33. package/dist/conformance/docs.js.map +1 -0
  34. package/dist/remote/index.d.ts.map +1 -1
  35. package/dist/remote/index.js +1 -0
  36. package/dist/remote/index.js.map +1 -1
  37. package/dist/serve/activity-guard.d.ts +4 -0
  38. package/dist/serve/activity-guard.d.ts.map +1 -0
  39. package/dist/serve/activity-guard.js +22 -0
  40. package/dist/serve/activity-guard.js.map +1 -0
  41. package/dist/serve/activity-route.d.ts +4 -0
  42. package/dist/serve/activity-route.d.ts.map +1 -0
  43. package/dist/serve/activity-route.js +157 -0
  44. package/dist/serve/activity-route.js.map +1 -0
  45. package/dist/serve/activity-warning.d.ts +4 -0
  46. package/dist/serve/activity-warning.d.ts.map +1 -0
  47. package/dist/serve/activity-warning.js +21 -0
  48. package/dist/serve/activity-warning.js.map +1 -0
  49. package/dist/serve/bridge-mount.d.ts +5 -0
  50. package/dist/serve/bridge-mount.d.ts.map +1 -1
  51. package/dist/serve/bridge-mount.js +1 -0
  52. package/dist/serve/bridge-mount.js.map +1 -1
  53. package/dist/serve/docs-ui/404.html +3 -0
  54. package/dist/serve/docs-ui/_astro/{_slug_.DPUwShm2.css → _slug_.CXh9yTP1.css} +1 -1
  55. package/dist/serve/docs-ui/_astro/_slug_.DUci-duz.css +1 -0
  56. package/dist/serve/docs-ui/docs/_rhythm/index.html +2 -1
  57. package/dist/serve/docs-ui/docs/agent/set-up-your-agent/index.html +3 -2
  58. package/dist/serve/docs-ui/docs/agent/set-up-your-agent.md +1 -1
  59. package/dist/serve/docs-ui/docs/agent/watch-and-review/index.html +2 -1
  60. package/dist/serve/docs-ui/docs/agent/work-with-an-agent/index.html +2 -1
  61. package/dist/serve/docs-ui/docs/ai-compat/index.html +2 -1
  62. package/dist/serve/docs-ui/docs/api-reference/index.html +51 -49
  63. package/dist/serve/docs-ui/docs/api-reference.md +3 -3
  64. package/dist/serve/docs-ui/docs/app-compat/index.html +2 -1
  65. package/dist/serve/docs-ui/docs/auth-compat/index.html +2 -1
  66. package/dist/serve/docs-ui/docs/build/ai-logic/index.html +18 -3
  67. package/dist/serve/docs-ui/docs/build/ai-logic.md +30 -2
  68. package/dist/serve/docs-ui/docs/build/authentication/index.html +2 -1
  69. package/dist/serve/docs-ui/docs/build/authentication.md +1 -1
  70. package/dist/serve/docs-ui/docs/build/cloud-firestore/index.html +2 -1
  71. package/dist/serve/docs-ui/docs/build/cloud-messaging/index.html +46 -2
  72. package/dist/serve/docs-ui/docs/build/cloud-messaging.md +56 -1
  73. package/dist/serve/docs-ui/docs/build/cloud-storage/index.html +2 -1
  74. package/dist/serve/docs-ui/docs/build/cloud-storage.md +1 -1
  75. package/dist/serve/docs-ui/docs/build/realtime-database/index.html +21 -3
  76. package/dist/serve/docs-ui/docs/build/realtime-database.md +25 -1
  77. package/dist/serve/docs-ui/docs/conformance-scores/index.html +2 -1
  78. package/dist/serve/docs-ui/docs/create-pyric-reference-api/index.html +61 -28
  79. package/dist/serve/docs-ui/docs/create-pyric-reference-api.md +65 -20
  80. package/dist/serve/docs-ui/docs/database-compat/index.html +2 -1
  81. package/dist/serve/docs-ui/docs/firestore-compat/index.html +6 -5
  82. package/dist/serve/docs-ui/docs/firestore-compat.md +4 -4
  83. package/dist/serve/docs-ui/docs/functions-rtdb-compat/index.html +2 -1
  84. package/dist/serve/docs-ui/docs/get-started/how-the-swap-works/index.html +2 -1
  85. package/dist/serve/docs-ui/docs/get-started/start-building/index.html +4 -3
  86. package/dist/serve/docs-ui/docs/get-started/start-building.md +2 -2
  87. package/dist/serve/docs-ui/docs/index.json +979 -579
  88. package/dist/serve/docs-ui/docs/messaging-compat/index.html +2 -1
  89. package/dist/serve/docs-ui/docs/observe/see-whats-happening/index.html +2 -1
  90. package/dist/serve/docs-ui/docs/observe/shape-your-data/index.html +2 -1
  91. package/dist/serve/docs-ui/docs/overview/index.html +2 -1
  92. package/dist/serve/docs-ui/docs/pyric-admin-app-reference-api/index.html +5 -4
  93. package/dist/serve/docs-ui/docs/pyric-admin-app-reference-api.md +3 -4
  94. package/dist/serve/docs-ui/docs/pyric-admin-auth-reference-api/index.html +5 -4
  95. package/dist/serve/docs-ui/docs/pyric-admin-auth-reference-api.md +3 -4
  96. package/dist/serve/docs-ui/docs/pyric-admin-database-reference-api/index.html +5 -4
  97. package/dist/serve/docs-ui/docs/pyric-admin-database-reference-api.md +3 -4
  98. package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-api/index.html +2503 -12
  99. package/dist/serve/docs-ui/docs/pyric-admin-firestore-reference-api.md +2219 -8
  100. package/dist/serve/docs-ui/docs/pyric-admin-messaging-reference-api/index.html +916 -0
  101. package/dist/serve/docs-ui/docs/pyric-admin-messaging-reference-api.md +706 -0
  102. package/dist/serve/docs-ui/docs/pyric-admin-storage-reference-api/index.html +4 -3
  103. package/dist/serve/docs-ui/docs/pyric-admin-storage-reference-api.md +2 -3
  104. package/dist/serve/docs-ui/docs/pyric-ai-reference-api/index.html +16 -11
  105. package/dist/serve/docs-ui/docs/pyric-ai-reference-api.md +14 -13
  106. package/dist/serve/docs-ui/docs/pyric-ai-scripting-reference-api/index.html +4 -3
  107. package/dist/serve/docs-ui/docs/pyric-ai-scripting-reference-api.md +2 -3
  108. package/dist/serve/docs-ui/docs/pyric-app-reference-api/index.html +7 -2
  109. package/dist/serve/docs-ui/docs/pyric-app-reference-api.md +5 -2
  110. package/dist/serve/docs-ui/docs/pyric-auth-reference-api/index.html +23 -12
  111. package/dist/serve/docs-ui/docs/pyric-auth-reference-api.md +15 -12
  112. package/dist/serve/docs-ui/docs/pyric-cli-assurance-browser-reference-api/index.html +10 -48
  113. package/dist/serve/docs-ui/docs/pyric-cli-assurance-browser-reference-api.md +11 -24
  114. package/dist/serve/docs-ui/docs/pyric-cli-assurance-reference-api/index.html +87 -97
  115. package/dist/serve/docs-ui/docs/pyric-cli-assurance-reference-api.md +53 -65
  116. package/dist/serve/docs-ui/docs/pyric-cli-bridge-client-reference-api/index.html +14 -15
  117. package/dist/serve/docs-ui/docs/pyric-cli-bridge-client-reference-api.md +19 -28
  118. package/dist/serve/docs-ui/docs/pyric-cli-bridge-reference-api/index.html +4 -3
  119. package/dist/serve/docs-ui/docs/pyric-cli-bridge-reference-api.md +2 -3
  120. package/dist/serve/docs-ui/docs/pyric-cli-conformance-browser-reference-api/index.html +3 -2
  121. package/dist/serve/docs-ui/docs/pyric-cli-conformance-browser-reference-api.md +1 -2
  122. package/dist/serve/docs-ui/docs/pyric-cli-conformance-docs-reference-api/index.html +51 -0
  123. package/dist/serve/docs-ui/docs/pyric-cli-conformance-docs-reference-api.md +36 -0
  124. package/dist/serve/docs-ui/docs/pyric-cli-conformance-reference-api/index.html +3 -2
  125. package/dist/serve/docs-ui/docs/pyric-cli-conformance-reference-api.md +1 -2
  126. package/dist/serve/docs-ui/docs/pyric-cli-credentials-node-reference-api/index.html +3 -2
  127. package/dist/serve/docs-ui/docs/pyric-cli-credentials-node-reference-api.md +1 -2
  128. package/dist/serve/docs-ui/docs/pyric-cli-discover-reference-api/index.html +3 -2
  129. package/dist/serve/docs-ui/docs/pyric-cli-discover-reference-api.md +1 -2
  130. package/dist/serve/docs-ui/docs/pyric-cli-register-reference-api/index.html +3 -2
  131. package/dist/serve/docs-ui/docs/pyric-cli-register-reference-api.md +1 -2
  132. package/dist/serve/docs-ui/docs/pyric-cli-remote-reference-api/index.html +1067 -83
  133. package/dist/serve/docs-ui/docs/pyric-cli-remote-reference-api.md +1291 -160
  134. package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api/index.html +253 -157
  135. package/dist/serve/docs-ui/docs/pyric-cli-serve-worker-reference-api.md +179 -85
  136. package/dist/serve/docs-ui/docs/pyric-cli-verify-reference-api/index.html +72 -7
  137. package/dist/serve/docs-ui/docs/pyric-cli-verify-reference-api.md +22 -7
  138. package/dist/serve/docs-ui/docs/pyric-cli-vite-reference-api/index.html +33 -12
  139. package/dist/serve/docs-ui/docs/pyric-cli-vite-reference-api.md +15 -12
  140. package/dist/serve/docs-ui/docs/pyric-database-reference-api/index.html +18 -17
  141. package/dist/serve/docs-ui/docs/pyric-database-reference-api.md +19 -22
  142. package/dist/serve/docs-ui/docs/pyric-firestore-reference-api/index.html +1512 -545
  143. package/dist/serve/docs-ui/docs/pyric-firestore-reference-api.md +1311 -316
  144. package/dist/serve/docs-ui/docs/pyric-messaging-reference-api/index.html +5 -4
  145. package/dist/serve/docs-ui/docs/pyric-messaging-reference-api.md +3 -4
  146. package/dist/serve/docs-ui/docs/pyric-messaging-sw-reference-api/index.html +69 -369
  147. package/dist/serve/docs-ui/docs/pyric-messaging-sw-reference-api.md +103 -216
  148. package/dist/serve/docs-ui/docs/pyric-rules-reference-api/index.html +10 -9
  149. package/dist/serve/docs-ui/docs/pyric-rules-reference-api.md +9 -10
  150. package/dist/serve/docs-ui/docs/pyric-sandbox-database-reference-api/index.html +8 -7
  151. package/dist/serve/docs-ui/docs/pyric-sandbox-database-reference-api.md +6 -7
  152. package/dist/serve/docs-ui/docs/pyric-sandbox-firestore-reference-api/index.html +10 -9
  153. package/dist/serve/docs-ui/docs/pyric-sandbox-firestore-reference-api.md +9 -10
  154. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api/index.html +371 -884
  155. package/dist/serve/docs-ui/docs/pyric-sandbox-reference-api.md +369 -883
  156. package/dist/serve/docs-ui/docs/pyric-storage-reference-api/index.html +25 -17
  157. package/dist/serve/docs-ui/docs/pyric-storage-reference-api.md +21 -19
  158. package/dist/serve/docs-ui/docs/pyric-ui-agents-reference-api/index.html +3 -2
  159. package/dist/serve/docs-ui/docs/pyric-ui-agents-reference-api.md +1 -2
  160. package/dist/serve/docs-ui/docs/pyric-ui-auth-hooks-reference-api/index.html +63 -776
  161. package/dist/serve/docs-ui/docs/pyric-ui-auth-hooks-reference-api.md +69 -510
  162. package/dist/serve/docs-ui/docs/pyric-ui-auth-reference-api/index.html +22 -21
  163. package/dist/serve/docs-ui/docs/pyric-ui-auth-reference-api.md +29 -30
  164. package/dist/serve/docs-ui/docs/pyric-ui-events-hooks-reference-api/index.html +15 -168
  165. package/dist/serve/docs-ui/docs/pyric-ui-events-hooks-reference-api.md +17 -87
  166. package/dist/serve/docs-ui/docs/pyric-ui-events-reference-api/index.html +6 -5
  167. package/dist/serve/docs-ui/docs/pyric-ui-events-reference-api.md +5 -6
  168. package/dist/serve/docs-ui/docs/pyric-ui-firestore-hooks-reference-api/index.html +82 -970
  169. package/dist/serve/docs-ui/docs/pyric-ui-firestore-hooks-reference-api.md +104 -479
  170. package/dist/serve/docs-ui/docs/pyric-ui-firestore-reference-api/index.html +30 -29
  171. package/dist/serve/docs-ui/docs/pyric-ui-firestore-reference-api.md +54 -55
  172. package/dist/serve/docs-ui/docs/pyric-ui-primitives-reference-api/index.html +3 -2
  173. package/dist/serve/docs-ui/docs/pyric-ui-primitives-reference-api.md +1 -2
  174. package/dist/serve/docs-ui/docs/pyric-ui-rtdb-reference-api/index.html +5 -4
  175. package/dist/serve/docs-ui/docs/pyric-ui-rtdb-reference-api.md +3 -4
  176. package/dist/serve/docs-ui/docs/pyric-ui-rules-hooks-reference-api/index.html +9 -124
  177. package/dist/serve/docs-ui/docs/pyric-ui-rules-hooks-reference-api.md +7 -58
  178. package/dist/serve/docs-ui/docs/pyric-ui-rules-reference-api/index.html +24 -23
  179. package/dist/serve/docs-ui/docs/pyric-ui-rules-reference-api.md +31 -34
  180. package/dist/serve/docs-ui/docs/pyric-ui-storage-hooks-reference-api/index.html +104 -1385
  181. package/dist/serve/docs-ui/docs/pyric-ui-storage-hooks-reference-api.md +133 -817
  182. package/dist/serve/docs-ui/docs/pyric-ui-storage-reference-api/index.html +34 -33
  183. package/dist/serve/docs-ui/docs/pyric-ui-storage-reference-api.md +37 -38
  184. package/dist/serve/docs-ui/docs/pyric-ui-traffic-hooks-reference-api/index.html +116 -1169
  185. package/dist/serve/docs-ui/docs/pyric-ui-traffic-hooks-reference-api.md +142 -590
  186. package/dist/serve/docs-ui/docs/pyric-ui-traffic-reference-api/index.html +4 -3
  187. package/dist/serve/docs-ui/docs/pyric-ui-traffic-reference-api.md +3 -4
  188. package/dist/serve/docs-ui/docs/rules-compat/index.html +34 -1
  189. package/dist/serve/docs-ui/docs/rules-compat.md +32 -0
  190. package/dist/serve/docs-ui/docs/secure/audit-your-rules/index.html +19 -2
  191. package/dist/serve/docs-ui/docs/secure/audit-your-rules.md +32 -0
  192. package/dist/serve/docs-ui/docs/secure/firestore-rules-limits/index.html +2 -1
  193. package/dist/serve/docs-ui/docs/secure/read-a-denial/index.html +2 -1
  194. package/dist/serve/docs-ui/docs/secure/rtdb-rules-in-typescript/index.html +2 -1
  195. package/dist/serve/docs-ui/docs/secure/rtdb-rules-in-typescript.md +1 -1
  196. package/dist/serve/docs-ui/docs/secure/rules-standard-library/index.html +2 -1
  197. package/dist/serve/docs-ui/docs/secure/secure-it-with-rules/index.html +2 -1
  198. package/dist/serve/docs-ui/docs/secure/simulate-and-lint/index.html +2 -1
  199. package/dist/serve/docs-ui/docs/secure/write-a-rules-test-suite/index.html +2 -1
  200. package/dist/serve/docs-ui/docs/ship/ship-to-production/index.html +2 -1
  201. package/dist/serve/docs-ui/docs/ship/test-in-node/index.html +2 -1
  202. package/dist/serve/docs-ui/docs/storage-compat/index.html +2 -1
  203. package/dist/serve/docs-ui/docs/trust/how-we-know-it-matches-firebase/index.html +2 -1
  204. package/dist/serve/docs-ui/docs/trust/versioning-and-compatibility/index.html +2 -1
  205. package/dist/serve/docs-ui/llms.txt +2 -1
  206. package/dist/serve/entries/ai.d.ts.map +1 -1
  207. package/dist/serve/entries/ai.js +39 -1
  208. package/dist/serve/entries/ai.js.map +1 -1
  209. package/dist/serve/entries/messaging-sw.d.ts.map +1 -1
  210. package/dist/serve/entries/messaging-sw.js +5 -1
  211. package/dist/serve/entries/messaging-sw.js.map +1 -1
  212. package/dist/serve/entries/messaging.d.ts.map +1 -1
  213. package/dist/serve/entries/messaging.js +7 -1
  214. package/dist/serve/entries/messaging.js.map +1 -1
  215. package/dist/serve/entries/runtime.d.ts.map +1 -1
  216. package/dist/serve/entries/runtime.js +20 -1
  217. package/dist/serve/entries/runtime.js.map +1 -1
  218. package/dist/serve/init-payload.d.ts +25 -0
  219. package/dist/serve/init-payload.d.ts.map +1 -1
  220. package/dist/serve/namespace.d.ts +39 -0
  221. package/dist/serve/namespace.d.ts.map +1 -1
  222. package/dist/serve/namespace.js +80 -1
  223. package/dist/serve/namespace.js.map +1 -1
  224. package/dist/serve/standalone-assets.d.ts +11 -9
  225. package/dist/serve/standalone-assets.d.ts.map +1 -1
  226. package/dist/serve/standalone-assets.js +6 -5
  227. package/dist/serve/standalone-assets.js.map +1 -1
  228. package/dist/serve/studio-ui/assets/{RulesCodeEditor-CXdSLKhO.js → RulesCodeEditor-CxVYcZXw.js} +1 -1
  229. package/dist/serve/studio-ui/assets/index-cpSfgQ7H.js +1218 -0
  230. package/dist/serve/studio-ui/assets/seed-DeuFKi4J.js +20 -0
  231. package/dist/serve/studio-ui/index.html +1 -1
  232. package/dist/serve/vite-plugin.d.ts +92 -15
  233. package/dist/serve/vite-plugin.d.ts.map +1 -1
  234. package/dist/serve/vite-plugin.js +281 -11
  235. package/dist/serve/vite-plugin.js.map +1 -1
  236. package/dist/serve/worker/activity-bootstrap.d.ts +8 -0
  237. package/dist/serve/worker/activity-bootstrap.d.ts.map +1 -0
  238. package/dist/serve/worker/activity-bootstrap.js +11 -0
  239. package/dist/serve/worker/activity-bootstrap.js.map +1 -0
  240. package/dist/serve/worker/client/connection.d.ts.map +1 -1
  241. package/dist/serve/worker/client/connection.js +17 -5
  242. package/dist/serve/worker/client/connection.js.map +1 -1
  243. package/dist/serve/worker/client/core.d.ts +2 -2
  244. package/dist/serve/worker/client/core.d.ts.map +1 -1
  245. package/dist/serve/worker/client/core.js +33 -5
  246. package/dist/serve/worker/client/core.js.map +1 -1
  247. package/dist/serve/worker/client/firestore-writes.d.ts.map +1 -1
  248. package/dist/serve/worker/client/firestore-writes.js +1 -0
  249. package/dist/serve/worker/client/firestore-writes.js.map +1 -1
  250. package/dist/serve/worker/client/messaging.d.ts +9 -1
  251. package/dist/serve/worker/client/messaging.d.ts.map +1 -1
  252. package/dist/serve/worker/client/messaging.js +15 -0
  253. package/dist/serve/worker/client/messaging.js.map +1 -1
  254. package/dist/serve/worker/client/studio.d.ts +10 -0
  255. package/dist/serve/worker/client/studio.d.ts.map +1 -1
  256. package/dist/serve/worker/client/studio.js +11 -0
  257. package/dist/serve/worker/client/studio.js.map +1 -1
  258. package/dist/serve/worker/durable-persistence.d.ts +12 -0
  259. package/dist/serve/worker/durable-persistence.d.ts.map +1 -0
  260. package/dist/serve/worker/durable-persistence.js +118 -0
  261. package/dist/serve/worker/durable-persistence.js.map +1 -0
  262. package/dist/serve/worker/entry.d.ts +7 -3
  263. package/dist/serve/worker/entry.d.ts.map +1 -1
  264. package/dist/serve/worker/entry.js +7 -3
  265. package/dist/serve/worker/entry.js.map +1 -1
  266. package/dist/serve/worker/host/core.d.ts +9 -5
  267. package/dist/serve/worker/host/core.d.ts.map +1 -1
  268. package/dist/serve/worker/host/core.js +34 -9
  269. package/dist/serve/worker/host/core.js.map +1 -1
  270. package/dist/serve/worker/host/dispatch.d.ts.map +1 -1
  271. package/dist/serve/worker/host/dispatch.js +9 -2
  272. package/dist/serve/worker/host/dispatch.js.map +1 -1
  273. package/dist/serve/worker/host/firestore-writes.d.ts.map +1 -1
  274. package/dist/serve/worker/host/firestore-writes.js +3 -2
  275. package/dist/serve/worker/host/firestore-writes.js.map +1 -1
  276. package/dist/serve/worker/host/studio.d.ts +1 -1
  277. package/dist/serve/worker/host/studio.d.ts.map +1 -1
  278. package/dist/serve/worker/host/studio.js +36 -1
  279. package/dist/serve/worker/host/studio.js.map +1 -1
  280. package/dist/serve/worker/host/subscriptions.d.ts.map +1 -1
  281. package/dist/serve/worker/host/subscriptions.js +27 -7
  282. package/dist/serve/worker/host/subscriptions.js.map +1 -1
  283. package/dist/serve/worker/host-context.d.ts +15 -0
  284. package/dist/serve/worker/host-context.d.ts.map +1 -1
  285. package/dist/serve/worker/host-context.js +10 -0
  286. package/dist/serve/worker/host-context.js.map +1 -1
  287. package/dist/serve/worker/host-messaging.d.ts.map +1 -1
  288. package/dist/serve/worker/host-messaging.js +9 -2
  289. package/dist/serve/worker/host-messaging.js.map +1 -1
  290. package/dist/serve/worker/index.d.ts +3 -2
  291. package/dist/serve/worker/index.d.ts.map +1 -1
  292. package/dist/serve/worker/index.js +4 -1
  293. package/dist/serve/worker/index.js.map +1 -1
  294. package/dist/serve/worker/protocol.d.ts +25 -3
  295. package/dist/serve/worker/protocol.d.ts.map +1 -1
  296. package/dist/serve/worker/protocol.js +2 -2
  297. package/dist/serve/worker/protocol.js.map +1 -1
  298. package/dist/serve/worker/serve-init.d.ts +23 -37
  299. package/dist/serve/worker/serve-init.d.ts.map +1 -1
  300. package/dist/serve/worker/serve-init.js +95 -172
  301. package/dist/serve/worker/serve-init.js.map +1 -1
  302. package/dist/vite.d.ts +4 -4
  303. package/dist/vite.d.ts.map +1 -1
  304. package/dist/vite.js +3 -3
  305. package/dist/vite.js.map +1 -1
  306. package/package.json +9 -4
  307. package/src/assurance/.generated/conformance-verdicts.ts +1090 -0
  308. package/src/assurance/attachment.ts +211 -0
  309. package/src/assurance/browser.ts +80 -0
  310. package/src/assurance/campaign.ts +496 -0
  311. package/src/assurance/capabilities.ts +446 -0
  312. package/src/assurance/cases.ts +43 -0
  313. package/src/assurance/index.ts +75 -0
  314. package/src/assurance/runner.ts +885 -0
  315. package/src/assurance/tool-names.ts +15 -0
  316. package/src/assurance/tools.ts +830 -0
  317. package/src/assurance/types.ts +352 -0
  318. package/src/assurance/validation.ts +434 -0
  319. package/src/bridge/client/bridge.ts +550 -0
  320. package/src/bridge/client/dispatch.ts +137 -0
  321. package/src/bridge/client.ts +45 -0
  322. package/src/bridge/protocol.ts +351 -0
  323. package/src/bridge/server/audit.ts +53 -0
  324. package/src/bridge/server/bridge.ts +597 -0
  325. package/src/bridge/server/headless.ts +160 -0
  326. package/src/bridge/server/json-schema-to-zod.ts +108 -0
  327. package/src/bridge/server/local-bridge.ts +66 -0
  328. package/src/bridge/server/logger.ts +50 -0
  329. package/src/bridge/server/mcp-contract.ts +93 -0
  330. package/src/bridge/server/mcp.ts +129 -0
  331. package/src/bridge/server/peer.ts +232 -0
  332. package/src/bridge/server/standalone.ts +347 -0
  333. package/src/bridge/server/tool-metadata.ts +99 -0
  334. package/src/bridge/server.ts +28 -0
  335. package/src/cli/can-i-use.ts +50 -0
  336. package/src/cli/cli.test.ts +493 -0
  337. package/src/cli/database-rules.ts +329 -0
  338. package/src/cli/dev-runner.ts +282 -0
  339. package/src/cli/firebase-json.ts +100 -0
  340. package/src/cli/firestore-indexes.ts +70 -0
  341. package/src/cli/index.ts +425 -0
  342. package/src/cli/init.ts +260 -0
  343. package/src/cli/mcp-proxy.ts +196 -0
  344. package/src/cli/parse-args.ts +80 -0
  345. package/src/cli/rules.ts +259 -0
  346. package/src/cli/scope.ts +67 -0
  347. package/src/cli/serve.ts +996 -0
  348. package/src/cli/service-commands.ts +73 -0
  349. package/src/cli/snapshot.ts +164 -0
  350. package/src/cli/storage-rules.ts +172 -0
  351. package/src/cli/verify.ts +416 -0
  352. package/src/conformance/.generated/can-i-use-browser.ts +113 -0
  353. package/src/conformance/.generated/can-i-use.ts +117 -0
  354. package/src/conformance/.generated/conformance-docs.ts +14 -0
  355. package/src/conformance/browser.ts +24 -0
  356. package/src/conformance/can-i-use-tool.ts +51 -0
  357. package/src/conformance/can-i-use.ts +18 -0
  358. package/src/conformance/docs.ts +8 -0
  359. package/src/conformance/index.ts +20 -0
  360. package/src/conformance/tools.ts +16 -0
  361. package/src/credentials/core/memoize-ttl.ts +142 -0
  362. package/src/credentials/core/types.ts +10 -0
  363. package/src/credentials/node/from-adc.ts +96 -0
  364. package/src/credentials/node/from-service-account.ts +133 -0
  365. package/src/credentials/node/index.ts +6 -0
  366. package/src/discover/concurrency.ts +127 -0
  367. package/src/discover/crawler-adapter.ts +142 -0
  368. package/src/discover/crawler.ts +1127 -0
  369. package/src/discover/credential-free.ts +27 -0
  370. package/src/discover/findCollectionGroup.ts +131 -0
  371. package/src/discover/firestore-source.ts +59 -0
  372. package/src/discover/index.ts +5 -0
  373. package/src/discover/merge.ts +523 -0
  374. package/src/discover/session.ts +402 -0
  375. package/src/discover/tools.ts +201 -0
  376. package/src/discover/types.ts +187 -0
  377. package/src/discover/wire.ts +324 -0
  378. package/src/functions-rtdb/child.ts +382 -0
  379. package/src/functions-rtdb/delivery.ts +7 -0
  380. package/src/functions-rtdb/discovery.ts +136 -0
  381. package/src/functions-rtdb/event.ts +64 -0
  382. package/src/functions-rtdb/execution.ts +111 -0
  383. package/src/functions-rtdb/in-memory-delivery.ts +40 -0
  384. package/src/functions-rtdb/project.ts +74 -0
  385. package/src/functions-rtdb/projection.ts +104 -0
  386. package/src/functions-rtdb/reference-pattern.ts +20 -0
  387. package/src/functions-rtdb/remote-delivery.ts +23 -0
  388. package/src/pkg-version.ts +49 -0
  389. package/src/register/esm-exports.ts +63 -0
  390. package/src/register/hooks.ts +30 -0
  391. package/src/register/index.ts +150 -0
  392. package/src/register/mapping.ts +33 -0
  393. package/src/remote/index.ts +1050 -0
  394. package/src/rtdb/crawl-snapshot.ts +118 -0
  395. package/src/rtdb/inspection.ts +137 -0
  396. package/src/rtdb/load-rules-document.ts +56 -0
  397. package/src/rtdb/rules-generation-tool.ts +38 -0
  398. package/src/rtdb/rules-json.ts +29 -0
  399. package/src/serve/activity-guard.ts +29 -0
  400. package/src/serve/activity-route.ts +164 -0
  401. package/src/serve/activity-warning.ts +26 -0
  402. package/src/serve/bridge-mount.ts +200 -0
  403. package/src/serve/bundler.ts +493 -0
  404. package/src/serve/capture-store.ts +65 -0
  405. package/src/serve/discovery.ts +199 -0
  406. package/src/serve/entries/ai.ts +292 -0
  407. package/src/serve/entries/app-backend.ts +4 -0
  408. package/src/serve/entries/app-client.ts +26 -0
  409. package/src/serve/entries/app-session-store.ts +47 -0
  410. package/src/serve/entries/app.ts +11 -0
  411. package/src/serve/entries/auth-helper-core.ts +181 -0
  412. package/src/serve/entries/auth-helper-dom.ts +134 -0
  413. package/src/serve/entries/auth-helper-runtime.ts +20 -0
  414. package/src/serve/entries/auth.ts +255 -0
  415. package/src/serve/entries/bridge-url.ts +31 -0
  416. package/src/serve/entries/database.ts +129 -0
  417. package/src/serve/entries/firestore.ts +232 -0
  418. package/src/serve/entries/init.ts +46 -0
  419. package/src/serve/entries/keepalive.ts +46 -0
  420. package/src/serve/entries/messaging-sw.ts +75 -0
  421. package/src/serve/entries/messaging.ts +96 -0
  422. package/src/serve/entries/runtime.ts +540 -0
  423. package/src/serve/entries/session-store.ts +97 -0
  424. package/src/serve/entries/storage.ts +92 -0
  425. package/src/serve/entries/tab-sync-wiring.ts +274 -0
  426. package/src/serve/entries/worker-runtime.ts +75 -0
  427. package/src/serve/init-payload.ts +42 -0
  428. package/src/serve/namespace.ts +675 -0
  429. package/src/serve/open-browser.ts +68 -0
  430. package/src/serve/rules.ts +272 -0
  431. package/src/serve/sandbox-marker.ts +31 -0
  432. package/src/serve/server.ts +428 -0
  433. package/src/serve/standalone-assets.ts +180 -0
  434. package/src/serve/state-store.ts +166 -0
  435. package/src/serve/studio/disk-project-store.ts +185 -0
  436. package/src/serve/studio/disk-workspace.ts +162 -0
  437. package/src/serve/studio/index.ts +20 -0
  438. package/src/serve/studio/routes.ts +237 -0
  439. package/src/serve/studio/store-types.ts +48 -0
  440. package/src/serve/studio/studio-storage.test.ts +289 -0
  441. package/src/serve/vite-plugin.ts +1102 -0
  442. package/src/serve/worker/activity-bootstrap.ts +24 -0
  443. package/src/serve/worker/client/admin-firestore.ts +38 -0
  444. package/src/serve/worker/client/ai.ts +124 -0
  445. package/src/serve/worker/client/auth.ts +489 -0
  446. package/src/serve/worker/client/connection.ts +202 -0
  447. package/src/serve/worker/client/core.ts +350 -0
  448. package/src/serve/worker/client/disconnect.ts +45 -0
  449. package/src/serve/worker/client/firestore-reads.ts +181 -0
  450. package/src/serve/worker/client/firestore-refs.ts +226 -0
  451. package/src/serve/worker/client/firestore-writes.ts +232 -0
  452. package/src/serve/worker/client/handles.ts +91 -0
  453. package/src/serve/worker/client/messaging.ts +119 -0
  454. package/src/serve/worker/client/presence.ts +174 -0
  455. package/src/serve/worker/client/rtdb.ts +311 -0
  456. package/src/serve/worker/client/rules.ts +63 -0
  457. package/src/serve/worker/client/service-worker-connection.ts +59 -0
  458. package/src/serve/worker/client/snapshots.ts +86 -0
  459. package/src/serve/worker/client/storage.ts +195 -0
  460. package/src/serve/worker/client/studio.ts +88 -0
  461. package/src/serve/worker/client.ts +57 -0
  462. package/src/serve/worker/durable-persistence.ts +137 -0
  463. package/src/serve/worker/entry.ts +179 -0
  464. package/src/serve/worker/host/admin-firestore.ts +88 -0
  465. package/src/serve/worker/host/connection.ts +179 -0
  466. package/src/serve/worker/host/core.ts +387 -0
  467. package/src/serve/worker/host/dispatch.ts +316 -0
  468. package/src/serve/worker/host/firestore-reads.ts +117 -0
  469. package/src/serve/worker/host/firestore-writes.ts +456 -0
  470. package/src/serve/worker/host/presence.ts +312 -0
  471. package/src/serve/worker/host/rtdb.ts +136 -0
  472. package/src/serve/worker/host/rules.ts +128 -0
  473. package/src/serve/worker/host/storage.ts +312 -0
  474. package/src/serve/worker/host/studio.ts +75 -0
  475. package/src/serve/worker/host/subscriptions.ts +238 -0
  476. package/src/serve/worker/host-ai.ts +165 -0
  477. package/src/serve/worker/host-auth.ts +469 -0
  478. package/src/serve/worker/host-context.ts +273 -0
  479. package/src/serve/worker/host-events.ts +94 -0
  480. package/src/serve/worker/host-messaging.ts +240 -0
  481. package/src/serve/worker/host.ts +47 -0
  482. package/src/serve/worker/index.ts +196 -0
  483. package/src/serve/worker/presence-timing.ts +15 -0
  484. package/src/serve/worker/protocol.ts +1112 -0
  485. package/src/serve/worker/serve-init.ts +606 -0
  486. package/src/serve/worker/service-worker-channel.ts +33 -0
  487. package/src/serve/worker/service-worker-relay.ts +86 -0
  488. package/src/serve/writer-lock.ts +53 -0
  489. package/src/verify/cases.ts +233 -0
  490. package/src/verify/fixture.ts +258 -0
  491. package/src/verify/index.ts +519 -0
  492. package/src/verify/tools.ts +108 -0
  493. package/src/version/compat-target.ts +17 -0
  494. package/src/vite.ts +17 -0
  495. package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api/index.html +0 -30
  496. package/dist/serve/docs-ui/docs/pyric-firestore-values-reference-api.md +0 -30
  497. package/dist/serve/studio-ui/assets/index-BvtQIpGn.js +0 -1211
  498. package/dist/serve/studio-ui/assets/seed-3DMedLL3.js +0 -2
@@ -0,0 +1,117 @@
1
+ // GENERATED FILE. Do not edit or commit.
2
+ // Regenerate: bun run compat:conformance
3
+ // Source: the central conformance model and its canonical can-i-use-query runtime.
4
+ export type DeveloperSurface = "ai" | "app" | "auth" | "firestore" | "firestore-rules" | "functions-rtdb" | "messaging" | "messaging-admin" | "rtdb" | "rtdb-rules" | "storage" | "storage-rules";
5
+ export type Availability = 'available' | 'unavailable' | 'deferred' | 'out-of-scope';
6
+ export type Fidelity = 'conforms' | 'diverged' | 'bug' | 'unsupported' | 'unverified' | 'not-applicable';
7
+ export type Assurance = 'eligible' | 'qualified' | 'ineligible' | 'not-applicable';
8
+ export type FeatureClaimKind = 'runtime-export' | 'type-export' | 'registry-row' | 'rules-construct';
9
+ export interface FeatureClaim { id: string; kind: FeatureClaimKind; surface: string; behavior: string; status: string; evidence: readonly string[]; assurance: Assurance; }
10
+ export interface FeatureSupport { feature: string; surface: DeveloperSurface; importPaths: readonly string[]; evidenceSlug: string; availability: Availability; fidelity: Fidelity; assurance: Assurance; summary: string; caveats: readonly string[]; claims: readonly FeatureClaim[]; }
11
+ export interface ImportEvidence { importPath: string; surface: DeveloperSurface; evidenceSlug: string; }
12
+ export const CONFORMANCE_SUPPORTS: readonly FeatureSupport[] = [{"feature":"AbstractUserDataWriter","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"AbstractUserDataWriter is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors."],"claims":[{"id":"firestore:runtime:AbstractUserDataWriter","kind":"runtime-export","surface":"firestore","behavior":"These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"}]},{"feature":"ActionCodeInfo","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"ActionCodeInfo is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"auth:type:ActionCodeInfo","kind":"type-export","surface":"auth","behavior":"ActionCodeInfo is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ActionCodeOperation","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"ActionCodeOperation is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:ActionCodeOperation","kind":"runtime-export","surface":"auth","behavior":"ActionCodeOperation is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#172","kind":"registry-row","surface":"auth","behavior":"The constant maps, value for value. `OperationType.SIGN_IN === 'signIn'`, `SignInMethod.EMAIL_LINK === 'emailLink'`, `ProviderId.GOOGLE === 'google.com'`, `ActionCodeOperation.PASSWORD_RESET === 'PASSWORD_RESET'`, and the 106-entry `AuthErrorCodes` map (`INVALID_OOB_CODE === 'auth/invalid-action-code'`, `PROVIDER_ALREADY_LINKED === 'auth/provider-already-linked'`, `NO_SUCH_PROVIDER === 'auth/no-such-provider'`, `USER_MISMATCH === 'auth/user-mismatch'`, …).","status":"conforms","evidence":["ORACLE-BACKED, snapshotted straight from the shipped SDK: `auth-mechanical-surface-constants` against firebase-js-sdk 12.13.0, replayed value-for-value in `unit:oracle-conformance.test.ts`. This matters more than it looks: consumer code COMPARES against these constants, so a mirror that got a string wrong would turn every such comparison into a silent `false` — a worse failure than the export simply being absent, because it typechecks and runs. NOTE: the capture's `persistenceTypes` block is deliberately NOT asserted — the harness runs under Node, where firebase/auth stubs the browser-only persistence tokens to `type: 'NONE'` (it reports 'NONE' even for `browserLocalPersistence`, which is unambiguously 'LOCAL'); asserting it would be asserting a harness artifact. See auth#178.","observation:auth-mechanical-surface-constants","packages/pyric/test/auth/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"ActionCodeSettings","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"ActionCodeSettings is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"auth:type:ActionCodeSettings","kind":"type-export","surface":"auth","behavior":"ActionCodeSettings is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ActionCodeURL","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"ActionCodeURL is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:ActionCodeURL","kind":"runtime-export","surface":"auth","behavior":"ActionCodeURL is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth:type:ActionCodeURL","kind":"type-export","surface":"auth","behavior":"ActionCodeURL is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#150","kind":"registry-row","surface":"auth","behavior":"Parses an out-of-band action link. The `mode` query param maps to a NORMALIZED operation (`mode=resetPassword` -> `PASSWORD_RESET`, `mode=signIn` -> `EMAIL_SIGNIN`), `oobCode` surfaces as `code`, `lang` as `languageCode`, and `continueUrl` comes out URL-DECODED. A link missing `mode`, missing `oobCode`, carrying an unknown mode, or that is not a URL at all parses to `null` — the parse NEVER throws. `parseActionCodeURL` and `ActionCodeURL.parseLink` agree.","status":"conforms","evidence":["ORACLE-BACKED and project-independent: this is a PURE client-side parse (no network, no project, no mailbox), so the sandbox owes prod an exact match and there is no room for a divergence. Oracle: `auth-actioncodeurl-parse` against firebase-js-sdk 12.13.0. Replayed in `unit:oracle-conformance.test.ts`.","observation:auth-actioncodeurl-parse","packages/pyric/test/auth/oracle-conformance.test.ts","packages/pyric/test/auth/sandbox-email-link.test.ts"],"assurance":"eligible"}]},{"feature":"addDoc","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"addDoc is available, has diverged fidelity, and is qualified for assurance.","caveats":["Auto-id format — prod uses 20-char base64-ish IDs; sandbox uses `pyric-admin`'s auto-id (also opaque, distinct format)","divergence: IDs are opaque on both sides; format differs but consumer code never parses them. Oracle-locked: `packages/conformance/observations/firestore/firestore-adddoc-autoid-format.json` — prod auto-ids are 20 characters, all alphanumeric (mixed upper, lower, digits; no other chars). Example: `S3PJENMPOk4qcDXol8Ez`."],"claims":[{"id":"firestore:runtime:addDoc","kind":"runtime-export","surface":"firestore","behavior":"addDoc is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#41","kind":"registry-row","surface":"firestore","behavior":"Returns a tagged `DocumentReference` with auto-id","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#42","kind":"registry-row","surface":"firestore","behavior":"Returned ref is usable in subsequent ops (`getDoc`, `setDoc`, `onSnapshot`)","status":"conforms","evidence":["`unit:sandbox-target.test.ts`, oracle: `packages/conformance/observations/firestore/firestore-row-42-adddoc-returned-ref-usable.json` — `addDoc(coll, {v:1})` returned a ref whose `.id` is a 20-char auto-id; `getDoc(ref)` returned `{v:1}` (round-trip), `setDoc(ref, {v:2})` overwrote without error, follow-up `getDoc` returned `{v:2}`, and `onSnapshot(ref, cb)` registered cleanly and fired once with `{exists:true, v:2}`. All four follow-up ops succeed on the returned ref without re-tagging.","observation:firestore-row-42-adddoc-returned-ref-usable","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#43","kind":"registry-row","surface":"firestore","behavior":"Sandbox-live: returned ref is a *live* ref (rebuild closure recorded) so follow-ups re-resolve auth","status":"conforms","evidence":["`unit:sandbox-live-identity.test.ts` (\"addDoc result is a tagged live ref\")","packages/pyric/test/firestore/sandbox-live-identity.test.ts"],"assurance":"eligible"},{"id":"firestore#44","kind":"registry-row","surface":"firestore","behavior":"Converter on the parent collection propagates onto the returned ref","status":"conforms","evidence":["`unit:sandbox-target.test.ts` (\"addDoc through a converted collection\")","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#45","kind":"registry-row","surface":"firestore","behavior":"Auto-id format — prod uses 20-char base64-ish IDs; sandbox uses `pyric-admin`'s auto-id (also opaque, distinct format)","status":"diverged-documented","evidence":["divergence: IDs are opaque on both sides; format differs but consumer code never parses them. Oracle-locked: `packages/conformance/observations/firestore/firestore-adddoc-autoid-format.json` — prod auto-ids are 20 characters, all alphanumeric (mixed upper, lower, digits; no other chars). Example: `S3PJENMPOk4qcDXol8Ez`.","observation:firestore-adddoc-autoid-format"],"assurance":"qualified"}]},{"feature":"AdditionalUserInfo","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"AdditionalUserInfo is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"auth:type:AdditionalUserInfo","kind":"type-export","surface":"auth","behavior":"AdditionalUserInfo is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"AddPrefixToKeys","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"AddPrefixToKeys is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:AddPrefixToKeys","kind":"type-export","surface":"firestore","behavior":"AddPrefixToKeys is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"AggregateField","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"AggregateField is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors."],"claims":[{"id":"firestore:runtime:AggregateField","kind":"runtime-export","surface":"firestore","behavior":"These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"},{"id":"firestore:type:AggregateField","kind":"type-export","surface":"firestore","behavior":"AggregateField is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"aggregateFieldEqual","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"aggregateFieldEqual is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Aggregate-field and aggregate-snapshot equality helpers are exported upstream but have no Pyric runtime implementation yet."],"claims":[{"id":"firestore:runtime:aggregateFieldEqual","kind":"runtime-export","surface":"firestore","behavior":"Aggregate-field and aggregate-snapshot equality helpers are exported upstream but have no Pyric runtime implementation yet.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"}]},{"feature":"AggregateFieldType","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"AggregateFieldType is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:AggregateFieldType","kind":"type-export","surface":"firestore","behavior":"AggregateFieldType is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"AggregateQuerySnapshot","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"AggregateQuerySnapshot is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors."],"claims":[{"id":"firestore:runtime:AggregateQuerySnapshot","kind":"runtime-export","surface":"firestore","behavior":"These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"},{"id":"firestore:type:AggregateQuerySnapshot","kind":"type-export","surface":"firestore","behavior":"AggregateQuerySnapshot is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"aggregateQuerySnapshotEqual","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"aggregateQuerySnapshotEqual is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Aggregate-field and aggregate-snapshot equality helpers are exported upstream but have no Pyric runtime implementation yet."],"claims":[{"id":"firestore:runtime:aggregateQuerySnapshotEqual","kind":"runtime-export","surface":"firestore","behavior":"Aggregate-field and aggregate-snapshot equality helpers are exported upstream but have no Pyric runtime implementation yet.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"}]},{"feature":"AggregateSpec","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"AggregateSpec is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"firestore:type:AggregateSpec","kind":"type-export","surface":"firestore","behavior":"AggregateSpec is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"AggregateSpecData","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"AggregateSpecData is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:AggregateSpecData","kind":"type-export","surface":"firestore","behavior":"AggregateSpecData is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"AggregateType","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"AggregateType is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:AggregateType","kind":"type-export","surface":"firestore","behavior":"AggregateType is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"AI","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"AI is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:AI","kind":"type-export","surface":"ai","behavior":"AI is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"AIError","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"AIError is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"ai:runtime:AIError","kind":"runtime-export","surface":"ai","behavior":"AIError is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:AIError","kind":"type-export","surface":"ai","behavior":"AIError is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai#error-aierror-shape","kind":"registry-row","surface":"ai","behavior":"HTTP failures surface as `AIError` with an `AIErrorCode` code and `customErrorData` carrying `status`, `statusText`, and `errorDetails`","status":"conforms","evidence":["`unit:errors-counttokens.test.ts` test `ai#error-aierror-shape` (capture ai-error-bad-api-key cited as the sample envelope)","observation:ai-error-bad-api-key","packages/pyric/test/ai/errors-counttokens.test.ts"],"assurance":"eligible"}]},{"feature":"AIErrorCode","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"AIErrorCode is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"ai:runtime:AIErrorCode","kind":"runtime-export","surface":"ai","behavior":"AIErrorCode is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:AIErrorCode","kind":"type-export","surface":"ai","behavior":"AIErrorCode is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai#error-aierror-shape","kind":"registry-row","surface":"ai","behavior":"HTTP failures surface as `AIError` with an `AIErrorCode` code and `customErrorData` carrying `status`, `statusText`, and `errorDetails`","status":"conforms","evidence":["`unit:errors-counttokens.test.ts` test `ai#error-aierror-shape` (capture ai-error-bad-api-key cited as the sample envelope)","observation:ai-error-bad-api-key","packages/pyric/test/ai/errors-counttokens.test.ts"],"assurance":"eligible"},{"id":"ai#error-code-vocabulary","kind":"registry-row","surface":"ai","behavior":"`AIErrorCode` exposes the 14 documented codes, from `error` through `unsupported`","status":"conforms","evidence":["`unit:errors-counttokens.test.ts` test `ai#error-code-vocabulary` (upstream constant vocabulary)","packages/pyric/test/ai/errors-counttokens.test.ts"],"assurance":"eligible"}]},{"feature":"AIModel","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"AIModel is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:AIModel","kind":"runtime-export","surface":"ai","behavior":"AIModel is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:AIModel","kind":"type-export","surface":"ai","behavior":"AIModel is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"AIOptions","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"AIOptions is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:AIOptions","kind":"type-export","surface":"ai","behavior":"AIOptions is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"allow","surface":"firestore-rules","importPaths":["pyric/rules"],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"allow is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#182","kind":"registry-row","surface":"firestore-rules","behavior":"User-defined `function`/`let`, granular `allow get/list/update/write` verbs, the ternary operator, and a recursive `{document=**}` match in rules","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 7 cases (role-gated docs + public recursive subtree). `oracle:rules-firestore-functions-verbs-and-recursive` — replayed by `unit:rules/oracle-conformance.test.ts`.","observation:rules-firestore-functions-verbs-and-recursive","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"and","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"and is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:and","kind":"runtime-export","surface":"firestore","behavior":"and is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#55a","kind":"registry-row","surface":"firestore","behavior":"**Existence + null filter guards (FS-B7)** — a doc missing the filter field is never returned by `==`/`<`/`<=`/`>`/`>=`/`in`/`!=`/`not-in`; `!=` and `not-in` additionally exclude null-valued docs and require the field to exist; a `null` in a `not-in` operand list matches nothing. Pre-FS-B7, `!=`/`not-in` matched missing-field and null docs.","status":"conforms","evidence":["`unit:admin-compat/inequality-existence-guards.test.ts` (verified failing pre-fix)","packages/pyric/test/sandbox/firestore/admin-compat/inequality-existence-guards.test.ts"],"assurance":"eligible"},{"id":"firestore#57","kind":"registry-row","surface":"firestore","behavior":"`and(...)` composite — every sub-filter matches","status":"conforms","evidence":["`unit:sandbox-target.test.ts` (\"and() requires every sub-filter\"), oracle: `packages/conformance/observations/firestore/firestore-and-composite.json` (4 seeded docs; `and(where('x','==',1), where('y','==',2))` returned only the intersection `{match-both}`)","observation:firestore-and-composite","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#58","kind":"registry-row","surface":"firestore","behavior":"Nested `or` / `and` — full composite tree","status":"conforms","evidence":["`unit:sandbox-target.test.ts` (\"nested or/and — the canonical composite pattern\"), oracle: `packages/conformance/observations/firestore/firestore-nested-or-and-composite.json` (6 seeded docs; `or(and(where('x','==',1), where('y','==',2)), where('z','==',3))` returned `{inner-and-match, outer-z-match, both-branches}` — exact boolean union as predicted)","observation:firestore-nested-or-and-composite","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#59a","kind":"registry-row","surface":"firestore","behavior":"**Canonical type-order comparison (FS-B3)** — orderBy + range filters compare by Firestore's canonical type order (`null < bool < number < timestamp < string < bytes < ref < geopoint < array < map`), then within-type; numbers sort numerically (not lexicographically), NaN sorts as the smallest number, and range filters (`<`/`<=`/`>`/`>=`) only match same-type values. Pre-FS-B3 the comparator fell back to `String(a).localeCompare(String(b))`.","status":"conforms","evidence":["`unit:admin-compat/canonical-type-order.test.ts` (cross-type ranking, numeric sort, NaN, timestamps, arrays; verified failing pre-fix)","packages/pyric/test/sandbox/firestore/admin-compat/canonical-type-order.test.ts"],"assurance":"eligible"},{"id":"firestore#59c","kind":"registry-row","surface":"firestore","behavior":"**Implicit orderBy + `__name__` tiebreak (FS-B8)** — the query's sort is normalized to: explicit orderBy clauses, then an implicit order on each inequality-filtered field, then a final document-key (`__name__`) clause. Equal-valued docs sort deterministically by key; a `where('x','>',v)` with no explicit orderBy returns docs ordered by `x`. Mirrors `clones/.../core/query.ts:queryNormalizedOrderBy`. Pre-FS-B8 equal-valued docs were nondeterministic and inequality results came back in insertion order.","status":"conforms","evidence":["`unit:admin-compat/implicit-order-name.test.ts` (key tiebreak, snapshot-cursor disambiguation, implicit inequality order; verified failing pre-fix)","packages/pyric/test/sandbox/firestore/admin-compat/implicit-order-name.test.ts"],"assurance":"eligible"},{"id":"firestore#63","kind":"registry-row","surface":"firestore","behavior":"Passing `orderBy` / `limit` into `or()` / `and()` → `TypeError`","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#64","kind":"registry-row","surface":"firestore","behavior":"Zero-arg `or()` / `and()` → `TypeError`","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"AndroidConfig","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"AndroidConfig is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#27","kind":"registry-row","surface":"messaging-admin","behavior":"Android overrides; `ttl` is in milliseconds and `priority` is `high` | `normal`.","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `messaging-api`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"AndroidFcmOptions","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"AndroidFcmOptions is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#30","kind":"registry-row","surface":"messaging-admin","behavior":"Android FCM options (`analyticsLabel`).","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `messaging-api`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"AndroidNotification","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"AndroidNotification is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#28","kind":"registry-row","surface":"messaging-admin","behavior":"Android notification options, including localization keys, LED light settings, and delivery-proxy controls.","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `messaging-api`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"AnyOfSchema","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"AnyOfSchema is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:AnyOfSchema","kind":"runtime-export","surface":"ai","behavior":"AnyOfSchema is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:AnyOfSchema","kind":"type-export","surface":"ai","behavior":"AnyOfSchema is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ApnsConfig","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"ApnsConfig is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#21","kind":"registry-row","surface":"messaging-admin","behavior":"APNs overrides.","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `messaging-api`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"ApnsFcmOptions","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"ApnsFcmOptions is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#26","kind":"registry-row","surface":"messaging-admin","behavior":"APNs FCM options (`analyticsLabel`, `imageUrl`).","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `messaging-api`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"ApnsPayload","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"ApnsPayload is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#22","kind":"registry-row","surface":"messaging-admin","behavior":"APNs payload wrapper carrying the required `aps` dictionary plus arbitrary custom keys.","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `messaging-api`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"ApplicationVerifier","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"ApplicationVerifier is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:ApplicationVerifier","kind":"type-export","surface":"auth","behavior":"ApplicationVerifier is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"applyActionCode","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"applyActionCode is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:applyActionCode","kind":"runtime-export","surface":"auth","behavior":"applyActionCode is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#152","kind":"registry-row","surface":"auth","behavior":"Redeems an out-of-band code and performs its state change (`VERIFY_EMAIL` sets `emailVerified`, `VERIFY_AND_CHANGE_EMAIL` moves the account to the new address). Throws `auth/invalid-action-code` for a code the project never issued, for the empty string, and for a code already redeemed (single-use). A `PASSWORD_RESET` code is refused — `confirmPasswordReset` owns that one.","status":"conforms","evidence":["ORACLE-BACKED on the reject path: `auth-action-code-invalid` confirmed prod emits `auth/invalid-action-code` for both a bogus code and the empty string (this endpoint is NOT gated on the password provider, so it answered honestly). The APPLY path (a real code, redeemed) cannot be probed from a client — it needs a code from a real inbox — and is unit-backed end to end against the sandbox outbox in `unit:sandbox-email-link.test.ts`.","observation:auth-action-code-invalid","packages/pyric/test/auth/oracle-conformance.test.ts","packages/pyric/test/auth/sandbox-email-link.test.ts"],"assurance":"eligible"}]},{"feature":"Aps","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"Aps is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#23","kind":"registry-row","surface":"messaging-admin","behavior":"APNs `aps` dictionary; `alert` is a string or an `ApsAlert`, `sound` a string or a `CriticalSound`.","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `messaging-api`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"ApsAlert","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"ApsAlert is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#24","kind":"registry-row","surface":"messaging-admin","behavior":"APNs alert object with title/subtitle/body and localization keys.","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `messaging-api`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"arithmetic","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"arithmetic is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"rtdb-rules#9","kind":"registry-row","surface":"rtdb-rules","behavior":"Arithmetic and comparison operators in quota rules — `+` `-` `*` `/` `%`, `>` `>=` `<` `<=`, `!==`, loose `==`, `||`, the ternary, and unary minus","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator evaluates every arithmetic and ordering operator as production does, across increment-only counters, doubling and halving deltas, a parity check, inclusive and exclusive range caps, a negative sentinel, loose equality against zero, a disjunction, and a ternary tier bound. `oracle:rules-rtdb-r9-quota-arithmetic` matches production verdict-for-verdict on all 23 cases.","observation:rules-rtdb-r9-quota-arithmetic","packages/pyric/test/rules/rtdb/rules-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"arrayRemove","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"arrayRemove is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:arrayRemove","kind":"runtime-export","surface":"firestore","behavior":"arrayRemove is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#102","kind":"registry-row","surface":"firestore","behavior":"`arrayRemove(...values)` strips matching members; values not present in the array are silent no-ops","status":"conforms","evidence":["`unit:sandbox-target.test.ts`, `playground:firestore-sentinels` (bundled) + `playground:firestore-row-102-arrayremove-strips` (one-claim), oracle: `packages/conformance/observations/firestore/firestore-row-102-arrayremove-strips.json` — `setDoc({tags: ['a','b','c']})` then `updateDoc({tags: arrayRemove('b','d')})` yields `['a','c']`: `'b'` removed, `'d'` (absent) was a silent no-op (no error). Merge-path: `unit:upstream-transform-txn-listener-probes.test.ts`","observation:firestore-row-102-arrayremove-strips","packages/pyric/test/firestore/sandbox-target.test.ts","packages/pyric/test/firestore/upstream-transform-txn-listener-probes.test.ts"],"assurance":"eligible"},{"id":"firestore#105a","kind":"registry-row","surface":"firestore","behavior":"**Sentinel overwrite on type mismatch (FS-B11)** — `increment(n)` on a non-numeric (or absent) prior OVERWRITES using a base value of 0 (result `n`); `arrayUnion`/`arrayRemove` on a non-array prior coerce the base to `[]`. Pre-FS-B11 these threw and surfaced as `invalid-argument` denials. Mirrors `clones/.../model/transform_operation.ts` (`computeTransformOperationBaseValue`, `coercedFieldValuesArray`).","status":"conforms","evidence":["`unit:simulator/converters/fieldvalue.test.ts` (FS-B11 overwrite block + flipped unit/integration/batch cases; verified failing pre-fix)","packages/pyric/test/sandbox/firestore/simulator/converters/fieldvalue.test.ts"],"assurance":"eligible"}]},{"feature":"ArraySchema","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"ArraySchema is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:ArraySchema","kind":"runtime-export","surface":"ai","behavior":"ArraySchema is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:ArraySchema","kind":"type-export","surface":"ai","behavior":"ArraySchema is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"arrayUnion","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"arrayUnion is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:arrayUnion","kind":"runtime-export","surface":"firestore","behavior":"arrayUnion is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#101","kind":"registry-row","surface":"firestore","behavior":"`arrayUnion(...values)` de-dupes against existing members **and** against duplicate args within the same call","status":"conforms","evidence":["`unit:sandbox-target.test.ts`, `playground:firestore-sentinels` (bundled) + `playground:firestore-row-101-arrayunion-dedupes` (one-claim), oracle: `packages/conformance/observations/firestore/firestore-row-101-arrayunion-dedupes.json` — `setDoc({tags: ['a','b']})` then `updateDoc({tags: arrayUnion('b','c')})` yields `['a','b','c']` (single `b`, not double). Follow-up `updateDoc({tags: arrayUnion('d','d','a')})` yields `['a','b','c','d']` — both inline duplicate args and existing-member duplicates are de-duped. Merge-path + object members: `unit:upstream-transform-txn-listener-probes.test.ts`","observation:firestore-row-101-arrayunion-dedupes","packages/pyric/test/firestore/sandbox-target.test.ts","packages/pyric/test/firestore/upstream-transform-txn-listener-probes.test.ts"],"assurance":"eligible"},{"id":"firestore#105a","kind":"registry-row","surface":"firestore","behavior":"**Sentinel overwrite on type mismatch (FS-B11)** — `increment(n)` on a non-numeric (or absent) prior OVERWRITES using a base value of 0 (result `n`); `arrayUnion`/`arrayRemove` on a non-array prior coerce the base to `[]`. Pre-FS-B11 these threw and surfaced as `invalid-argument` denials. Mirrors `clones/.../model/transform_operation.ts` (`computeTransformOperationBaseValue`, `coercedFieldValuesArray`).","status":"conforms","evidence":["`unit:simulator/converters/fieldvalue.test.ts` (FS-B11 overwrite block + flipped unit/integration/batch cases; verified failing pre-fix)","packages/pyric/test/sandbox/firestore/simulator/converters/fieldvalue.test.ts"],"assurance":"eligible"}]},{"feature":"atoms","surface":"rtdb","importPaths":[],"evidenceSlug":"database-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"atoms is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"rtdb#84","kind":"registry-row","surface":"rtdb","behavior":"`atoms` exports the documented set of primitive predicates (`authenticated`, `ownPath`, `ownField`, `isNew`, `hasChildren`, `hasChild`, `fieldIsString/Number/Boolean`, `fieldEnum`, `immutable`, `immutableSelf`, `rootExists`, `rootEquals`) — each returns an `Expr`","status":"conforms","evidence":["`unit:constraints/atoms.test.ts`","packages/pyric/test/rules/rtdb/constraints/atoms.test.ts"],"assurance":"eligible"},{"id":"rtdb#85","kind":"registry-row","surface":"rtdb","behavior":"`policies` exports composite predicates that compose atoms: `pathOwnerOnly`, `fieldOwnerOnly`, `ownerOrNew`, `hasRole`, `isMember`, `required`, `transition`","status":"conforms","evidence":["`unit:constraints/policies.test.ts`","packages/pyric/test/rules/rtdb/constraints/policies.test.ts"],"assurance":"eligible"}]},{"feature":"AudioConversationController","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"AudioConversationController is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:AudioConversationController","kind":"type-export","surface":"ai","behavior":"AudioConversationController is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"AudioTranscriptionConfig","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"AudioTranscriptionConfig is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:AudioTranscriptionConfig","kind":"type-export","surface":"ai","behavior":"AudioTranscriptionConfig is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"Auth","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"Auth is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:type:Auth","kind":"type-export","surface":"auth","behavior":"Auth is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#49e","kind":"registry-row","surface":"auth","behavior":"`auth.signOut()` method form works alongside the free `signOut(auth)` function (`firebase/auth`'s `Auth` exposes both) (AUTH-GAP)","status":"conforms","evidence":["`unit:auth-gap-surface.test.ts`","packages/pyric/test/auth/auth-gap-surface.test.ts"],"assurance":"eligible"},{"id":"auth#49f","kind":"registry-row","surface":"auth","behavior":"Sandbox auth errors are real `FirebaseError` instances (`err instanceof FirebaseError`) carrying the prod message wrapper `Firebase: <message> (<auth/...>).` — e.g. `Firebase: Error (auth/invalid-email).`, matching the oracle (AUTH-GAP)","status":"conforms","evidence":["`unit:auth-gap-surface.test.ts`","packages/pyric/test/auth/auth-gap-surface.test.ts"],"assurance":"eligible"}]},{"feature":"auth","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"auth is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb-rules#1","kind":"registry-row","surface":"rtdb-rules","behavior":"`auth != null` gate on `.read`/`.write` — authed ops allow, signed-out ops deny","status":"conforms","evidence":["`oracle:rules-rtdb-r1-auth-only` — production verdicts captured by deploy-observe-restore against the live oracle database (RTDB has no server-side rules test API), replayed verdict-for-verdict against the in-process simulator by `packages/pyric/test/rules/rtdb/rules-conformance.test.ts`; all 4 cases match production.","observation:rules-rtdb-r1-auth-only","packages/pyric/test/rules/rtdb/rules-conformance.test.ts"],"assurance":"eligible"},{"id":"rtdb.binding.auth","kind":"rules-construct","surface":"rtdb-rules","behavior":"auth is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/rules#auth"],"assurance":"qualified"}]},{"feature":"auth.token","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"auth.token is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb-rules#12","kind":"registry-row","surface":"rtdb-rules","behavior":"`now` (the server evaluation clock) and `auth.token` claims, read both dotted (`auth.token.firebase.sign_in_provider`) and subscripted (`auth.token['firebase']['sign_in_provider']`)","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator resolves the server clock and the decoded ID-token claims as production does, through both access forms. The subscript's receiver is load-bearing: production's rules compiler ACCEPTS `auth.token[...]`, a map indexed by key, but REJECTS the same subscript applied to a snapshot value — `newData.val()['kind']` fails to compile with \"No such method/property\" — so `[]` is a map accessor, not a general indexing operator. `oracle:rules-rtdb-r12-server-time-and-token` matches production verdict-for-verdict on all 7 cases.","observation:rules-rtdb-r12-server-time-and-token","packages/pyric/test/rules/rtdb/rules-conformance.test.ts"],"assurance":"eligible"},{"id":"rtdb.binding.auth.token","kind":"rules-construct","surface":"rtdb-rules","behavior":"auth.token is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/rules#auth"],"assurance":"qualified"}]},{"feature":"auth.uid","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"auth.uid is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb-rules#2","kind":"registry-row","surface":"rtdb-rules","behavior":"`$uid` path-variable ownership (`$uid === auth.uid`) — the owner path allows, a foreign uid and an anonymous request deny","status":"conforms","evidence":["`oracle:rules-rtdb-r2-own-uid` — production verdicts captured by deploy-observe-restore, replayed verdict-for-verdict against the in-process simulator; all 5 cases match production, so the simulator binds the path variable against `auth.uid` exactly as production does.","observation:rules-rtdb-r2-own-uid","packages/pyric/test/rules/rtdb/rules-conformance.test.ts"],"assurance":"eligible"},{"id":"rtdb.binding.auth.uid","kind":"rules-construct","surface":"rtdb-rules","behavior":"auth.uid is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/rules#auth"],"assurance":"qualified"}]},{"feature":"AuthCredential","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"AuthCredential is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"auth:runtime:AuthCredential","kind":"runtime-export","surface":"auth","behavior":"AuthCredential is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth:type:AuthCredential","kind":"type-export","surface":"auth","behavior":"AuthCredential is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"AuthError","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"AuthError is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:AuthError","kind":"type-export","surface":"auth","behavior":"AuthError is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"AuthErrorCodes","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"AuthErrorCodes is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:AuthErrorCodes","kind":"runtime-export","surface":"auth","behavior":"AuthErrorCodes is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#172","kind":"registry-row","surface":"auth","behavior":"The constant maps, value for value. `OperationType.SIGN_IN === 'signIn'`, `SignInMethod.EMAIL_LINK === 'emailLink'`, `ProviderId.GOOGLE === 'google.com'`, `ActionCodeOperation.PASSWORD_RESET === 'PASSWORD_RESET'`, and the 106-entry `AuthErrorCodes` map (`INVALID_OOB_CODE === 'auth/invalid-action-code'`, `PROVIDER_ALREADY_LINKED === 'auth/provider-already-linked'`, `NO_SUCH_PROVIDER === 'auth/no-such-provider'`, `USER_MISMATCH === 'auth/user-mismatch'`, …).","status":"conforms","evidence":["ORACLE-BACKED, snapshotted straight from the shipped SDK: `auth-mechanical-surface-constants` against firebase-js-sdk 12.13.0, replayed value-for-value in `unit:oracle-conformance.test.ts`. This matters more than it looks: consumer code COMPARES against these constants, so a mirror that got a string wrong would turn every such comparison into a silent `false` — a worse failure than the export simply being absent, because it typechecks and runs. NOTE: the capture's `persistenceTypes` block is deliberately NOT asserted — the harness runs under Node, where firebase/auth stubs the browser-only persistence tokens to `type: 'NONE'` (it reports 'NONE' even for `browserLocalPersistence`, which is unambiguously 'LOCAL'); asserting it would be asserting a harness artifact. See auth#178.","observation:auth-mechanical-surface-constants","packages/pyric/test/auth/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"AuthErrorMap","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"AuthErrorMap is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"auth:type:AuthErrorMap","kind":"type-export","surface":"auth","behavior":"AuthErrorMap is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"AuthProvider","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"AuthProvider is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"auth:type:AuthProvider","kind":"type-export","surface":"auth","behavior":"AuthProvider is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"AuthSettings","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"AuthSettings is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:AuthSettings","kind":"type-export","surface":"auth","behavior":"AuthSettings is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"average","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"average is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:average","kind":"runtime-export","surface":"firestore","behavior":"average is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#77","kind":"registry-row","surface":"firestore","behavior":"`count()` / `sum(field)` / `average(field)` compose under one spec — `field` may be a dotted nested path","status":"conforms","evidence":["`unit:sandbox-target.test.ts`; nested `sum('metadata.pages')`: `unit:upstream-write-aggregate-probes.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts","packages/pyric/test/firestore/upstream-write-aggregate-probes.test.ts"],"assurance":"eligible"},{"id":"firestore#78","kind":"registry-row","surface":"firestore","behavior":"`average` returns `null` on empty input (matches JS SDK)","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"Backend","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"Backend is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:Backend","kind":"runtime-export","surface":"ai","behavior":"Backend is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:Backend","kind":"type-export","surface":"ai","behavior":"Backend is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"BackendType","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"BackendType is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:BackendType","kind":"runtime-export","surface":"ai","behavior":"BackendType is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:BackendType","kind":"type-export","surface":"ai","behavior":"BackendType is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"BaseMessage","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"BaseMessage is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#11","kind":"registry-row","surface":"messaging-admin","behavior":"Common message fields shared by every target variant. Production accepts a message carrying ONLY a `notification` block and, separately, ONLY a `data` block — neither is individually required.","status":"conforms","evidence":["oracle: `messaging-send-notification-only-vs-data-only-accepted.json` (both accepted). Replayed by the conformance suite.","observation:messaging-send-notification-only-vs-data-only-accepted","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"messaging-admin#12","kind":"registry-row","surface":"messaging-admin","behavior":"A device-token target. A syntactically invalid token is rejected with HTTP 400 INVALID_ARGUMENT whose fieldViolations name `message.token`.","status":"conforms","evidence":["oracle: `messaging-send-invalid-token-error-envelope.json` (fieldViolations names message.token). Replayed by the conformance suite.","observation:messaging-send-invalid-token-error-envelope","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"messaging-admin#13","kind":"registry-row","surface":"messaging-admin","behavior":"A topic target. A well-formed topic send is accepted and returns the standard resource name (no subscribers required); a topic name containing characters outside the documented `[a-zA-Z0-9-_.~%]` set is rejected with an INVALID_ARGUMENT error envelope.","status":"conforms","evidence":["oracle: `messaging-send-topic-accepted.json` (accepted) + `messaging-send-invalid-topic-name-error-envelope.json` (bad name rejected). Replayed by the conformance suite.","observation:messaging-send-topic-accepted","observation:messaging-send-invalid-topic-name-error-envelope","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"messaging-admin#14","kind":"registry-row","surface":"messaging-admin","behavior":"A condition target. A well-formed condition of the form `\"'a' in topics && 'b' in topics\"` is accepted with the standard resource-name shape (no subscribers required); a malformed condition (dangling operator) is rejected with an error envelope.","status":"conforms","evidence":["oracle: `messaging-send-condition-accepted.json` (accepted) + `messaging-send-invalid-condition-error-envelope.json` (malformed rejected). Replayed by the conformance suite.","observation:messaging-send-condition-accepted","observation:messaging-send-invalid-condition-error-envelope","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"messaging-admin#15","kind":"registry-row","surface":"messaging-admin","behavior":"A multicast target of up to 500 tokens, fanned out by `sendEachForMulticast`.","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `messaging-api`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"BaseParams","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"BaseParams is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:BaseParams","kind":"type-export","surface":"ai","behavior":"BaseParams is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"beforeAuthStateChanged","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"beforeAuthStateChanged is available, has diverged fidelity, and is qualified for assurance.","caveats":["`sandbox.setUser` (the sandbox-only test driver) BYPASSES the gate entirely — it is a raw identity force with no prod analog (same bypass it already has for provider enforcement / `signInProvider` tracking), so no registered `beforeAuthStateChanged` callback runs and none can block it.","`unit:sandbox-before-auth-state-changed.test.ts` (\"sandbox.setUser test driver bypasses the gate\")","Served-worker path (SharedWorker-backed auth in `@pyric/cli`): the worker owns the shared user pool and commits transitions on its own side of the port, so a page-local `beforeAuthStateChanged` registration can't actually gate a worker-driven sign-in. Rather than silently accept a callback that could never run, registering THROWS immediately (`auth/operation-not-supported-in-this-environment`) — same defensive pattern as `signInWithCredential` over the worker.","`packages/cli/src/serve/worker/client.ts` (`beforeAuthStateChanged` throws `makeUnsupported`)"],"claims":[{"id":"auth:runtime:beforeAuthStateChanged","kind":"runtime-export","surface":"auth","behavior":"beforeAuthStateChanged is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#76","kind":"registry-row","surface":"auth","behavior":"Registers a BLOCKING gate that runs before a real sign-in/sign-out transition commits. Callbacks run in registration order; a callback that throws (or returns a rejected promise) aborts the transition entirely: the pending `signInWith…`/`signOut` call rejects with `auth/login-blocked`, `currentUser` is unchanged, and `onAuthStateChanged`/`onIdTokenChanged` do NOT fire. Covers every sign-in path that exists in `pyric/auth`: `signInAnonymously`, `signInWithEmailAndPassword`, `createUserWithEmailAndPassword`, `signInWithPopup`, `signInWithRedirect`, `signInWithCredential`, `signInWithCustomToken`, and `signOut`. Modeled after the real `@firebase/auth` `AuthMiddlewareQueue.runMiddleware` (`auth_impl.ts`), read directly from the installed SDK source, not just its `.d.ts`.","status":"conforms","evidence":["`unit:sandbox-before-auth-state-changed.test.ts` — implementation cross-checked against `@firebase/auth`'s `AuthMiddlewareQueue` source (registration-order queue, per-callback try/await, `auth/login-blocked` wrap). Custom-token allow/block: `unit:upstream-auth-probes.test.ts`. No live-oracle capture (no observable client-visible signal to probe beyond the documented+sourced contract already read).","packages/pyric/test/auth/sandbox-before-auth-state-changed.test.ts","packages/pyric/test/auth/upstream-auth-probes.test.ts"],"assurance":"eligible"},{"id":"auth#76a","kind":"registry-row","surface":"auth","behavior":"`onAbort` semantics: when a callback throws, every `onAbort` registered by a callback that ALREADY SUCCEEDED in the same pass runs, in REVERSE registration order — matches upstream's rollback-stack (`runMiddleware`'s `onAbortStack`). An `onAbort` that itself throws is swallowed so it can't mask the original block reason or skip the remaining rollbacks.","status":"conforms","evidence":["`unit:sandbox-before-auth-state-changed.test.ts` (\"onAbort runs (in reverse order)…\", \"a callback whose own onAbort throws…\")","packages/pyric/test/auth/sandbox-before-auth-state-changed.test.ts"],"assurance":"eligible"},{"id":"auth#76b","kind":"registry-row","surface":"auth","behavior":"Fires on BOTH directions: a real sign-in (`nextUser` non-null) and a real sign-out (`nextUser === null`) — a throwing callback blocks `signOut` too, leaving the previous user signed in. Matches upstream, where the same middleware queue gates `_updateCurrentUser` and `signOut`.","status":"conforms","evidence":["`unit:sandbox-before-auth-state-changed.test.ts` (\"fires on sign-out too…\")","packages/pyric/test/auth/sandbox-before-auth-state-changed.test.ts"],"assurance":"eligible"},{"id":"auth#76c","kind":"registry-row","surface":"auth","behavior":"`sandbox.setUser` (the sandbox-only test driver) BYPASSES the gate entirely — it is a raw identity force with no prod analog (same bypass it already has for provider enforcement / `signInProvider` tracking), so no registered `beforeAuthStateChanged` callback runs and none can block it.","status":"diverged-documented","evidence":["`unit:sandbox-before-auth-state-changed.test.ts` (\"sandbox.setUser test driver bypasses the gate\")","packages/pyric/test/auth/sandbox-before-auth-state-changed.test.ts"],"assurance":"qualified"},{"id":"auth#76d","kind":"registry-row","surface":"auth","behavior":"Served-worker path (SharedWorker-backed auth in `@pyric/cli`): the worker owns the shared user pool and commits transitions on its own side of the port, so a page-local `beforeAuthStateChanged` registration can't actually gate a worker-driven sign-in. Rather than silently accept a callback that could never run, registering THROWS immediately (`auth/operation-not-supported-in-this-environment`) — same defensive pattern as `signInWithCredential` over the worker.","status":"diverged-documented","evidence":["`packages/cli/src/serve/worker/client.ts` (`beforeAuthStateChanged` throws `makeUnsupported`)"],"assurance":"qualified"}]},{"feature":"BlockReason","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"BlockReason is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:BlockReason","kind":"runtime-export","surface":"ai","behavior":"BlockReason is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:BlockReason","kind":"type-export","surface":"ai","behavior":"BlockReason is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"BooleanSchema","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"BooleanSchema is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:BooleanSchema","kind":"runtime-export","surface":"ai","behavior":"BooleanSchema is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:BooleanSchema","kind":"type-export","surface":"ai","behavior":"BooleanSchema is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"browserCookiePersistence","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"browserCookiePersistence is available, has diverged fidelity, and is qualified for assurance.","caveats":["Inert configuration tokens, accepted so the idiomatic `initializeAuth(app, { persistence: indexedDBLocalPersistence })` and `setPersistence(auth, browserCookiePersistence)` compile, run, and behave identically. The `.type` discriminant matches upstream exactly (`NONE` / `SESSION` / `LOCAL` / `LOCAL` / `COOKIE`) because consumer code branches on it. `browserPopupRedirectResolver` is accepted and ignored — the sandbox has its own first-class pluggable equivalent (`sandbox.setAuthFlowResolver`). `prodErrorMap` is accepted and DELIBERATELY not honored: installing it upstream strips error messages, and doing that in a sandbox whose purpose is to tell a developer what went wrong would be actively hostile.","In an in-memory sandbox the persistence CHOICE has no observable consequence, so accepting the token and recording the mode is the honest behavior — the same inert-token pattern `pyric/firestore` uses for its cache-factory tokens. `unit:types.test.ts` + `unit:sandbox-email-link.test.ts` cover the exports. Oracle caveat recorded on auth#172: the `persistenceTypes` block of `auth-mechanical-surface-constants` reports `NONE` for every token including `browserLocalPersistence` — a Node-build stub artifact, not the browser contract, so the `.type` values here follow the documented `Persistence.type` union instead."],"claims":[{"id":"auth:runtime:browserCookiePersistence","kind":"runtime-export","surface":"auth","behavior":"browserCookiePersistence is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#178","kind":"registry-row","surface":"auth","behavior":"Inert configuration tokens, accepted so the idiomatic `initializeAuth(app, { persistence: indexedDBLocalPersistence })` and `setPersistence(auth, browserCookiePersistence)` compile, run, and behave identically. The `.type` discriminant matches upstream exactly (`NONE` / `SESSION` / `LOCAL` / `LOCAL` / `COOKIE`) because consumer code branches on it. `browserPopupRedirectResolver` is accepted and ignored — the sandbox has its own first-class pluggable equivalent (`sandbox.setAuthFlowResolver`). `prodErrorMap` is accepted and DELIBERATELY not honored: installing it upstream strips error messages, and doing that in a sandbox whose purpose is to tell a developer what went wrong would be actively hostile.","status":"diverged-documented","evidence":["In an in-memory sandbox the persistence CHOICE has no observable consequence, so accepting the token and recording the mode is the honest behavior — the same inert-token pattern `pyric/firestore` uses for its cache-factory tokens. `unit:types.test.ts` + `unit:sandbox-email-link.test.ts` cover the exports. Oracle caveat recorded on auth#172: the `persistenceTypes` block of `auth-mechanical-surface-constants` reports `NONE` for every token including `browserLocalPersistence` — a Node-build stub artifact, not the browser contract, so the `.type` values here follow the documented `Persistence.type` union instead.","packages/pyric/test/auth/types.test.ts","packages/pyric/test/auth/sandbox-email-link.test.ts"],"assurance":"qualified"}]},{"feature":"browserLocalPersistence","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"browserLocalPersistence is available, has diverged fidelity, and is qualified for assurance.","caveats":["Inert configuration tokens, accepted so the idiomatic `initializeAuth(app, { persistence: indexedDBLocalPersistence })` and `setPersistence(auth, browserCookiePersistence)` compile, run, and behave identically. The `.type` discriminant matches upstream exactly (`NONE` / `SESSION` / `LOCAL` / `LOCAL` / `COOKIE`) because consumer code branches on it. `browserPopupRedirectResolver` is accepted and ignored — the sandbox has its own first-class pluggable equivalent (`sandbox.setAuthFlowResolver`). `prodErrorMap` is accepted and DELIBERATELY not honored: installing it upstream strips error messages, and doing that in a sandbox whose purpose is to tell a developer what went wrong would be actively hostile.","In an in-memory sandbox the persistence CHOICE has no observable consequence, so accepting the token and recording the mode is the honest behavior — the same inert-token pattern `pyric/firestore` uses for its cache-factory tokens. `unit:types.test.ts` + `unit:sandbox-email-link.test.ts` cover the exports. Oracle caveat recorded on auth#172: the `persistenceTypes` block of `auth-mechanical-surface-constants` reports `NONE` for every token including `browserLocalPersistence` — a Node-build stub artifact, not the browser contract, so the `.type` values here follow the documented `Persistence.type` union instead."],"claims":[{"id":"auth:runtime:browserLocalPersistence","kind":"runtime-export","surface":"auth","behavior":"browserLocalPersistence is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#178","kind":"registry-row","surface":"auth","behavior":"Inert configuration tokens, accepted so the idiomatic `initializeAuth(app, { persistence: indexedDBLocalPersistence })` and `setPersistence(auth, browserCookiePersistence)` compile, run, and behave identically. The `.type` discriminant matches upstream exactly (`NONE` / `SESSION` / `LOCAL` / `LOCAL` / `COOKIE`) because consumer code branches on it. `browserPopupRedirectResolver` is accepted and ignored — the sandbox has its own first-class pluggable equivalent (`sandbox.setAuthFlowResolver`). `prodErrorMap` is accepted and DELIBERATELY not honored: installing it upstream strips error messages, and doing that in a sandbox whose purpose is to tell a developer what went wrong would be actively hostile.","status":"diverged-documented","evidence":["In an in-memory sandbox the persistence CHOICE has no observable consequence, so accepting the token and recording the mode is the honest behavior — the same inert-token pattern `pyric/firestore` uses for its cache-factory tokens. `unit:types.test.ts` + `unit:sandbox-email-link.test.ts` cover the exports. Oracle caveat recorded on auth#172: the `persistenceTypes` block of `auth-mechanical-surface-constants` reports `NONE` for every token including `browserLocalPersistence` — a Node-build stub artifact, not the browser contract, so the `.type` values here follow the documented `Persistence.type` union instead.","packages/pyric/test/auth/types.test.ts","packages/pyric/test/auth/sandbox-email-link.test.ts"],"assurance":"qualified"},{"id":"auth#184","kind":"registry-row","surface":"auth","behavior":"After the sibling receives the LOCAL persistence event, same-named Firebase app instances in sibling tabs keep independent active Auth sessions; an anonymous sign-in in one tab does not update the sibling tab's currentUser during the bounded post-signal observation window","status":"conforms","evidence":["oracle: `app-production-cross-tab-auth-persistence` (firebase 12.13.0, two real Chromium pages in one browser context) + served twin: `packages/cli/test/e2e/app-multi-app.pw.ts`","observation:app-production-cross-tab-auth-persistence","packages/cli/test/e2e/app-multi-app.pw.ts"],"assurance":"eligible"}]},{"feature":"browserPopupRedirectResolver","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"browserPopupRedirectResolver is available, has diverged fidelity, and is qualified for assurance.","caveats":["Inert configuration tokens, accepted so the idiomatic `initializeAuth(app, { persistence: indexedDBLocalPersistence })` and `setPersistence(auth, browserCookiePersistence)` compile, run, and behave identically. The `.type` discriminant matches upstream exactly (`NONE` / `SESSION` / `LOCAL` / `LOCAL` / `COOKIE`) because consumer code branches on it. `browserPopupRedirectResolver` is accepted and ignored — the sandbox has its own first-class pluggable equivalent (`sandbox.setAuthFlowResolver`). `prodErrorMap` is accepted and DELIBERATELY not honored: installing it upstream strips error messages, and doing that in a sandbox whose purpose is to tell a developer what went wrong would be actively hostile.","In an in-memory sandbox the persistence CHOICE has no observable consequence, so accepting the token and recording the mode is the honest behavior — the same inert-token pattern `pyric/firestore` uses for its cache-factory tokens. `unit:types.test.ts` + `unit:sandbox-email-link.test.ts` cover the exports. Oracle caveat recorded on auth#172: the `persistenceTypes` block of `auth-mechanical-surface-constants` reports `NONE` for every token including `browserLocalPersistence` — a Node-build stub artifact, not the browser contract, so the `.type` values here follow the documented `Persistence.type` union instead."],"claims":[{"id":"auth:runtime:browserPopupRedirectResolver","kind":"runtime-export","surface":"auth","behavior":"browserPopupRedirectResolver is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#178","kind":"registry-row","surface":"auth","behavior":"Inert configuration tokens, accepted so the idiomatic `initializeAuth(app, { persistence: indexedDBLocalPersistence })` and `setPersistence(auth, browserCookiePersistence)` compile, run, and behave identically. The `.type` discriminant matches upstream exactly (`NONE` / `SESSION` / `LOCAL` / `LOCAL` / `COOKIE`) because consumer code branches on it. `browserPopupRedirectResolver` is accepted and ignored — the sandbox has its own first-class pluggable equivalent (`sandbox.setAuthFlowResolver`). `prodErrorMap` is accepted and DELIBERATELY not honored: installing it upstream strips error messages, and doing that in a sandbox whose purpose is to tell a developer what went wrong would be actively hostile.","status":"diverged-documented","evidence":["In an in-memory sandbox the persistence CHOICE has no observable consequence, so accepting the token and recording the mode is the honest behavior — the same inert-token pattern `pyric/firestore` uses for its cache-factory tokens. `unit:types.test.ts` + `unit:sandbox-email-link.test.ts` cover the exports. Oracle caveat recorded on auth#172: the `persistenceTypes` block of `auth-mechanical-surface-constants` reports `NONE` for every token including `browserLocalPersistence` — a Node-build stub artifact, not the browser contract, so the `.type` values here follow the documented `Persistence.type` union instead.","packages/pyric/test/auth/types.test.ts","packages/pyric/test/auth/sandbox-email-link.test.ts"],"assurance":"qualified"}]},{"feature":"browserSessionPersistence","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"browserSessionPersistence is available, has diverged fidelity, and is qualified for assurance.","caveats":["Inert configuration tokens, accepted so the idiomatic `initializeAuth(app, { persistence: indexedDBLocalPersistence })` and `setPersistence(auth, browserCookiePersistence)` compile, run, and behave identically. The `.type` discriminant matches upstream exactly (`NONE` / `SESSION` / `LOCAL` / `LOCAL` / `COOKIE`) because consumer code branches on it. `browserPopupRedirectResolver` is accepted and ignored — the sandbox has its own first-class pluggable equivalent (`sandbox.setAuthFlowResolver`). `prodErrorMap` is accepted and DELIBERATELY not honored: installing it upstream strips error messages, and doing that in a sandbox whose purpose is to tell a developer what went wrong would be actively hostile.","In an in-memory sandbox the persistence CHOICE has no observable consequence, so accepting the token and recording the mode is the honest behavior — the same inert-token pattern `pyric/firestore` uses for its cache-factory tokens. `unit:types.test.ts` + `unit:sandbox-email-link.test.ts` cover the exports. Oracle caveat recorded on auth#172: the `persistenceTypes` block of `auth-mechanical-surface-constants` reports `NONE` for every token including `browserLocalPersistence` — a Node-build stub artifact, not the browser contract, so the `.type` values here follow the documented `Persistence.type` union instead."],"claims":[{"id":"auth:runtime:browserSessionPersistence","kind":"runtime-export","surface":"auth","behavior":"browserSessionPersistence is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#178","kind":"registry-row","surface":"auth","behavior":"Inert configuration tokens, accepted so the idiomatic `initializeAuth(app, { persistence: indexedDBLocalPersistence })` and `setPersistence(auth, browserCookiePersistence)` compile, run, and behave identically. The `.type` discriminant matches upstream exactly (`NONE` / `SESSION` / `LOCAL` / `LOCAL` / `COOKIE`) because consumer code branches on it. `browserPopupRedirectResolver` is accepted and ignored — the sandbox has its own first-class pluggable equivalent (`sandbox.setAuthFlowResolver`). `prodErrorMap` is accepted and DELIBERATELY not honored: installing it upstream strips error messages, and doing that in a sandbox whose purpose is to tell a developer what went wrong would be actively hostile.","status":"diverged-documented","evidence":["In an in-memory sandbox the persistence CHOICE has no observable consequence, so accepting the token and recording the mode is the honest behavior — the same inert-token pattern `pyric/firestore` uses for its cache-factory tokens. `unit:types.test.ts` + `unit:sandbox-email-link.test.ts` cover the exports. Oracle caveat recorded on auth#172: the `persistenceTypes` block of `auth-mechanical-surface-constants` reports `NONE` for every token including `browserLocalPersistence` — a Node-build stub artifact, not the browser contract, so the `.type` values here follow the documented `Persistence.type` union instead.","packages/pyric/test/auth/types.test.ts","packages/pyric/test/auth/sandbox-email-link.test.ts"],"assurance":"qualified"}]},{"feature":"Bytes","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"Bytes is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:Bytes","kind":"runtime-export","surface":"firestore","behavior":"Bytes is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore:type:Bytes","kind":"type-export","surface":"firestore","behavior":"Bytes is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#106","kind":"registry-row","surface":"firestore","behavior":"The sandbox mirror owns compatible scalar constructors — `Bytes.fromUint8Array(...)`, `new GeoPoint(lat, lng)`, `new FieldPath(...)`, and `documentId()` — without importing `firebase/firestore`","status":"conforms","evidence":["`unit:sandbox-target.test.ts` (constructibility + round trips), `package-edge:package-dependencies.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts","packages/cli/test/package-dependencies.test.ts"],"assurance":"eligible"},{"id":"firestore#109","kind":"registry-row","surface":"firestore","behavior":"`Bytes` round-trip through the sandbox wire encoder — `Bytes` written via `setDoc` reads back as a `Bytes` instance with the same base64 representation","status":"conforms","evidence":["`unit:packages/pyric/test/sandbox/firestore/wire-encoder-bytes-geopoint.test.ts` + `unit:packages/pyric/test/firestore/sandbox-target.test.ts` (\"Bytes + GeoPoint round-trip\"), oracle: `packages/conformance/observations/firestore/firestore-row-109-bytes-roundtrip.json` — `setDoc({payload: Bytes.fromUint8Array([1,2,3,4])})` then `getDoc` yields `payload instanceof Bytes === true`, `payload.constructor.name === 'Bytes'`, `payload.toBase64() === 'AQIDBA=='`, and `payload.toUint8Array()` returns `[1,2,3,4]` against blockingfun. The sandbox converter stores the rules `Bytes` wrapper; `pyric/firestore` finalizes reads into its locally owned `Bytes` class with the same observed methods and values.","observation:firestore-row-109-bytes-roundtrip","packages/pyric/test/firestore/sandbox-target.test.ts","packages/pyric/test/sandbox/firestore/wire-encoder-bytes-geopoint.test.ts"],"assurance":"eligible"}]},{"feature":"bytes.size","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"bytes.size is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["`Bytes`, `String.toUtf8()`, and `hashing.{md5,sha256,crc32,crc32c}()` (Item 5.3) in rules","`oracle:rules-firestore-bytes-toutf8-and-hashing` — production Firestore Rules Test API verdicts for corpus scenario \"bytes-toutf8-and-hashing\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator's toUtf8/md5/sha256/crc32/crc32c byte-encoding and reference-hash implementations diverge from production on all 5 scenario cases, so a rule that should DENY on hash mismatch ALLOWs locally — pinned KNOWN_DIVERGENCE"],"claims":[{"id":"firestore-rules#161","kind":"registry-row","surface":"firestore-rules","behavior":"`Bytes`, `String.toUtf8()`, and `hashing.{md5,sha256,crc32,crc32c}()` (Item 5.3) in rules","status":"diverged-documented","evidence":["`oracle:rules-firestore-bytes-toutf8-and-hashing` — production Firestore Rules Test API verdicts for corpus scenario \"bytes-toutf8-and-hashing\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator's toUtf8/md5/sha256/crc32/crc32c byte-encoding and reference-hash implementations diverge from production on all 5 scenario cases, so a rule that should DENY on hash mismatch ALLOWs locally — pinned KNOWN_DIVERGENCE","observation:rules-firestore-bytes-toutf8-and-hashing","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"ineligible"},{"id":"firestore.method.bytes.size","kind":"rules-construct","surface":"firestore-rules","behavior":"bytes.size is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.Bytes#function_size_"],"assurance":"ineligible"}]},{"feature":"bytes.toBase64","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"bytes.toBase64 is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["`Bytes`, `String.toUtf8()`, and `hashing.{md5,sha256,crc32,crc32c}()` (Item 5.3) in rules","`oracle:rules-firestore-bytes-toutf8-and-hashing` — production Firestore Rules Test API verdicts for corpus scenario \"bytes-toutf8-and-hashing\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator's toUtf8/md5/sha256/crc32/crc32c byte-encoding and reference-hash implementations diverge from production on all 5 scenario cases, so a rule that should DENY on hash mismatch ALLOWs locally — pinned KNOWN_DIVERGENCE"],"claims":[{"id":"firestore-rules#161","kind":"registry-row","surface":"firestore-rules","behavior":"`Bytes`, `String.toUtf8()`, and `hashing.{md5,sha256,crc32,crc32c}()` (Item 5.3) in rules","status":"diverged-documented","evidence":["`oracle:rules-firestore-bytes-toutf8-and-hashing` — production Firestore Rules Test API verdicts for corpus scenario \"bytes-toutf8-and-hashing\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator's toUtf8/md5/sha256/crc32/crc32c byte-encoding and reference-hash implementations diverge from production on all 5 scenario cases, so a rule that should DENY on hash mismatch ALLOWs locally — pinned KNOWN_DIVERGENCE","observation:rules-firestore-bytes-toutf8-and-hashing","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"ineligible"},{"id":"firestore.method.bytes.toBase64","kind":"rules-construct","surface":"firestore-rules","behavior":"bytes.toBase64 is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.Bytes#function_toBase64_"],"assurance":"ineligible"}]},{"feature":"bytes.toHexString","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"bytes.toHexString is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["`Bytes`, `String.toUtf8()`, and `hashing.{md5,sha256,crc32,crc32c}()` (Item 5.3) in rules","`oracle:rules-firestore-bytes-toutf8-and-hashing` — production Firestore Rules Test API verdicts for corpus scenario \"bytes-toutf8-and-hashing\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator's toUtf8/md5/sha256/crc32/crc32c byte-encoding and reference-hash implementations diverge from production on all 5 scenario cases, so a rule that should DENY on hash mismatch ALLOWs locally — pinned KNOWN_DIVERGENCE"],"claims":[{"id":"firestore-rules#161","kind":"registry-row","surface":"firestore-rules","behavior":"`Bytes`, `String.toUtf8()`, and `hashing.{md5,sha256,crc32,crc32c}()` (Item 5.3) in rules","status":"diverged-documented","evidence":["`oracle:rules-firestore-bytes-toutf8-and-hashing` — production Firestore Rules Test API verdicts for corpus scenario \"bytes-toutf8-and-hashing\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator's toUtf8/md5/sha256/crc32/crc32c byte-encoding and reference-hash implementations diverge from production on all 5 scenario cases, so a rule that should DENY on hash mismatch ALLOWs locally — pinned KNOWN_DIVERGENCE","observation:rules-firestore-bytes-toutf8-and-hashing","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"ineligible"},{"id":"firestore.method.bytes.toHexString","kind":"rules-construct","surface":"firestore-rules","behavior":"bytes.toHexString is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.Bytes#function_toHexString_"],"assurance":"ineligible"}]},{"feature":"CACHE_SIZE_UNLIMITED","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"CACHE_SIZE_UNLIMITED is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Index-tuning / GC-policy APIs have no real knob to turn in an in-memory sandbox today, but sibling cache-factory tokens are already honest inert tokens; these are buildable the same way and not genuinely out of scope."],"claims":[{"id":"firestore:runtime:CACHE_SIZE_UNLIMITED","kind":"runtime-export","surface":"firestore","behavior":"Index-tuning / GC-policy APIs have no real knob to turn in an in-memory sandbox today, but sibling cache-factory tokens are already honest inert tokens; these are buildable the same way and not genuinely out of scope.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"}]},{"feature":"cast.bool","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"diverged","assurance":"ineligible","summary":"cast.bool is available, has diverged fidelity, and is ineligible for assurance.","caveats":[],"claims":[{"id":"firestore.function.cast.bool","kind":"rules-construct","surface":"firestore-rules","behavior":"cast.bool is enumerated in the firestore rules-language inventory","status":"rejected","evidence":["https://firebase.google.com/docs/reference/rules/rules#casting","Error: firestore.rules line [5], column [22]. Function not found error: Name: [bool]."],"assurance":"ineligible"}]},{"feature":"cast.float","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"cast.float is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["`int`/`float` division and type distinction (RULES-B5) in rules — truncating int÷int, float division stays float, div-by-zero denies, `is int`/`is float` distinct","`oracle:rules-firestore-int-float-and-division` — production Firestore Rules Test API verdicts for corpus scenario \"int-float-and-division\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator narrows a float-valued payload field toward int on the float-payload case, unlike production which preserves the float type — pinned KNOWN_DIVERGENCE"],"claims":[{"id":"firestore-rules#167","kind":"registry-row","surface":"firestore-rules","behavior":"`int`/`float` division and type distinction (RULES-B5) in rules — truncating int÷int, float division stays float, div-by-zero denies, `is int`/`is float` distinct","status":"diverged-documented","evidence":["`oracle:rules-firestore-int-float-and-division` — production Firestore Rules Test API verdicts for corpus scenario \"int-float-and-division\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator narrows a float-valued payload field toward int on the float-payload case, unlike production which preserves the float type — pinned KNOWN_DIVERGENCE","observation:rules-firestore-int-float-and-division","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"ineligible"},{"id":"firestore.function.cast.float","kind":"rules-construct","surface":"firestore-rules","behavior":"cast.float is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules#casting"],"assurance":"ineligible"}]},{"feature":"cast.int","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"cast.int is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["`int`/`float` division and type distinction (RULES-B5) in rules — truncating int÷int, float division stays float, div-by-zero denies, `is int`/`is float` distinct","`oracle:rules-firestore-int-float-and-division` — production Firestore Rules Test API verdicts for corpus scenario \"int-float-and-division\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator narrows a float-valued payload field toward int on the float-payload case, unlike production which preserves the float type — pinned KNOWN_DIVERGENCE"],"claims":[{"id":"firestore-rules#167","kind":"registry-row","surface":"firestore-rules","behavior":"`int`/`float` division and type distinction (RULES-B5) in rules — truncating int÷int, float division stays float, div-by-zero denies, `is int`/`is float` distinct","status":"diverged-documented","evidence":["`oracle:rules-firestore-int-float-and-division` — production Firestore Rules Test API verdicts for corpus scenario \"int-float-and-division\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator narrows a float-valued payload field toward int on the float-payload case, unlike production which preserves the float type — pinned KNOWN_DIVERGENCE","observation:rules-firestore-int-float-and-division","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"ineligible"},{"id":"firestore.function.cast.int","kind":"rules-construct","surface":"firestore-rules","behavior":"cast.int is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules#casting"],"assurance":"ineligible"}]},{"feature":"cast.path","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"cast.path is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["`Path` wrapper, `path()` constructor, and `Path.bind()` (Item 5.4) in rules","`oracle:rules-firestore-path-constructor-and-bind` — production Firestore Rules Test API verdicts for corpus scenario \"path-constructor-and-bind\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator treats `path()` as idempotent on an already-Path argument where production denies — pinned KNOWN_DIVERGENCE"],"claims":[{"id":"firestore-rules#171","kind":"registry-row","surface":"firestore-rules","behavior":"`Path` wrapper, `path()` constructor, and `Path.bind()` (Item 5.4) in rules","status":"diverged-documented","evidence":["`oracle:rules-firestore-path-constructor-and-bind` — production Firestore Rules Test API verdicts for corpus scenario \"path-constructor-and-bind\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator treats `path()` as idempotent on an already-Path argument where production denies — pinned KNOWN_DIVERGENCE","observation:rules-firestore-path-constructor-and-bind","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"ineligible"},{"id":"firestore.function.cast.path","kind":"rules-construct","surface":"firestore-rules","behavior":"cast.path is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules#casting"],"assurance":"ineligible"}]},{"feature":"cast.string","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"cast.string is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.function.cast.string","kind":"rules-construct","surface":"firestore-rules","behavior":"cast.string is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules#casting"],"assurance":"eligible"}]},{"feature":"ChatSession","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"ChatSession is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:ChatSession","kind":"runtime-export","surface":"ai","behavior":"ChatSession is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:ChatSession","kind":"type-export","surface":"ai","behavior":"ChatSession is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ChatSessionBase","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"ChatSessionBase is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:ChatSessionBase","kind":"runtime-export","surface":"ai","behavior":"ChatSessionBase is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:ChatSessionBase","kind":"type-export","surface":"ai","behavior":"ChatSessionBase is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"checkActionCode","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"checkActionCode is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:checkActionCode","kind":"runtime-export","surface":"auth","behavior":"checkActionCode is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#159","kind":"registry-row","surface":"auth","behavior":"`checkActionCode` and `verifyPasswordResetCode` INSPECT a code without burning it — a check must not destroy the code the subsequent apply needs. `confirmPasswordReset` redeems it and sets the password, running the same strength check `createUserWithEmailAndPassword` runs; a weak new password throws `auth/weak-password` and does NOT burn the code (a typo must not destroy the user's one reset link). A code staged as expired throws `auth/expired-action-code`.","status":"conforms","evidence":["UNIT-BACKED, stated honestly: these three endpoints answered `auth/operation-not-allowed` in the oracle run (`auth-action-code-invalid`) because the oracle project's disabled password provider replies before the invalid-code contract can. That is a fact about the project's configuration, not about the API, so it is NOT asserted as evidence. The error codes used here are matched to the oracle-CAPTURED `AuthErrorCodes` map (`INVALID_OOB_CODE = auth/invalid-action-code`, `EXPIRED_OOB_CODE = auth/expired-action-code` — see auth#172). Behavior proven in `unit:sandbox-email-link.test.ts`.","packages/pyric/test/auth/sandbox-email-link.test.ts"],"assurance":"eligible"}]},{"feature":"child","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"child is available, has unverified fidelity, and is qualified for assurance.","caveats":["`child(ref, 'a/b')` joins a relative path, including embedded slashes","upstream contract"],"claims":[{"id":"database:runtime:child","kind":"runtime-export","surface":"database","behavior":"child is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#102","kind":"registry-row","surface":"rtdb-modular","behavior":"`child(ref, 'a/b')` joins a relative path, including embedded slashes","status":"unverified","evidence":["upstream contract"],"assurance":"qualified"},{"id":"rtdb-modular#M18","kind":"registry-row","surface":"rtdb-modular","behavior":"`push(ref, value)` writes `value` at the new child path","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"push(ref, value) writes the value at the new child path\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M41","kind":"registry-row","surface":"rtdb-modular","behavior":"`onChildAdded` replays each existing direct child of the parent ref on subscribe (one fire per existing key)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-child-events.test.ts` (\"replays existing direct children on subscribe — one fire per key\"); matches oracle observation `packages/conformance/observations/rtdb-modular/rtdb-modular-onchildadded-initial-replay.json` (seeded `{k1,k2,k3}`, observed `firedKeys: ['k1','k2','k3']`).","observation:rtdb-modular-onchildadded-initial-replay","packages/pyric/test/database/modular/sandbox-child-events.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M42","kind":"registry-row","surface":"rtdb-modular","behavior":"After subscribe, `onChildAdded` fires exactly once per new direct child write; snapshot carries `{key, val}` of the new child","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-child-events.test.ts` (\"fires exactly once per NEW direct child after subscribe\"); matches oracle observation `packages/conformance/observations/rtdb-modular/rtdb-modular-onchildadded-post-subscribe.json` (`postSubscribeFires: 1`, `lastFire: {key:'k3', val:{v:3}}`).","observation:rtdb-modular-onchildadded-post-subscribe","packages/pyric/test/database/modular/sandbox-child-events.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M43","kind":"registry-row","surface":"rtdb-modular","behavior":"`onChildChanged` has NO initial replay; fires once when an existing direct child's value transitions; snapshot carries the NEW value","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-child-events.test.ts` (\"does NOT fire on subscribe (no initial replay)\" + \"fires once when an existing child transitions to a new value; snapshot carries NEW val\"); matches oracle observation `packages/conformance/observations/rtdb-modular/rtdb-modular-onchildchanged-fires-on-update.json` (`firedOnInitial: 0, firedOnUpdate: 1, lastFire: {key:'k1', val:{v:2}}`).","observation:rtdb-modular-onchildchanged-fires-on-update","packages/pyric/test/database/modular/sandbox-child-events.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M45","kind":"registry-row","surface":"rtdb-modular","behavior":"`onChildRemoved` has NO initial replay; fires once when a direct child is deleted (via `remove(child)` or `set(child, null)`); snapshot carries the PRIOR (now-removed) value","status":"conforms","evidence":["`unit:upstream-rtdb-probes.test.ts` (parent wipe fan-out via remove(parent) / set(parent, scalar)) + `unit:modular/sandbox-child-events.test.ts` (single-child delete carries PRIOR val); matches oracle `rtdb-modular-onchildremoved-fires-on-delete.json`","observation:rtdb-modular-onchildremoved-fires-on-delete","packages/pyric/test/database/upstream-rtdb-probes.test.ts","packages/pyric/test/database/modular/sandbox-child-events.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M47","kind":"registry-row","surface":"rtdb-modular","behavior":"`off(ref)` (no event type) removes ALL listeners at that ref — value + every child event variety","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-child-events.test.ts` (\"off(ref) removes ALL listeners at the ref\" + \"off(ref) also removes value listeners at the same path\"); matches oracle observation `packages/conformance/observations/rtdb-modular/rtdb-modular-off-stops-child-fires.json` (`postOffFires: 0`).","observation:rtdb-modular-off-stops-child-fires","packages/pyric/test/database/modular/sandbox-child-events.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M5","kind":"registry-row","surface":"rtdb-modular","behavior":"`child(ref, 'sub/path')` composes paths; result inherits the parent's target","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"child(ref, 'sub') composes paths\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M65","kind":"registry-row","surface":"rtdb-modular","behavior":"Write-boundary normalization (`nodeFromJSON`-equivalent): a value written as an array is stored as an integer-keyed object — `child(ref, '1')` returns the element, `forEach` iterates `0,1,2…` (DB-B2)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/normalization.test.ts` (\"array write is addressable by integer-string child key\" + \"forEach over an array iterates its elements\"); upstream `core/snap/nodeFromJSON.ts:118-128`, `core/snap/ChildrenNode.ts:194-230`","packages/pyric/test/database/modular/normalization.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M71","kind":"registry-row","surface":"rtdb-modular","behavior":"`DataSnapshot` shape: `size` (getter), `priority` (currently always `null`), `exportVal()`, `key`, `ref`, `val()`, `exists()`, `child()`, `hasChild()`, `hasChildren()`, `forEach()`, `toJSON()`. It does NOT ship the legacy namespaced `numChildren()` method (DB-B10)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/snapshot-shape.test.ts` (\"exposes size/priority/exportVal; NOT numChildren()\"); matches oracle `packages/conformance/observations/rtdb-modular/rtdb-modular-get-snapshot-shape.json` (`hasSize: true, hasNumChildren: false`) + upstream `api/Reference_impl.ts:288-447`. **Flipped masking tests**: `modular/queries.test.ts` + `modular/sandbox-target.test.ts` asserted `snap.numChildren()` — updated to `snap.size`.","observation:rtdb-modular-get-snapshot-shape","packages/pyric/test/database/modular/snapshot-shape.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M73","kind":"registry-row","surface":"rtdb-modular","behavior":"A primitive at the ROOT is legal (`set(ref(db), 'hello')`); a subsequent child write replaces the primitive root (\"writes win\") (DB-B13)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/root-primitive.test.ts` (2 cases)","packages/pyric/test/database/modular/root-primitive.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M8","kind":"registry-row","surface":"rtdb-modular","behavior":"`get(ref)` returns a `DataSnapshot`-shaped object with `val()`, `exists()`, `key`, `child()`, `hasChildren()`, `numChildren()`, `toJSON()`","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (snapshot shape tests)","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"ChildUpdateFields","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"ChildUpdateFields is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:ChildUpdateFields","kind":"type-export","surface":"firestore","behavior":"ChildUpdateFields is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ChromeAdapter","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"ChromeAdapter is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:ChromeAdapter","kind":"type-export","surface":"ai","behavior":"ChromeAdapter is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"Citation","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"Citation is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:Citation","kind":"type-export","surface":"ai","behavior":"Citation is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"CitationMetadata","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"CitationMetadata is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:CitationMetadata","kind":"type-export","surface":"ai","behavior":"CitationMetadata is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"clearIndexedDbPersistence","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"clearIndexedDbPersistence is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:clearIndexedDbPersistence","kind":"runtime-export","surface":"firestore","behavior":"clearIndexedDbPersistence is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#142","kind":"registry-row","surface":"firestore","behavior":"Maps to `Sandbox.clearPersistence()` — actually wipes the persisted blob (honest, not a no-op); already a no-op when persistence was never enabled","status":"conforms","evidence":["`unit:firestore/persistence-network.test.ts`","packages/pyric/test/firestore/persistence-network.test.ts"],"assurance":"eligible"}]},{"feature":"CodeExecutionResult","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"CodeExecutionResult is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:CodeExecutionResult","kind":"type-export","surface":"ai","behavior":"CodeExecutionResult is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"CodeExecutionResultPart","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"CodeExecutionResultPart is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:CodeExecutionResultPart","kind":"type-export","surface":"ai","behavior":"CodeExecutionResultPart is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"CodeExecutionTool","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"CodeExecutionTool is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:CodeExecutionTool","kind":"type-export","surface":"ai","behavior":"CodeExecutionTool is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"collection","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"collection is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:collection","kind":"runtime-export","surface":"firestore","behavior":"collection is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#10","kind":"registry-row","surface":"firestore","behavior":"`doc(coll, id)` appends under a collection ref","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#12","kind":"registry-row","surface":"firestore","behavior":"`collection(docRef, name)` builds a subcollection ref","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#13","kind":"registry-row","surface":"firestore","behavior":"`collectionGroup(db, id)` returns a query spanning every collection with that id","status":"conforms","evidence":["`unit:sandbox-target.test.ts` (\"gathers documents across every parent collection\")","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#14","kind":"registry-row","surface":"firestore","behavior":"Unknown ref (not produced by this package) → `TypeError` with \"unrecognized reference\"","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#9","kind":"registry-row","surface":"firestore","behavior":"`collection(db, path)` returns a tagged `CollectionReference`","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"collectionGroup","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"collectionGroup is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:collectionGroup","kind":"runtime-export","surface":"firestore","behavior":"collectionGroup is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#13","kind":"registry-row","surface":"firestore","behavior":"`collectionGroup(db, id)` returns a query spanning every collection with that id","status":"conforms","evidence":["`unit:sandbox-target.test.ts` (\"gathers documents across every parent collection\")","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#14","kind":"registry-row","surface":"firestore","behavior":"Unknown ref (not produced by this package) → `TypeError` with \"unrecognized reference\"","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"CollectionReference","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"CollectionReference is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors."],"claims":[{"id":"firestore:runtime:CollectionReference","kind":"runtime-export","surface":"firestore","behavior":"These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"},{"id":"firestore:type:CollectionReference","kind":"type-export","surface":"firestore","behavior":"CollectionReference is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"comparison","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"comparison is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"rtdb-rules#9","kind":"registry-row","surface":"rtdb-rules","behavior":"Arithmetic and comparison operators in quota rules — `+` `-` `*` `/` `%`, `>` `>=` `<` `<=`, `!==`, loose `==`, `||`, the ternary, and unary minus","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator evaluates every arithmetic and ordering operator as production does, across increment-only counters, doubling and halving deltas, a parity check, inclusive and exclusive range caps, a negative sentinel, loose equality against zero, a disjunction, and a ternary tier bound. `oracle:rules-rtdb-r9-quota-arithmetic` matches production verdict-for-verdict on all 23 cases.","observation:rules-rtdb-r9-quota-arithmetic","packages/pyric/test/rules/rtdb/rules-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"compileRtdbRules","surface":"rtdb","importPaths":["pyric/rules/internal/rtdb"],"evidenceSlug":"database-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"compileRtdbRules is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"rtdb#89","kind":"registry-row","surface":"rtdb","behavior":"`compileRtdbRules(rulesJson)` produces an environment-independent tree where each node carries its path, parsed expressions, and child nodes","status":"conforms","evidence":["`unit:compiled-rules.test.ts`","packages/pyric/test/rules/rtdb/compiled-rules.test.ts"],"assurance":"eligible"},{"id":"rtdb#91","kind":"registry-row","surface":"rtdb","behavior":"Round-trip `compileRtdbRules(serializeRtdbRules(compiled))` produces an equivalent rules tree (locked path/expression-text equality, not object identity)","status":"conforms","evidence":["`unit:compiled-rules.test.ts`","packages/pyric/test/rules/rtdb/compiled-rules.test.ts"],"assurance":"eligible"},{"id":"rtdb#92","kind":"registry-row","surface":"rtdb","behavior":"Path-variable segments (`$userId`, `$gameId`) preserved across the round-trip","status":"conforms","evidence":["`unit:compiled-rules.test.ts`","packages/pyric/test/rules/rtdb/compiled-rules.test.ts"],"assurance":"eligible"},{"id":"rtdb#93","kind":"registry-row","surface":"rtdb","behavior":"`.indexOn` arrays preserved across the round-trip","status":"conforms","evidence":["`unit:compiled-rules.test.ts`","packages/pyric/test/rules/rtdb/compiled-rules.test.ts"],"assurance":"eligible"}]},{"feature":"CompleteFn","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"CompleteFn is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:CompleteFn","kind":"type-export","surface":"auth","behavior":"CompleteFn is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"compose","surface":"rtdb","importPaths":[],"evidenceSlug":"database-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"compose is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"rtdb#85","kind":"registry-row","surface":"rtdb","behavior":"`policies` exports composite predicates that compose atoms: `pathOwnerOnly`, `fieldOwnerOnly`, `ownerOrNew`, `hasRole`, `isMember`, `required`, `transition`","status":"conforms","evidence":["`unit:constraints/policies.test.ts`","packages/pyric/test/rules/rtdb/constraints/policies.test.ts"],"assurance":"eligible"},{"id":"rtdb#86","kind":"registry-row","surface":"rtdb","behavior":"`compose` exports the boolean combinators `all`, `any`, `not`, `deny`, `always`, plus the raw `expr` constructor","status":"conforms","evidence":["`unit:constraints/compose.test.ts`","packages/pyric/test/rules/rtdb/constraints/compose.test.ts"],"assurance":"eligible"},{"id":"rtdb#88","kind":"registry-row","surface":"rtdb","behavior":"Game-domain helpers (`turnGuard`, `flip`, `winCheckHelper`) compose into legal rule expressions","status":"conforms","evidence":["`unit:constraints/game.test.ts`","packages/pyric/test/rules/rtdb/constraints/game.test.ts"],"assurance":"eligible"}]},{"feature":"concat","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"concat is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#168","kind":"registry-row","surface":"firestore-rules","behavior":"`List.concat()`/`removeAll()`/`toSet()` (Item 5.2) in rules","status":"conforms","evidence":["`oracle:rules-firestore-list-methods-concat-removeall-toset` — production Firestore Rules Test API verdicts for corpus scenario \"list-methods-concat-removeall-toset\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`; all cases match production.","observation:rules-firestore-list-methods-concat-removeall-toset","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"ConditionMessage","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"ConditionMessage is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#10","kind":"registry-row","surface":"messaging-admin","behavior":"A send payload carrying exactly one of token, topic, or condition.","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `messaging-api`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"messaging-admin#14","kind":"registry-row","surface":"messaging-admin","behavior":"A condition target. A well-formed condition of the form `\"'a' in topics && 'b' in topics\"` is accepted with the standard resource-name shape (no subscribers required); a malformed condition (dangling operator) is rejected with an error envelope.","status":"conforms","evidence":["oracle: `messaging-send-condition-accepted.json` (accepted) + `messaging-send-invalid-condition-error-envelope.json` (malformed rejected). Replayed by the conformance suite.","observation:messaging-send-condition-accepted","observation:messaging-send-invalid-condition-error-envelope","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"Config","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"Config is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:Config","kind":"type-export","surface":"auth","behavior":"Config is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ConfirmationResult","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"ConfirmationResult is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:ConfirmationResult","kind":"type-export","surface":"auth","behavior":"ConfirmationResult is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"confirmPasswordReset","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"confirmPasswordReset is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:confirmPasswordReset","kind":"runtime-export","surface":"auth","behavior":"confirmPasswordReset is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#159","kind":"registry-row","surface":"auth","behavior":"`checkActionCode` and `verifyPasswordResetCode` INSPECT a code without burning it — a check must not destroy the code the subsequent apply needs. `confirmPasswordReset` redeems it and sets the password, running the same strength check `createUserWithEmailAndPassword` runs; a weak new password throws `auth/weak-password` and does NOT burn the code (a typo must not destroy the user's one reset link). A code staged as expired throws `auth/expired-action-code`.","status":"conforms","evidence":["UNIT-BACKED, stated honestly: these three endpoints answered `auth/operation-not-allowed` in the oracle run (`auth-action-code-invalid`) because the oracle project's disabled password provider replies before the invalid-code contract can. That is a fact about the project's configuration, not about the API, so it is NOT asserted as evidence. The error codes used here are matched to the oracle-CAPTURED `AuthErrorCodes` map (`INVALID_OOB_CODE = auth/invalid-action-code`, `EXPIRED_OOB_CODE = auth/expired-action-code` — see auth#172). Behavior proven in `unit:sandbox-email-link.test.ts`.","packages/pyric/test/auth/sandbox-email-link.test.ts"],"assurance":"eligible"}]},{"feature":"connectAuthEmulator","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"connectAuthEmulator is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"auth:runtime:connectAuthEmulator","kind":"runtime-export","surface":"auth","behavior":"connectAuthEmulator is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"connectDatabaseEmulator","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"connectDatabaseEmulator is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["No-op on sandbox-target handles (the sandbox IS the local emulator)","Phase 3","A production target is intentionally absent; production code continues to use `connectDatabaseEmulator` from the unchanged `firebase/database` package"],"claims":[{"id":"database:runtime:connectDatabaseEmulator","kind":"runtime-export","surface":"database","behavior":"connectDatabaseEmulator is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#165","kind":"registry-row","surface":"rtdb-modular","behavior":"No-op on sandbox-target handles (the sandbox IS the local emulator)","status":"unsupported","evidence":["Phase 3"],"assurance":"ineligible"},{"id":"rtdb-modular#166","kind":"registry-row","surface":"rtdb-modular","behavior":"A production target is intentionally absent; production code continues to use `connectDatabaseEmulator` from the unchanged `firebase/database` package","status":"unsupported","evidence":["Phase 3"],"assurance":"ineligible"},{"id":"rtdb-modular#M32","kind":"registry-row","surface":"rtdb-modular","behavior":"`connectDatabaseEmulator(db, host, port)` is a no-op on sandbox targets (the sandbox IS a local emulator)","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"is a no-op on sandbox handles\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"connectFirestoreEmulator","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"connectFirestoreEmulator is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:connectFirestoreEmulator","kind":"runtime-export","surface":"firestore","behavior":"connectFirestoreEmulator is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#119","kind":"registry-row","surface":"firestore","behavior":"No-op on sandbox-target handles (the sandbox already IS a local emulator)","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#120","kind":"registry-row","surface":"firestore","behavior":"Production does not enter the mirror: inactive package resolution leaves Firebase's `connectFirestoreEmulator` implementation unchanged","status":"conforms","evidence":["`node-register:register-child.test.ts` (inactive canonical Firestore is not rewritten)","packages/cli/test/register/register-child.test.ts"],"assurance":"eligible"},{"id":"firestore#121","kind":"registry-row","surface":"firestore","behavior":"The sandbox mirror accepts Firebase's `mockUserToken` option shape as an inert compatibility argument; production uses Firebase's untouched implementation","status":"conforms","evidence":["type-only smoke"],"assurance":"eligible"}]},{"feature":"connectStorageEmulator","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"connectStorageEmulator is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["Exported by `firebase/storage`; reroutes a `FirebaseStorage` handle to a local emulator","not implemented in `pyric/storage` — the sandbox IS the local-target alternative; emulator parity is out of scope per `index.ts`"],"claims":[{"id":"storage:runtime:connectStorageEmulator","kind":"runtime-export","surface":"storage","behavior":"connectStorageEmulator is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"storage#93","kind":"registry-row","surface":"storage","behavior":"Exported by `firebase/storage`; reroutes a `FirebaseStorage` handle to a local emulator","status":"unsupported","evidence":["not implemented in `pyric/storage` — the sandbox IS the local-target alternative; emulator parity is out of scope per `index.ts`"],"assurance":"ineligible"}]},{"feature":"constructorAccess","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"constructorAccess is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#172","kind":"registry-row","surface":"firestore-rules","behavior":"Own-keys-only map membership and constructor-access denial (RULES-B7) in rules — `'toString' in map` is `false`, `.constructor` access errors (no JS prototype-chain leakage)","status":"conforms","evidence":["`oracle:rules-firestore-prototype-chain-keys` — production Firestore Rules Test API verdicts for corpus scenario \"prototype-chain-keys\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`; all cases match production.","observation:rules-firestore-prototype-chain-keys","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"Content","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"Content is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:Content","kind":"type-export","surface":"ai","behavior":"Content is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ContextWindowCompressionConfig","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"ContextWindowCompressionConfig is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:ContextWindowCompressionConfig","kind":"type-export","surface":"ai","behavior":"ContextWindowCompressionConfig is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"count","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"count is available, has diverged fidelity, and is qualified for assurance.","caveats":["Aggregates count documents server-side without paying read cost per doc in prod; sandbox computes locally (no cost model)","divergence: cost behavior differs, observable shape identical. Oracle-locked: `packages/conformance/observations/firestore/firestore-count-aggregate-shape.json` — `getCountFromServer().data()` returns `{ count: <number> }` (single key, no other fields). Empty query returns `count: 0` (not `null`/`undefined`); seeded 3 docs returns `count: 3`; filtered query honors the `where` constraint (`count: 2`)."],"claims":[{"id":"firestore:runtime:count","kind":"runtime-export","surface":"firestore","behavior":"count is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#74","kind":"registry-row","surface":"firestore","behavior":"`getCountFromServer(query)` returns `{ data: () => ({ count: N }) }`","status":"conforms","evidence":["`unit:sandbox-target.test.ts`; collectionGroup: `unit:upstream-write-aggregate-probes.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts","packages/pyric/test/firestore/upstream-write-aggregate-probes.test.ts"],"assurance":"eligible"},{"id":"firestore#77","kind":"registry-row","surface":"firestore","behavior":"`count()` / `sum(field)` / `average(field)` compose under one spec — `field` may be a dotted nested path","status":"conforms","evidence":["`unit:sandbox-target.test.ts`; nested `sum('metadata.pages')`: `unit:upstream-write-aggregate-probes.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts","packages/pyric/test/firestore/upstream-write-aggregate-probes.test.ts"],"assurance":"eligible"},{"id":"firestore#79","kind":"registry-row","surface":"firestore","behavior":"Aggregates count documents server-side without paying read cost per doc in prod; sandbox computes locally (no cost model)","status":"diverged-documented","evidence":["divergence: cost behavior differs, observable shape identical. Oracle-locked: `packages/conformance/observations/firestore/firestore-count-aggregate-shape.json` — `getCountFromServer().data()` returns `{ count: <number> }` (single key, no other fields). Empty query returns `count: 0` (not `null`/`undefined`); seeded 3 docs returns `count: 3`; filtered query honors the `where` constraint (`count: 2`).","observation:firestore-count-aggregate-shape"],"assurance":"qualified"}]},{"feature":"countTokens","surface":"ai","importPaths":[],"evidenceSlug":"ai-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"countTokens is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"ai#counttokens-deterministic","kind":"registry-row","surface":"ai","behavior":"An identical payload returns an identical `totalTokens` across calls","status":"conforms","evidence":["Capture ai-counttokens-envelope (deterministicAcrossTwoCalls) replayed by packages/pyric/test/ai/errors-counttokens.test.ts test `ai#counttokens-deterministic`","observation:ai-counttokens-envelope","packages/pyric/test/ai/errors-counttokens.test.ts"],"assurance":"eligible"},{"id":"ai#counttokens-envelope","kind":"registry-row","surface":"ai","behavior":"The countTokens envelope key set is exactly `promptTokensDetails`, `totalTokens`","status":"conforms","evidence":["Capture ai-counttokens-envelope replayed by packages/pyric/test/ai/errors-counttokens.test.ts test `ai#counttokens-envelope`","observation:ai-counttokens-envelope","packages/pyric/test/ai/errors-counttokens.test.ts"],"assurance":"eligible"},{"id":"ai#error-bad-api-key","kind":"registry-row","surface":"ai","behavior":"An invalid API key fails 400 INVALID_ARGUMENT, not 401, with ErrorInfo plus LocalizedMessage details and the message `API key not valid. Please pass a valid API key.`","status":"conforms","evidence":["Capture ai-error-bad-api-key replayed by packages/pyric/test/ai/errors-counttokens.test.ts test `ai#error-bad-api-key`","observation:ai-error-bad-api-key","packages/pyric/test/ai/errors-counttokens.test.ts"],"assurance":"eligible"},{"id":"ai#error-retired-model","kind":"registry-row","surface":"ai","behavior":"A retired model family (Gemini 1.5) fails 404 NOT_FOUND with an ErrorInfo detail and a retirement message distinct from unknown-model","status":"conforms","evidence":["Capture ai-error-retired-model replayed by packages/pyric/test/ai/errors-counttokens.test.ts test `ai#error-retired-model`","observation:ai-error-retired-model","packages/pyric/test/ai/errors-counttokens.test.ts"],"assurance":"eligible"},{"id":"ai#error-unknown-model","kind":"registry-row","surface":"ai","behavior":"A model name production has never served fails 404 NOT_FOUND with the error key set `code`, `message`, `status` and no details","status":"conforms","evidence":["Capture ai-error-unknown-model replayed by packages/pyric/test/ai/errors-counttokens.test.ts test `ai#error-unknown-model`","observation:ai-error-unknown-model","packages/pyric/test/ai/errors-counttokens.test.ts"],"assurance":"eligible"}]},{"feature":"CountTokensRequest","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"CountTokensRequest is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:CountTokensRequest","kind":"type-export","surface":"ai","behavior":"CountTokensRequest is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"CountTokensResponse","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"CountTokensResponse is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:CountTokensResponse","kind":"type-export","surface":"ai","behavior":"CountTokensResponse is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"createUserWithEmailAndPassword","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"createUserWithEmailAndPassword is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:createUserWithEmailAndPassword","kind":"runtime-export","surface":"auth","behavior":"createUserWithEmailAndPassword is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#20","kind":"registry-row","surface":"auth","behavior":"Creates a new user, signs them in automatically (currentUser becomes the new user)","status":"conforms","evidence":["`playground:auth-email-password` (bundled) + `playground:auth-row-20-create-user-auto-signs-in` (one-claim), `unit:sandbox-email-password.test.ts`","packages/pyric/test/auth/sandbox-email-password.test.ts"],"assurance":"eligible"},{"id":"auth#21","kind":"registry-row","surface":"auth","behavior":"Returns `UserCredential` with `operationType: 'signIn'` (NOT `'register'` — matches prod)","status":"conforms","evidence":["`unit:sandbox-email-password.test.ts` + oracle: `packages/conformance/observations/auth/auth-createUser-operationType.json` (`operationType: 'signIn'` against blockingfun, fb-js-sdk 12.13.0; matches sandbox)","observation:auth-createUser-operationType","packages/pyric/test/auth/oracle-conformance.test.ts","packages/pyric/test/auth/sandbox-email-password.test.ts"],"assurance":"eligible"},{"id":"auth#22","kind":"registry-row","surface":"auth","behavior":"Throws `auth/email-already-in-use` when the email is already registered","status":"conforms","evidence":["`unit:sandbox-email-password.test.ts` + oracle: `packages/conformance/observations/auth/auth-email-already-in-use-error-code.json` (`code: 'auth/email-already-in-use'` against blockingfun, fb-js-sdk 12.13.0; matches sandbox)","observation:auth-email-already-in-use-error-code","packages/pyric/test/auth/sandbox-email-password.test.ts"],"assurance":"eligible"},{"id":"auth#23","kind":"registry-row","surface":"auth","behavior":"The created user has `isAnonymous: false`, `email: <input>`, `displayName: null`","status":"conforms","evidence":["`unit:sandbox-email-password.test.ts` + `playground:auth-row-23-create-user-shape` (one-claim)","packages/pyric/test/auth/sandbox-email-password.test.ts"],"assurance":"eligible"},{"id":"auth#24","kind":"registry-row","surface":"auth","behavior":"Fires `onAuthStateChanged` with the new user once","status":"conforms","evidence":["`unit:sandbox-listeners.test.ts` + oracle: `packages/conformance/observations/auth/auth-row-24-createuser-fires-once.json` (against blockingfun, fb-js-sdk 12.13.0: subscribe (1 initial null fire) → `createUserWithEmailAndPassword` → `firesForCreate: 1` with the newly-created uid, `lastFireUidMatches: true`)","observation:auth-row-24-createuser-fires-once","packages/pyric/test/auth/sandbox-listeners.test.ts"],"assurance":"eligible"}]},{"feature":"CriticalSound","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"CriticalSound is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#25","kind":"registry-row","surface":"messaging-admin","behavior":"APNs critical sound — `name` required; `volume` in the range 0.0–1.0.","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `messaging-api`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"crossTypeOperators","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"crossTypeOperators is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#162","kind":"registry-row","surface":"firestore-rules","behavior":"Typed cross-type operator overloads for `Timestamp`/`Duration` (Item 2) in rules — no silent numeric coercion / type-identity loss","status":"conforms","evidence":["`oracle:rules-firestore-cross-type-operator-overloads` — production Firestore Rules Test API verdicts for corpus scenario \"cross-type-operator-overloads\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`; all cases match production.","observation:rules-firestore-cross-type-operator-overloads","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"CustomErrorData","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"CustomErrorData is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:CustomErrorData","kind":"type-export","surface":"ai","behavior":"CustomErrorData is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"CustomParameters","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"CustomParameters is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:CustomParameters","kind":"type-export","surface":"auth","behavior":"CustomParameters is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"data","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"data is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.binding.data","kind":"rules-construct","surface":"rtdb-rules","behavior":"data is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/rules#data"],"assurance":"qualified"}]},{"feature":"Database","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"Database is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["These Firebase classes are mirrored structurally in Pyric's type surface but are not exported as runtime constructor values; runtime identity remains unbuilt."],"claims":[{"id":"database:runtime:Database","kind":"runtime-export","surface":"database","behavior":"These Firebase classes are mirrored structurally in Pyric's type surface but are not exported as runtime constructor values; runtime identity remains unbuilt.","status":"deferred","evidence":["upstream:firebase/database"],"assurance":"not-applicable"},{"id":"database:type:Database","kind":"type-export","surface":"database","behavior":"Database is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"DatabaseEvent","surface":"functions-rtdb","importPaths":[],"evidenceSlug":"functions-rtdb-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"DatabaseEvent is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"functions-rtdb#10","kind":"registry-row","surface":"functions-rtdb","behavior":"For the production Admin SDK write, the event exposes authType `unknown` and authId `null`.","status":"conforms","evidence":["oracle: `functions-rtdb-onvaluecreated-exact-create.json`. Local replay: `packages/cli/test/functions-rtdb/oracle-conformance.test.ts` assertion set `functions-rtdb#10`.","observation:functions-rtdb-onvaluecreated-exact-create","packages/cli/test/functions-rtdb/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"functions-rtdb#8","kind":"registry-row","surface":"functions-rtdb","behavior":"The delivered DataSnapshot exposes the created value, key, existence, JSON projection, child lookup, child count, and child enumeration.","status":"conforms","evidence":["oracle: `functions-rtdb-onvaluecreated-exact-create.json`; frozen val/key/exists/toJSON/child enumeration shape. Local replay: `packages/cli/test/functions-rtdb/oracle-conformance.test.ts` assertion set `functions-rtdb#8`.","observation:functions-rtdb-onvaluecreated-exact-create","packages/cli/test/functions-rtdb/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"functions-rtdb#9","kind":"registry-row","surface":"functions-rtdb","behavior":"The snapshot ref is an Admin DatabaseReference rooted at the matched path and can perform an awaited write from the handler.","status":"conforms","evidence":["oracle: `functions-rtdb-onvaluecreated-exact-create.json`; matched Admin ref completed the awaited sibling write. Local replay: `packages/cli/test/functions-rtdb/oracle-conformance.test.ts` assertion set `functions-rtdb#9`.","observation:functions-rtdb-onvaluecreated-exact-create","packages/cli/test/functions-rtdb/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"DatabaseReference","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"DatabaseReference is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"database:type:DatabaseReference","kind":"type-export","surface":"database","behavior":"DatabaseReference is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"DataMessagePayload","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"DataMessagePayload is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#31","kind":"registry-row","surface":"messaging-admin","behavior":"Legacy data payload — up to 4KB; the keys `from` and `google.*` are reserved.","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `messaging-api`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"DataSnapshot","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"DataSnapshot is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["These Firebase classes are mirrored structurally in Pyric's type surface but are not exported as runtime constructor values; runtime identity remains unbuilt."],"claims":[{"id":"database:runtime:DataSnapshot","kind":"runtime-export","surface":"database","behavior":"These Firebase classes are mirrored structurally in Pyric's type surface but are not exported as runtime constructor values; runtime identity remains unbuilt.","status":"deferred","evidence":["upstream:firebase/database"],"assurance":"not-applicable"},{"id":"database:type:DataSnapshot","kind":"type-export","surface":"database","behavior":"DataSnapshot is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"Date","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"Date is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:Date","kind":"type-export","surface":"ai","behavior":"Date is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"debug","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"diverged","assurance":"ineligible","summary":"debug is available, has diverged fidelity, and is ineligible for assurance.","caveats":[],"claims":[{"id":"firestore.function.debug","kind":"rules-construct","surface":"firestore-rules","behavior":"debug is enumerated in the firestore rules-language inventory","status":"rejected","evidence":["https://firebase.google.com/docs/reference/rules/rules#function_debug_","Error: firestore.rules line [5], column [22]. Function not found error: Name: [debug]."],"assurance":"ineligible"}]},{"feature":"debugErrorMap","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"debugErrorMap is available, has diverged fidelity, and is qualified for assurance.","caveats":["Inert configuration tokens, accepted so the idiomatic `initializeAuth(app, { persistence: indexedDBLocalPersistence })` and `setPersistence(auth, browserCookiePersistence)` compile, run, and behave identically. The `.type` discriminant matches upstream exactly (`NONE` / `SESSION` / `LOCAL` / `LOCAL` / `COOKIE`) because consumer code branches on it. `browserPopupRedirectResolver` is accepted and ignored — the sandbox has its own first-class pluggable equivalent (`sandbox.setAuthFlowResolver`). `prodErrorMap` is accepted and DELIBERATELY not honored: installing it upstream strips error messages, and doing that in a sandbox whose purpose is to tell a developer what went wrong would be actively hostile.","In an in-memory sandbox the persistence CHOICE has no observable consequence, so accepting the token and recording the mode is the honest behavior — the same inert-token pattern `pyric/firestore` uses for its cache-factory tokens. `unit:types.test.ts` + `unit:sandbox-email-link.test.ts` cover the exports. Oracle caveat recorded on auth#172: the `persistenceTypes` block of `auth-mechanical-surface-constants` reports `NONE` for every token including `browserLocalPersistence` — a Node-build stub artifact, not the browser contract, so the `.type` values here follow the documented `Persistence.type` union instead."],"claims":[{"id":"auth:runtime:debugErrorMap","kind":"runtime-export","surface":"auth","behavior":"debugErrorMap is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#178","kind":"registry-row","surface":"auth","behavior":"Inert configuration tokens, accepted so the idiomatic `initializeAuth(app, { persistence: indexedDBLocalPersistence })` and `setPersistence(auth, browserCookiePersistence)` compile, run, and behave identically. The `.type` discriminant matches upstream exactly (`NONE` / `SESSION` / `LOCAL` / `LOCAL` / `COOKIE`) because consumer code branches on it. `browserPopupRedirectResolver` is accepted and ignored — the sandbox has its own first-class pluggable equivalent (`sandbox.setAuthFlowResolver`). `prodErrorMap` is accepted and DELIBERATELY not honored: installing it upstream strips error messages, and doing that in a sandbox whose purpose is to tell a developer what went wrong would be actively hostile.","status":"diverged-documented","evidence":["In an in-memory sandbox the persistence CHOICE has no observable consequence, so accepting the token and recording the mode is the honest behavior — the same inert-token pattern `pyric/firestore` uses for its cache-factory tokens. `unit:types.test.ts` + `unit:sandbox-email-link.test.ts` cover the exports. Oracle caveat recorded on auth#172: the `persistenceTypes` block of `auth-mechanical-surface-constants` reports `NONE` for every token including `browserLocalPersistence` — a Node-build stub artifact, not the browser contract, so the `.type` values here follow the documented `Persistence.type` union instead.","packages/pyric/test/auth/types.test.ts","packages/pyric/test/auth/sandbox-email-link.test.ts"],"assurance":"qualified"}]},{"feature":"deleteAllPersistentCacheIndexes","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"deleteAllPersistentCacheIndexes is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Index-tuning / GC-policy APIs have no real knob to turn in an in-memory sandbox today, but sibling cache-factory tokens are already honest inert tokens; these are buildable the same way and not genuinely out of scope."],"claims":[{"id":"firestore:runtime:deleteAllPersistentCacheIndexes","kind":"runtime-export","surface":"firestore","behavior":"Index-tuning / GC-policy APIs have no real knob to turn in an in-memory sandbox today, but sibling cache-factory tokens are already honest inert tokens; these are buildable the same way and not genuinely out of scope.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"}]},{"feature":"deleteApp","surface":"app","importPaths":["pyric/app"],"evidenceSlug":"app-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"deleteApp is available, has diverged fidelity, and is qualified for assurance.","caveats":["Production permits a different configuration after deletion; Pyric retains the runtime backend lock and rejects the reinitialization","oracle: `app-registry-delete-reinitialize-different-config` (firebase 12.13.0) + replay pins `app/multiple-configs-not-supported`","Served worker mode rejects page-local custom AnswerEngine objects; a model retained from a deleted app rejects, while an equal-config sibling model remains usable through its own app-scoped worker port","`packages/cli/test/e2e/app-deletion.pw.ts` observes AI code `unsupported` for a custom engine, then exercises retained and sibling models through canonical served imports after deleting one app; `packages/pyric/src/ai/sandbox-plane.ts` guards every model operation. A credentialed production AI lifecycle capture is still needed"],"claims":[{"id":"app:runtime:deleteApp","kind":"runtime-export","surface":"app","behavior":"deleteApp is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"app#10","kind":"registry-row","surface":"app","behavior":"`deleteApp` on an already-deleted app throws `FirebaseError` code `app/app-deleted`","status":"conforms","evidence":["oracle: `app-registry-deleteapp-double` (firebase 12.13.0) + replay: `oracle-conformance.test.ts`","observation:app-registry-deleteapp-double","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"app#20","kind":"registry-row","surface":"app","behavior":"Production permits a different configuration after deletion; Pyric retains the runtime backend lock and rejects the reinitialization","status":"diverged-documented","evidence":["oracle: `app-registry-delete-reinitialize-different-config` (firebase 12.13.0) + replay pins `app/multiple-configs-not-supported`","observation:app-registry-delete-reinitialize-different-config","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"qualified"},{"id":"app#24","kind":"registry-row","surface":"app","behavior":"After deletion resolves, every public FirebaseApp property accessor throws `FirebaseError` code `app/app-deleted`","status":"conforms","evidence":["oracle: `app-registry-deleted-property-access` (firebase 12.13.0) + replay: `oracle-conformance.test.ts`","observation:app-registry-deleted-property-access","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"app#25","kind":"registry-row","surface":"app","behavior":"After deletion, fresh Auth/Firestore/RTDB/Storage factories reject; cached factories return retained handles; retained Auth sign-out resolves but a new anonymous sign-in rejects `app/app-deleted`; Firestore reads report termination, RTDB refuses new refs, Storage refs remain constructible, and `getAI(deletedApp)` returns an app-associated handle","status":"conforms","evidence":["oracles: `app-registry-deleted-service-factories` and real-Chromium `app-production-multi-app-topology` (firebase 12.13.0) + replays: `oracle-conformance.test.ts`, `deleted-service-lifecycle.test.ts`, and `production-multi-app-oracle.test.ts`","observation:app-registry-deleted-service-factories","observation:app-production-multi-app-topology","packages/pyric/test/app/oracle-conformance.test.ts","packages/pyric/test/app/deleted-service-lifecycle.test.ts","packages/pyric/test/app/production-multi-app-oracle.test.ts"],"assurance":"eligible"},{"id":"app#26","kind":"registry-row","surface":"app","behavior":"Deleting one app terminates its Firestore listener through the error callback with code `aborted`, silently stops its RTDB listener, and leaves equal-config sibling listeners and the shared backend usable","status":"conforms","evidence":["oracle: `app-production-multi-app-topology` (firebase 12.13.0, real Chromium against production) + twin replay: `production-multi-app-oracle.test.ts`; focused family tests: `multi-app-listener-auth.test.ts` and served `app-multi-app.pw.ts`","observation:app-production-multi-app-topology","packages/pyric/test/app/production-multi-app-oracle.test.ts","packages/pyric/test/app/multi-app-listener-auth.test.ts","packages/cli/test/e2e/app-multi-app.pw.ts"],"assurance":"eligible"},{"id":"app#27","kind":"registry-row","surface":"app","behavior":"Served worker mode rejects page-local custom AnswerEngine objects; a model retained from a deleted app rejects, while an equal-config sibling model remains usable through its own app-scoped worker port","status":"unverified","evidence":["`packages/cli/test/e2e/app-deletion.pw.ts` observes AI code `unsupported` for a custom engine, then exercises retained and sibling models through canonical served imports after deleting one app; `packages/pyric/src/ai/sandbox-plane.ts` guards every model operation. A credentialed production AI lifecycle capture is still needed"],"assurance":"qualified"},{"id":"app#9","kind":"registry-row","surface":"app","behavior":"`deleteApp(app)` returns a Promise, deregisters the app (so `getApps()` shrinks), a later `getApp(name)` throws `app/no-app`, and the name can be re-initialized afterwards","status":"conforms","evidence":["oracle: `app-registry-deleteapp` (firebase 12.13.0) + replay: `oracle-conformance.test.ts`","observation:app-registry-deleteapp","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"deleteDoc","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"deleteDoc is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:deleteDoc","kind":"runtime-export","surface":"firestore","behavior":"deleteDoc is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#38","kind":"registry-row","surface":"firestore","behavior":"Removes the document; subsequent `getDoc` returns `exists()===false`","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#39","kind":"registry-row","surface":"firestore","behavior":"Idempotent — `deleteDoc` on missing doc resolves without throwing (matches JS SDK)","status":"conforms","evidence":["`unit:deletedoc-missing.test.ts`, `playground:firestore-deletedoc-missing`, oracle: `packages/conformance/observations/firestore/firestore-deletedoc-missing.json`","observation:firestore-deletedoc-missing"],"assurance":"eligible"},{"id":"firestore#40","kind":"registry-row","surface":"firestore","behavior":"Rules-denied delete throws `permission-denied`","status":"conforms","evidence":["`unit:sandbox-target.test.ts` (rules-reject branch), oracle: `packages/conformance/observations/firestore/firestore-delete-denied-error-code.json` (prod `deleteDoc` on a denied path throws a `FirebaseError` with `.code === 'permission-denied'`, `.message === '7 PERMISSION_DENIED: Missing or insufficient permissions.'`, `instanceof Error`)","observation:firestore-delete-denied-error-code","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"deleteField","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"deleteField is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:deleteField","kind":"runtime-export","surface":"firestore","behavior":"deleteField is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#103","kind":"registry-row","surface":"firestore","behavior":"`deleteField()` removes a field on update — the field is fully absent from the returned data, not merely undefined-valued. Legal at the top level or via a **dot-path** (`{'a.b': deleteField()}` removes the nested leaf — FS-B5). **Nested inside a map literal (`{a: {b: deleteField()}}`) it throws `invalid-argument` (FS-B13)** instead of destroying the sibling map.","status":"conforms","evidence":["`playground:firestore-sentinels` (bundled) + `playground:firestore-row-103-deletefield-removes-field` (one-claim), oracle: `packages/conformance/observations/firestore/firestore-row-103-deletefield-removes-field.json` — `setDoc({keep:1, remove:2})` then `updateDoc({remove: deleteField()})` yields a doc whose `data()` has keys `['keep']` only, `keep === 1` preserved; `unit:admin-compat/nested-delete-field.test.ts` (nested → invalid-argument; dot-path + top-level still valid; verified failing pre-fix)","observation:firestore-row-103-deletefield-removes-field","packages/pyric/test/sandbox/firestore/admin-compat/nested-delete-field.test.ts"],"assurance":"eligible"}]},{"feature":"deleteObject","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"deleteObject is available, has diverged fidelity, and is qualified for assurance.","caveats":["Sandbox: no-op on missing path (does NOT throw)","divergence: sandbox is no-op via `persistence.ts`'s `delete`. Prod's `deleteObject` on a missing path throws `storage/object-not-found`. Oracle-locked: `packages/conformance/observations/storage/storage-delete-missing-throws.json` (`code: 'storage/object-not-found'`, `name: 'FirebaseError'` against blockingfun, fb-js-sdk 12.13.0). Both sides pinned in `oracle-conformance.test.ts`; documented in `download.ts`."],"claims":[{"id":"storage:runtime:deleteObject","kind":"runtime-export","surface":"storage","behavior":"deleteObject is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"storage#63","kind":"registry-row","surface":"storage","behavior":"Removes both the blob AND the metadata atomically (post-delete `getBlob` throws `object-not-found`)","status":"conforms","evidence":["`unit:reference.test.ts` (\"removes both blob and metadata\")","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#64","kind":"registry-row","surface":"storage","behavior":"Sandbox: no-op on missing path (does NOT throw)","status":"diverged-documented","evidence":["divergence: sandbox is no-op via `persistence.ts`'s `delete`. Prod's `deleteObject` on a missing path throws `storage/object-not-found`. Oracle-locked: `packages/conformance/observations/storage/storage-delete-missing-throws.json` (`code: 'storage/object-not-found'`, `name: 'FirebaseError'` against blockingfun, fb-js-sdk 12.13.0). Both sides pinned in `oracle-conformance.test.ts`; documented in `download.ts`.","observation:storage-delete-missing-throws","packages/pyric/test/storage/oracle-conformance.test.ts"],"assurance":"qualified"},{"id":"storage#65","kind":"registry-row","surface":"storage","behavior":"Throws `storage/invalid-root-operation` on the root reference","status":"conforms","evidence":["`unit:reference.test.ts` (\"throws invalid-root-operation on root\")","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#66","kind":"registry-row","surface":"storage","behavior":"Prod: a successful `deleteObject` followed by `getDownloadURL` on the same ref throws `storage/object-not-found`","status":"conforms","evidence":["oracle: `packages/conformance/observations/storage/storage-delete-then-get-throws.json` (against blockingfun, fb-js-sdk 12.13.0: upload + delete succeed, then `getDownloadURL` throws `code: 'storage/object-not-found'`, message `\"Firebase Storage: Object '…' does not exist.\"`, `isFirebaseError: true`)","observation:storage-delete-then-get-throws"],"assurance":"eligible"},{"id":"storage#67","kind":"registry-row","surface":"storage","behavior":"Sandbox: writes-then-delete leaves no metadata (post-delete `getMetadata` throws `object-not-found`)","status":"conforms","evidence":["follows from #63 + `getMetadata`"],"assurance":"eligible"}]},{"feature":"deleteToken","surface":"messaging","importPaths":["pyric/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"deleteToken is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging:runtime:deleteToken","kind":"runtime-export","surface":"messaging","behavior":"deleteToken is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"messaging#3","kind":"registry-row","surface":"messaging","behavior":"Deletes the registration token and unsubscribes the instance from its push subscription; resolves truthy. After deletion no message reaches the client on either route, and a server send to the now-dead token eventually surfaces the UNREGISTERED / 404-class error on the send plane (propagation is asynchronous — the first send after delete may still be accepted while delivery has already stopped).","status":"conforms","evidence":["oracle: `messaging-web-deletetoken-unregistered.json` (deleteToken resolved truthy; no delivery to client; send plane eventually UNREGISTERED). Replayed by the conformance suite.","observation:messaging-web-deletetoken-unregistered","packages/pyric/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"deleteUser","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"deleteUser is available, has diverged fidelity, and is qualified for assurance.","caveats":["In production the POINT of re-authentication is the `auth/requires-recent-login` gate: `updateEmail` / `updatePassword` / `deleteUser` refuse to run on a session whose sign-in is older than a few minutes, and re-auth is how you clear it. The sandbox does NOT enforce that gate — those three mutations already run on a session of any age (a pre-existing documented divergence), so there is no gate here for re-auth to clear. What re-auth DOES do here is real but narrower: it genuinely re-verifies the credential, mints a fresh token, and returns `operationType: 'reauthenticate'`. Code that calls it runs unchanged against prod, where it also clears the gate.","Declared divergence, not a bug: inventing a recent-login gate would break every existing sandbox flow (which never re-authenticates) while proving nothing. `unit:sandbox-linking-reauth.test.ts` pins the behavior that IS provided (real credential re-verification + a fresh token)."],"claims":[{"id":"auth:runtime:deleteUser","kind":"runtime-export","surface":"auth","behavior":"deleteUser is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#176","kind":"registry-row","surface":"auth","behavior":"In production the POINT of re-authentication is the `auth/requires-recent-login` gate: `updateEmail` / `updatePassword` / `deleteUser` refuse to run on a session whose sign-in is older than a few minutes, and re-auth is how you clear it. The sandbox does NOT enforce that gate — those three mutations already run on a session of any age (a pre-existing documented divergence), so there is no gate here for re-auth to clear. What re-auth DOES do here is real but narrower: it genuinely re-verifies the credential, mints a fresh token, and returns `operationType: 'reauthenticate'`. Code that calls it runs unchanged against prod, where it also clears the gate.","status":"diverged-documented","evidence":["Declared divergence, not a bug: inventing a recent-login gate would break every existing sandbox flow (which never re-authenticates) while proving nothing. `unit:sandbox-linking-reauth.test.ts` pins the behavior that IS provided (real credential re-verification + a fresh token).","packages/pyric/test/auth/sandbox-linking-reauth.test.ts"],"assurance":"qualified"},{"id":"auth#83","kind":"registry-row","surface":"auth","behavior":"Deletes the account from the user store AND signs the user out if they are current (fires `onAuthStateChanged(null)`), matching prod where deleting the signed-in user clears `auth.currentUser`. Real behavior: a subsequent `signInWithEmailAndPassword` for that identity throws `auth/user-not-found`; `reload(user)` after delete rejects with `auth/user-token-expired`","status":"conforms","evidence":["`unit:fruit-aliases.test.ts` — user removed from the store, sign-out fired, re-sign-in throws `auth/user-not-found`; post-delete `reload` → `auth/user-token-expired`: `unit:upstream-auth-probes.test.ts`","packages/pyric/test/auth/fruit-aliases.test.ts","packages/pyric/test/auth/upstream-auth-probes.test.ts"],"assurance":"eligible"}]},{"feature":"denyByDefault","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"denyByDefault is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"rtdb-rules#6","kind":"registry-row","surface":"rtdb-rules","behavior":"Literal `.read`/`.write: false` — the deny-all baseline denies every op, authed or anonymous, read or write","status":"conforms","evidence":["`oracle:rules-rtdb-r6-deny-everything` — production verdicts captured by deploy-observe-restore, replayed verdict-for-verdict; all 3 cases DENY in production and in the simulator.","observation:rules-rtdb-r6-deny-everything","packages/pyric/test/rules/rtdb/rules-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"Dependencies","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"Dependencies is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:Dependencies","kind":"type-export","surface":"auth","behavior":"Dependencies is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"diff","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"diff is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#178","kind":"registry-row","surface":"firestore-rules","behavior":"Required-fields validation idiom in rules — `request.resource.data.keys().hasAll()/hasOnly()` and the `diff().addedKeys()/removedKeys()/changedKeys()/affectedKeys()/unchangedKeys()` MapDiff family gating field-level mutations","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 7 cases (exact required-field set on create, field-scoped update via MapDiff). `oracle:rules-firestore-required-fields-and-mapdiff` — replayed by `unit:rules/oracle-conformance.test.ts`.","observation:rules-firestore-required-fields-and-mapdiff","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"difference","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"difference is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#174","kind":"registry-row","surface":"firestore-rules","behavior":"`Set.difference()`/`union()`/`intersection()` (Item 5.1) in rules","status":"conforms","evidence":["`oracle:rules-firestore-set-algebra-difference-union-intersection` — production Firestore Rules Test API verdicts for corpus scenario \"set-algebra-difference-union-intersection\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`; all cases match production.","observation:rules-firestore-set-algebra-difference-union-intersection","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"disableNetwork","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"disableNetwork is available, has diverged fidelity, and is qualified for assurance.","caveats":["Resolve in the sandbox mirror — no network exists to toggle; writes issued while \"disabled\" still commit immediately (no offline queue is simulated)","`unit:firestore/persistence-network.test.ts`"],"claims":[{"id":"firestore:runtime:disableNetwork","kind":"runtime-export","surface":"firestore","behavior":"disableNetwork is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#143","kind":"registry-row","surface":"firestore","behavior":"Resolve in the sandbox mirror — no network exists to toggle; writes issued while \"disabled\" still commit immediately (no offline queue is simulated)","status":"diverged-documented","evidence":["`unit:firestore/persistence-network.test.ts`","packages/pyric/test/firestore/persistence-network.test.ts"],"assurance":"qualified"}]},{"feature":"disablePersistentCacheIndexAutoCreation","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"disablePersistentCacheIndexAutoCreation is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Index-tuning / GC-policy APIs have no real knob to turn in an in-memory sandbox today, but sibling cache-factory tokens are already honest inert tokens; these are buildable the same way and not genuinely out of scope."],"claims":[{"id":"firestore:runtime:disablePersistentCacheIndexAutoCreation","kind":"runtime-export","surface":"firestore","behavior":"Index-tuning / GC-policy APIs have no real knob to turn in an in-memory sandbox today, but sibling cache-factory tokens are already honest inert tokens; these are buildable the same way and not genuinely out of scope.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"}]},{"feature":"doc","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"doc is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:doc","kind":"runtime-export","surface":"firestore","behavior":"doc is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#10","kind":"registry-row","surface":"firestore","behavior":"`doc(coll, id)` appends under a collection ref","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#11","kind":"registry-row","surface":"firestore","behavior":"`doc(coll)` (no id) mints an auto-id `DocumentReference`","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#14","kind":"registry-row","surface":"firestore","behavior":"Unknown ref (not produced by this package) → `TypeError` with \"unrecognized reference\"","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#15","kind":"registry-row","surface":"firestore","behavior":"Held doc/coll ref under `sandbox-live` re-resolves to the chainable under the current user at op time (via rebuild closure)","status":"conforms","evidence":["`unit:sandbox-live-identity.test.ts` (\"held doc ref re-resolves under the current user\")","packages/pyric/test/firestore/sandbox-live-identity.test.ts"],"assurance":"eligible"},{"id":"firestore#7","kind":"registry-row","surface":"firestore","behavior":"`doc(db, path)` returns a tagged `DocumentReference` with `id` / `path`","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#8","kind":"registry-row","surface":"firestore","behavior":"`doc(db, 'a', 'b', 'c', 'd')` joins variadic path segments","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"DocumentChange","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"DocumentChange is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:DocumentChange","kind":"type-export","surface":"firestore","behavior":"DocumentChange is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"DocumentChangeType","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"DocumentChangeType is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:DocumentChangeType","kind":"type-export","surface":"firestore","behavior":"DocumentChangeType is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"DocumentData","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"DocumentData is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"firestore:type:DocumentData","kind":"type-export","surface":"firestore","behavior":"DocumentData is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"documentId","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"documentId is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:documentId","kind":"runtime-export","surface":"firestore","behavior":"documentId is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#106","kind":"registry-row","surface":"firestore","behavior":"The sandbox mirror owns compatible scalar constructors — `Bytes.fromUint8Array(...)`, `new GeoPoint(lat, lng)`, `new FieldPath(...)`, and `documentId()` — without importing `firebase/firestore`","status":"conforms","evidence":["`unit:sandbox-target.test.ts` (constructibility + round trips), `package-edge:package-dependencies.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts","packages/cli/test/package-dependencies.test.ts"],"assurance":"eligible"},{"id":"firestore#107","kind":"registry-row","surface":"firestore","behavior":"`documentId()` works in `where(documentId(), …)` / `orderBy(documentId())` against the sandbox — string ids, DocumentReference operands, ranges, and id sort","status":"conforms","evidence":["`unit:upstream-query-probes.test.ts` (`documentId() filters + orderBy`); modular `where`/`orderBy` accept `FieldPath`","packages/pyric/test/firestore/upstream-query-probes.test.ts"],"assurance":"eligible"}]},{"feature":"DocumentReference","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"DocumentReference is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors."],"claims":[{"id":"firestore:runtime:DocumentReference","kind":"runtime-export","surface":"firestore","behavior":"These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"},{"id":"firestore:type:DocumentReference","kind":"type-export","surface":"firestore","behavior":"DocumentReference is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"DocumentSnapshot","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"DocumentSnapshot is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors."],"claims":[{"id":"firestore:runtime:DocumentSnapshot","kind":"runtime-export","surface":"firestore","behavior":"These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"},{"id":"firestore:type:DocumentSnapshot","kind":"type-export","surface":"firestore","behavior":"DocumentSnapshot is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"documentSnapshotFromJSON","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"documentSnapshotFromJSON is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Snapshot JSON reconstruction and listener-resume helpers depend on serialized snapshot state that the sandbox has not modeled."],"claims":[{"id":"firestore:runtime:documentSnapshotFromJSON","kind":"runtime-export","surface":"firestore","behavior":"Snapshot JSON reconstruction and listener-resume helpers depend on serialized snapshot state that the sandbox has not modeled.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"}]},{"feature":"duration","surface":"firestore-rules","importPaths":["pyric/rules"],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"duration is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#160","kind":"registry-row","surface":"firestore-rules","behavior":"CEL builtins `math.*`/`timestamp.*`/`duration.*` (FM3) — arithmetic, date, and duration comparisons in rules","status":"conforms","evidence":["`oracle:rules-firestore-builtins-time-and-math` — production Firestore Rules Test API verdicts for corpus scenario \"builtins-time-and-math\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`; all cases match production.","observation:rules-firestore-builtins-time-and-math","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"firestore-rules#181","kind":"registry-row","surface":"firestore-rules","behavior":"`latlng.value().latitude()/longitude()/distance()` and `duration.value()/time()/abs()` in rules","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 2 cases (coordinate + duration bounds). `oracle:rules-firestore-duration-and-latlng` — replayed by `unit:rules/oracle-conformance.test.ts`.","observation:rules-firestore-duration-and-latlng","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"Duration","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"Duration is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#162","kind":"registry-row","surface":"firestore-rules","behavior":"Typed cross-type operator overloads for `Timestamp`/`Duration` (Item 2) in rules — no silent numeric coercion / type-identity loss","status":"conforms","evidence":["`oracle:rules-firestore-cross-type-operator-overloads` — production Firestore Rules Test API verdicts for corpus scenario \"cross-type-operator-overloads\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`; all cases match production.","observation:rules-firestore-cross-type-operator-overloads","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"duration.abs","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"duration.abs is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.function.duration.abs","kind":"rules-construct","surface":"firestore-rules","behavior":"duration.abs is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.duration#function_abs_"],"assurance":"eligible"}]},{"feature":"duration.nanos","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"duration.nanos is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"firestore.method.duration.nanos","kind":"rules-construct","surface":"firestore-rules","behavior":"duration.nanos is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.Duration#function_nanos_"],"assurance":"qualified"}]},{"feature":"duration.seconds","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"duration.seconds is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"firestore.method.duration.seconds","kind":"rules-construct","surface":"firestore-rules","behavior":"duration.seconds is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.Duration#function_seconds_"],"assurance":"qualified"}]},{"feature":"duration.time","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"duration.time is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.function.duration.time","kind":"rules-construct","surface":"firestore-rules","behavior":"duration.time is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.duration#function_time_"],"assurance":"eligible"}]},{"feature":"duration.value","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"duration.value is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.function.duration.value","kind":"rules-construct","surface":"firestore-rules","behavior":"duration.value is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.duration#function_value_"],"assurance":"eligible"}]},{"feature":"duration.value","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"duration.value is available, has conforms fidelity, and is eligible for assurance.","caveats":["duration.value(magnitude, unit) — a duration the evaluator returns as milliseconds so it adds to / subtracts from the millis-modeled timestamps, enabling the freshness idiom `request.time < resource.timeCreated + duration.value(1, 'h')`."],"claims":[{"id":"storage-rules#116","kind":"registry-row","surface":"storage-rules","behavior":"`resource.name` (full object path), `resource.timeCreated`, `resource.updated`, `resource.bucket` — the object-identity and time fields of the existing-object binding, plus `duration.value(n, unit)`","status":"conforms","evidence":["ROW CORRECTED, 2026-07-12: the fields are now modeled, sourced from the persisted object record. `oracle:rules-storage-resource-object-identity` matches production verdict-for-verdict on all 9 cases — an extension guard (`resource.name.matches`), a freshness window (`resource.timeCreated + duration.value(1, 'h')`), an immutability check (`resource.timeCreated == resource.updated`), and an absent-property negation. Production semantics pinned by the capture: `resource.name` is the object's FULL path within the bucket (GCS object-name convention, sourced from the persisted record's `fullPath`, not the client SDK's last-segment `name`); `timeCreated`/`updated` are timestamps (production rejects an int with \"Unsupported operation error. Received: int < timestamp\"); the update-time field is `updated` — there is NO `resource.timeUpdated`. An absent property is an evaluation error that absorbs to DENY and SURVIVES negation, so `resource.name != 'x'` on an object with no name denies rather than false-allowing. The prior row recorded these fields as an unsupported gap; that gap is closed.","observation:rules-storage-resource-object-identity","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.function.duration.value","kind":"rules-construct","surface":"storage-rules","behavior":"duration.value(magnitude, unit) — a duration the evaluator returns as milliseconds so it adds to / subtracts from the millis-modeled timestamps, enabling the freshness idiom `request.time < resource.timeCreated + duration.value(1, 'h')`.","status":"accepted","evidence":["https://firebase.google.com/docs/reference/security/storage/duration#value"],"assurance":"eligible"}]},{"feature":"EmailAuthCredential","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"EmailAuthCredential is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:EmailAuthCredential","kind":"runtime-export","surface":"auth","behavior":"EmailAuthCredential is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth:type:EmailAuthCredential","kind":"type-export","surface":"auth","behavior":"EmailAuthCredential is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#180","kind":"registry-row","surface":"auth","behavior":"Real classes, not markers. `EmailAuthProvider.credential(email, password)` returns an `EmailAuthCredential` that CARRIES THE SECRET — which is what makes `linkWithCredential`, `reauthenticateWithCredential`, and `signInWithCredential` decidable in the sandbox with no resolver and no mock (the backend already stores and verifies passwords). `credentialWithLink` carries the link instead, and `signInMethod` discriminates (`'password'` vs `'emailLink'`). The backing secret is non-enumerable, so a spread or `Object.keys` walk does not pick it up; `toJSON()` DOES carry it, matching upstream (whose `fromJSON` needs it to round-trip). `OAuthCredential` carries the IdP tokens, which the sandbox cannot verify — those flows keep going through the resolver seam.","status":"conforms","evidence":["`unit:sandbox-linking-reauth.test.ts` — pins the secret-carrying behavior, the enumerable/toJSON split (so nobody 'hardens' it into a divergence later), and that a real email credential now signs in via `signInWithCredential` instead of throwing the sandbox-only `auth/no-mock-configured` it used to.","packages/pyric/test/auth/sandbox-linking-reauth.test.ts"],"assurance":"eligible"}]},{"feature":"EmailAuthProvider","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"EmailAuthProvider is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["Custom scopes / params / language code","sandbox ignores; prod forwards"],"claims":[{"id":"auth:runtime:EmailAuthProvider","kind":"runtime-export","surface":"auth","behavior":"EmailAuthProvider is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth:type:EmailAuthProvider","kind":"type-export","surface":"auth","behavior":"EmailAuthProvider is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#50","kind":"registry-row","surface":"auth","behavior":"Exports the same constructor signatures as `firebase/auth` for each provider","status":"conforms","evidence":["type-only smoke in `unit:types.test.ts`","packages/pyric/test/auth/types.test.ts"],"assurance":"eligible"},{"id":"auth#51","kind":"registry-row","surface":"auth","behavior":"`Provider.credential(...)` static factories produce `AuthCredential`-shaped objects","status":"conforms","evidence":["`unit:sandbox-providers.test.ts`","packages/pyric/test/auth/sandbox-providers.test.ts"],"assurance":"eligible"},{"id":"auth#53","kind":"registry-row","surface":"auth","behavior":"Custom scopes / params / language code","status":"unsupported","evidence":["sandbox ignores; prod forwards"],"assurance":"ineligible"}]},{"feature":"EmulatorConfig","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"EmulatorConfig is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:EmulatorConfig","kind":"type-export","surface":"auth","behavior":"EmulatorConfig is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"EmulatorMockTokenOptions","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"EmulatorMockTokenOptions is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:EmulatorMockTokenOptions","kind":"type-export","surface":"firestore","behavior":"EmulatorMockTokenOptions is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"EmulatorMockTokenOptions","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"EmulatorMockTokenOptions is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"database:type:EmulatorMockTokenOptions","kind":"type-export","surface":"database","behavior":"EmulatorMockTokenOptions is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"EmulatorMockTokenOptions","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"EmulatorMockTokenOptions is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"storage:type:EmulatorMockTokenOptions","kind":"type-export","surface":"storage","behavior":"EmulatorMockTokenOptions is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"enableIndexedDbPersistence","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"enableIndexedDbPersistence is available, has diverged fidelity, and is qualified for assurance.","caveats":["Resolves in the sandbox mirror — persistence is already the default; does not reject with `'failed-precondition'` when called after other ops (deliberately more lenient than the real SDK — no cache-init race to protect)","`unit:firestore/persistence-network.test.ts`"],"claims":[{"id":"firestore:runtime:enableIndexedDbPersistence","kind":"runtime-export","surface":"firestore","behavior":"enableIndexedDbPersistence is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#140","kind":"registry-row","surface":"firestore","behavior":"Resolves in the sandbox mirror — persistence is already the default; does not reject with `'failed-precondition'` when called after other ops (deliberately more lenient than the real SDK — no cache-init race to protect)","status":"diverged-documented","evidence":["`unit:firestore/persistence-network.test.ts`","packages/pyric/test/firestore/persistence-network.test.ts"],"assurance":"qualified"}]},{"feature":"enableLogging","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"enableLogging is available, has diverged fidelity, and is qualified for assurance.","caveats":["`enableLogging(logger?, persistent?)` — accepted no-op: the sandbox has no modular-SDK-style logger to wire a level/sink into (it uses host-level `console` logging directly, matching `pyric/firestore`'s `setLogLevel`). Accepted so init code that calls it compiles + runs","`unit:modular/fruit-aliases.test.ts`"],"claims":[{"id":"database:runtime:enableLogging","kind":"runtime-export","surface":"database","behavior":"enableLogging is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#173","kind":"registry-row","surface":"rtdb-modular","behavior":"`enableLogging(logger?, persistent?)` — accepted no-op: the sandbox has no modular-SDK-style logger to wire a level/sink into (it uses host-level `console` logging directly, matching `pyric/firestore`'s `setLogLevel`). Accepted so init code that calls it compiles + runs","status":"diverged-documented","evidence":["`unit:modular/fruit-aliases.test.ts`","packages/pyric/test/database/modular/fruit-aliases.test.ts"],"assurance":"qualified"}]},{"feature":"enableMultiTabIndexedDbPersistence","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"enableMultiTabIndexedDbPersistence is available, has diverged fidelity, and is qualified for assurance.","caveats":["Resolves in the sandbox mirror — the SharedWorker path already is the one shared store every tab talks to","`unit:firestore/persistence-network.test.ts`"],"claims":[{"id":"firestore:runtime:enableMultiTabIndexedDbPersistence","kind":"runtime-export","surface":"firestore","behavior":"enableMultiTabIndexedDbPersistence is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#141","kind":"registry-row","surface":"firestore","behavior":"Resolves in the sandbox mirror — the SharedWorker path already is the one shared store every tab talks to","status":"diverged-documented","evidence":["`unit:firestore/persistence-network.test.ts`","packages/pyric/test/firestore/persistence-network.test.ts"],"assurance":"qualified"}]},{"feature":"enableNetwork","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"enableNetwork is available, has diverged fidelity, and is qualified for assurance.","caveats":["Resolve in the sandbox mirror — no network exists to toggle; writes issued while \"disabled\" still commit immediately (no offline queue is simulated)","`unit:firestore/persistence-network.test.ts`"],"claims":[{"id":"firestore:runtime:enableNetwork","kind":"runtime-export","surface":"firestore","behavior":"enableNetwork is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#143","kind":"registry-row","surface":"firestore","behavior":"Resolve in the sandbox mirror — no network exists to toggle; writes issued while \"disabled\" still commit immediately (no offline queue is simulated)","status":"diverged-documented","evidence":["`unit:firestore/persistence-network.test.ts`","packages/pyric/test/firestore/persistence-network.test.ts"],"assurance":"qualified"}]},{"feature":"enablePersistentCacheIndexAutoCreation","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"enablePersistentCacheIndexAutoCreation is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Index-tuning / GC-policy APIs have no real knob to turn in an in-memory sandbox today, but sibling cache-factory tokens are already honest inert tokens; these are buildable the same way and not genuinely out of scope."],"claims":[{"id":"firestore:runtime:enablePersistentCacheIndexAutoCreation","kind":"runtime-export","surface":"firestore","behavior":"Index-tuning / GC-policy APIs have no real knob to turn in an in-memory sandbox today, but sibling cache-factory tokens are already honest inert tokens; these are buildable the same way and not genuinely out of scope.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"}]},{"feature":"endAt","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"endAt is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:endAt","kind":"runtime-export","surface":"firestore","behavior":"endAt is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#69","kind":"registry-row","surface":"firestore","behavior":"`endAt(...values)` — inclusive end cursor","status":"conforms","evidence":["`unit:sandbox-target.test.ts`, oracle: `packages/conformance/observations/firestore/firestore-cursor-endat-inclusive.json` (5 seeded docs at pos=[1..5]; `query(c, orderBy('pos'), endAt(3))` returned exactly `[pos-1, pos-2, pos-3]` — the cursor doc IS included)","observation:firestore-cursor-endat-inclusive","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#72","kind":"registry-row","surface":"firestore","behavior":"`endAt(snapshot)` overload","status":"conforms","evidence":["`unit:sandbox-target.test.ts` (\"endAt(snapshot) trims to-and-including the anchor\")","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"endAt","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"endAt is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"database:runtime:endAt","kind":"runtime-export","surface":"database","behavior":"endAt is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#147","kind":"registry-row","surface":"rtdb-modular","behavior":"`endAt(v)` is **inclusive**","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-orderbychild-window.json` — `startAt(2) + endAt(4)` matched positions `[2,3,4]` (endAt(4) included its boundary value).","observation:rtdb-modular-orderbychild-window","observation:rtdb-modular-orderbykey-window"],"assurance":"eligible"},{"id":"rtdb-modular#M49","kind":"registry-row","surface":"rtdb-modular","behavior":"`query(ref, orderByChild(p), startAt(v), endAt(w))` window is BOTH-INCLUSIVE — children whose ordered field === `v` or === `w` are included","status":"conforms","evidence":["`unit:upstream-rtdb-probes.test.ts` (deep orderByChild nested path) + `unit:modular/queries.test.ts` (\"returns children whose ordered child is within [startAt, endAt] inclusive\"); matches oracle `rtdb-modular-orderbychild-window.json`","observation:rtdb-modular-orderbychild-window","packages/pyric/test/database/upstream-rtdb-probes.test.ts","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M50","kind":"registry-row","surface":"rtdb-modular","behavior":"`orderByKey()` orders children by RTDB `nameCompare` — integer-looking keys sort numerically FIRST (so `['1','2','10']`, not the lexicographic `['1','10','2']`), then non-integer keys lexicographically; `startAt`/`endAt` cursors + the optional `key` tie-breaker use the same order (DB-B4)","status":"conforms","evidence":["`unit:upstream-rtdb-probes.test.ts` (INT32 overflow/underflow cursors) + `unit:modular/queries.test.ts` + `unit:modular/name-compare.test.ts`; matches oracle `rtdb-modular-orderbykey-window.json` and upstream `core/util/util.ts:253-276`","packages/pyric/test/database/upstream-rtdb-probes.test.ts","packages/pyric/test/database/modular/name-compare.test.ts","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M69","kind":"registry-row","surface":"rtdb-modular","behavior":"Conflicting query constraints throw synchronously at `query(...)` construction (NOT silent last-win): multiple `orderBy*`, a second `limitToFirst`/`limitToLast`, a second start (`startAt`/`startAfter`/`equalTo`) or end (`endAt`/`endBefore`/`equalTo`) (DB-B5)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/constraint-conflicts.test.ts` (5 cases); upstream `api/Reference_impl.ts:160-165,1824-1841,1888-1905,1945-1951,2193-2206`","packages/pyric/test/database/modular/constraint-conflicts.test.ts"],"assurance":"eligible"}]},{"feature":"endBefore","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"endBefore is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:endBefore","kind":"runtime-export","surface":"firestore","behavior":"endBefore is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#70","kind":"registry-row","surface":"firestore","behavior":"`endBefore(...values)` — exclusive end cursor","status":"conforms","evidence":["`unit:sandbox-target.test.ts`, oracle: `packages/conformance/observations/firestore/firestore-cursor-endbefore-exclusive.json` (5 seeded docs at pos=[1..5]; `query(c, orderBy('pos'), endBefore(3))` returned exactly `[pos-1, pos-2]` — the cursor doc is EXCLUDED)","observation:firestore-cursor-endbefore-exclusive","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"endBefore","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"endBefore is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"database:runtime:endBefore","kind":"runtime-export","surface":"database","behavior":"endBefore is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#149","kind":"registry-row","surface":"rtdb-modular","behavior":"`endBefore(v)` is **exclusive**","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-startafter-endbefore-exclusive.json` — same probe; cursor `5` dropped.","observation:rtdb-modular-startafter-endbefore-exclusive"],"assurance":"eligible"},{"id":"rtdb-modular#M57","kind":"registry-row","surface":"rtdb-modular","behavior":"`startAfter(v)` and `endBefore(v)` are EXCLUSIVE — the boundary value is dropped from the result","status":"conforms","evidence":["Sandbox aligned: `unit:modular/queries.test.ts` (\"startAfter + endBefore drop the boundary values\"); matches oracle observation `packages/conformance/observations/rtdb-modular/rtdb-modular-startafter-endbefore-exclusive.json` (positions `[3,4]`, cursors 2 + 5 dropped).","observation:rtdb-modular-startafter-endbefore-exclusive","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M69","kind":"registry-row","surface":"rtdb-modular","behavior":"Conflicting query constraints throw synchronously at `query(...)` construction (NOT silent last-win): multiple `orderBy*`, a second `limitToFirst`/`limitToLast`, a second start (`startAt`/`startAfter`/`equalTo`) or end (`endAt`/`endBefore`/`equalTo`) (DB-B5)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/constraint-conflicts.test.ts` (5 cases); upstream `api/Reference_impl.ts:160-165,1824-1841,1888-1905,1945-1951,2193-2206`","packages/pyric/test/database/modular/constraint-conflicts.test.ts"],"assurance":"eligible"}]},{"feature":"EnhancedGenerateContentResponse","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"EnhancedGenerateContentResponse is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:EnhancedGenerateContentResponse","kind":"type-export","surface":"ai","behavior":"EnhancedGenerateContentResponse is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ensureFirestoreConfigured","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"ensureFirestoreConfigured is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["The upstream package publicly exports these low-level configuration/write helpers, but Pyric does not expose equivalent runtime plumbing yet."],"claims":[{"id":"firestore:runtime:ensureFirestoreConfigured","kind":"runtime-export","surface":"firestore","behavior":"The upstream package publicly exports these low-level configuration/write helpers, but Pyric does not expose equivalent runtime plumbing yet.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"}]},{"feature":"equalTo","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"equalTo is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"database:runtime:equalTo","kind":"runtime-export","surface":"database","behavior":"equalTo is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#145","kind":"registry-row","surface":"rtdb-modular","behavior":"`equalTo(v)` filters children whose ordered field === v (returns 0, 1, or multiple matches — RTDB does NOT enforce uniqueness)","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-query-equalto.json` — seeded `{red, blue, blue, green}`, observed `matchedKeys: ['k2', 'k3']` for `equalTo('blue')` (both blue children, none of the others). Additional probe: `packages/conformance/observations/rtdb-modular/rtdb-modular-equalTo-filter.json` (a..b..c groups) confirms `equalTo('b')` returns the two `b` children.","observation:rtdb-modular-equalTo-filter","observation:rtdb-modular-query-equalto"],"assurance":"eligible"},{"id":"rtdb-modular#M52","kind":"registry-row","surface":"rtdb-modular","behavior":"`orderByChild(p) + equalTo(v)` returns ALL children whose field at `p` === `v` — no uniqueness enforced","status":"conforms","evidence":["Sandbox aligned: `unit:modular/queries.test.ts` (\"returns ALL children whose ordered field === the supplied value\"); matches oracle observation `packages/conformance/observations/rtdb-modular/rtdb-modular-equalTo-filter.json` (both 'b'-grouped children returned).","observation:rtdb-modular-equalTo-filter","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M53","kind":"registry-row","surface":"rtdb-modular","behavior":"`equalTo` with no matches returns an empty snapshot (`exists() === false`, `numChildren() === 0`)","status":"conforms","evidence":["`unit:modular/queries.test.ts` (\"returns an empty snapshot when nothing matches\")","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M69","kind":"registry-row","surface":"rtdb-modular","behavior":"Conflicting query constraints throw synchronously at `query(...)` construction (NOT silent last-win): multiple `orderBy*`, a second `limitToFirst`/`limitToLast`, a second start (`startAt`/`startAfter`/`equalTo`) or end (`endAt`/`endBefore`/`equalTo`) (DB-B5)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/constraint-conflicts.test.ts` (5 cases); upstream `api/Reference_impl.ts:160-165,1824-1841,1888-1905,1945-1951,2193-2206`","packages/pyric/test/database/modular/constraint-conflicts.test.ts"],"assurance":"eligible"}]},{"feature":"ErrorCode","surface":"messaging","importPaths":[],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"ErrorCode is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging#12","kind":"registry-row","surface":"messaging","behavior":"Client failures surface as thrown `FirebaseError`s carrying one of the 18 documented `ErrorCode` values (`missing-app-config-values`, `only-available-in-window`, `only-available-in-sw`, `permission-default`, `permission-blocked`, `unsupported-browser`, `indexed-db-unsupported`, `failed-service-worker-registration`, `token-subscribe-failed`, `token-subscribe-no-token`, `token-unsubscribe-failed`, `token-update-failed`, `token-update-no-token`, `invalid-bg-handler`, `use-sw-after-get-token`, `invalid-sw-registration`, `use-vapid-key-after-get-token`, `invalid-vapid-key`). The enum itself is `@internal`, not a public export.","status":"conforms","evidence":["Upstream typings (`@firebase/messaging` 0.12.26 `src/util/errors`); no client-error observation among the committed set.","packages/pyric/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"ErrorDetails","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"ErrorDetails is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:ErrorDetails","kind":"type-export","surface":"ai","behavior":"ErrorDetails is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ErrorFn","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"ErrorFn is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:ErrorFn","kind":"type-export","surface":"auth","behavior":"ErrorFn is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"evaluateStorageRules","surface":"storage-rules","importPaths":["pyric/storage"],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"evaluateStorageRules is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#100","kind":"registry-row","surface":"storage-rules","behavior":"`evaluateStorageRules` supports `request.resource.size < N` constraints (with arithmetic literals like `10 * 1024 * 1024`)","status":"conforms","evidence":["`unit:rules.test.ts` (\"allows JSON writes under 10MB\")","packages/pyric/test/storage/rules.test.ts"],"assurance":"eligible"},{"id":"storage-rules#101","kind":"registry-row","surface":"storage-rules","behavior":"`evaluateStorageRules` supports `request.resource.contentType == '<mime>'` constraints","status":"conforms","evidence":["`unit:rules.test.ts` (mime constraint inside the session-archive ruleset)","packages/pyric/test/storage/rules.test.ts"],"assurance":"eligible"},{"id":"storage-rules#98","kind":"registry-row","surface":"storage-rules","behavior":"`evaluateStorageRules` matches `match /sessions/{id} { allow read: if request.auth != null; }` for an authed read","status":"conforms","evidence":["`unit:rules.test.ts` (\"allows authenticated reads of /sessions/{id}\")","packages/pyric/test/storage/rules.test.ts"],"assurance":"eligible"},{"id":"storage-rules#99","kind":"registry-row","surface":"storage-rules","behavior":"`evaluateStorageRules` denies anonymous reads when the rule requires `request.auth != null`","status":"conforms","evidence":["`unit:rules.test.ts` (\"denies anonymous reads\")","packages/pyric/test/storage/rules.test.ts"],"assurance":"eligible"}]},{"feature":"EventType","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"EventType is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"database:type:EventType","kind":"type-export","surface":"database","behavior":"EventType is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ExecutableCode","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"ExecutableCode is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:ExecutableCode","kind":"type-export","surface":"ai","behavior":"ExecutableCode is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ExecutableCodePart","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"ExecutableCodePart is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:ExecutableCodePart","kind":"type-export","surface":"ai","behavior":"ExecutableCodePart is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"executeWrite","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"executeWrite is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["The upstream package publicly exports these low-level configuration/write helpers, but Pyric does not expose equivalent runtime plumbing yet."],"claims":[{"id":"firestore:runtime:executeWrite","kind":"runtime-export","surface":"firestore","behavior":"The upstream package publicly exports these low-level configuration/write helpers, but Pyric does not expose equivalent runtime plumbing yet.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"}]},{"feature":"exists","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"exists is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["`get()` of a missing document (RULES-B8) in rules — resource identity (`id`/`__name__`) exposure on a mocked/missing get() result","`oracle:rules-firestore-get-missing-doc` — production Firestore Rules Test API verdicts for corpus scenario \"get-missing-doc\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator synthesizes a resource identity (`id`, `__name__`) for mocked get() results that production leaves absent, on 2 scenario cases — pinned KNOWN_DIVERGENCE"],"claims":[{"id":"firestore-rules#165","kind":"registry-row","surface":"firestore-rules","behavior":"`get()` of a missing document (RULES-B8) in rules — resource identity (`id`/`__name__`) exposure on a mocked/missing get() result","status":"diverged-documented","evidence":["`oracle:rules-firestore-get-missing-doc` — production Firestore Rules Test API verdicts for corpus scenario \"get-missing-doc\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator synthesizes a resource identity (`id`, `__name__`) for mocked get() results that production leaves absent, on 2 scenario cases — pinned KNOWN_DIVERGENCE","observation:rules-firestore-get-missing-doc","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"ineligible"},{"id":"firestore.function.exists","kind":"rules-construct","surface":"firestore-rules","behavior":"exists is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.firestore#function_exists_"],"assurance":"ineligible"}]},{"feature":"existsAfter","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"diverged","assurance":"ineligible","summary":"existsAfter is available, has diverged fidelity, and is ineligible for assurance.","caveats":["`getAfter()`/`existsAfter()` (Item 7) in rules — post-write document identity and existence semantics","`oracle:rules-firestore-get-after-and-exists-after` — production Firestore Rules Test API verdicts for corpus scenario \"get-after-and-exists-after\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator does not model the post-write document identity/existence production compares against on 4 scenario cases (getAfter target identity, existsAfter on create/delete, existsAfter over an unrelated mocked path) — pinned KNOWN_DIVERGENCE","Discrepancy: the simulator's evaluator implements existsAfter() (simulator/evaluator.ts case 'existsAfter'), but the parser validator's BUILTIN_FUNCTIONS set (grammar/FirestoreValidator.ts) lists only get/exists/getAfter/debug — existsAfter is absent there, so the validator alone would not recognize it as a builtin."],"claims":[{"id":"firestore-rules#164","kind":"registry-row","surface":"firestore-rules","behavior":"`getAfter()`/`existsAfter()` (Item 7) in rules — post-write document identity and existence semantics","status":"diverged-documented","evidence":["`oracle:rules-firestore-get-after-and-exists-after` — production Firestore Rules Test API verdicts for corpus scenario \"get-after-and-exists-after\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator does not model the post-write document identity/existence production compares against on 4 scenario cases (getAfter target identity, existsAfter on create/delete, existsAfter over an unrelated mocked path) — pinned KNOWN_DIVERGENCE","observation:rules-firestore-get-after-and-exists-after","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"ineligible"},{"id":"firestore.function.existsAfter","kind":"rules-construct","surface":"firestore-rules","behavior":"Discrepancy: the simulator's evaluator implements existsAfter() (simulator/evaluator.ts case 'existsAfter'), but the parser validator's BUILTIN_FUNCTIONS set (grammar/FirestoreValidator.ts) lists only get/exists/getAfter/debug — existsAfter is absent there, so the validator alone would not recognize it as a builtin.","status":"rejected","evidence":["https://firebase.google.com/docs/reference/rules/rules.firestore#function_existsAfter_","Error: firestore.rules line [5], column [23]. Function not found error: Name: [existsAfter]."],"assurance":"ineligible"}]},{"feature":"ExperimentalLongPollingOptions","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"ExperimentalLongPollingOptions is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:ExperimentalLongPollingOptions","kind":"type-export","surface":"firestore","behavior":"ExperimentalLongPollingOptions is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"experimentalSetDeliveryMetricsExportedToBigQueryEnabled","surface":"messaging","importPaths":["pyric/messaging/sw"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"experimentalSetDeliveryMetricsExportedToBigQueryEnabled is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-sw:runtime:experimentalSetDeliveryMetricsExportedToBigQueryEnabled","kind":"runtime-export","surface":"messaging-sw","behavior":"experimentalSetDeliveryMetricsExportedToBigQueryEnabled is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"messaging#15","kind":"registry-row","surface":"messaging","behavior":"Enables or disables delivery-metrics export to BigQuery at runtime; default off.","status":"conforms","evidence":["Upstream typings (`@firebase/messaging` 0.12.26 `sw/index-public`); no observation yet.","packages/pyric/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"messaging#17","kind":"registry-row","surface":"messaging","behavior":"The sw entry exports `onBackgroundMessage`, `getMessaging`, `experimentalSetDeliveryMetricsExportedToBigQueryEnabled`, and `isSupported`, but NOT `getToken` / `deleteToken` / `onMessage`; the client entry exports the latter but NOT `onBackgroundMessage` / the metrics toggle. The two modules register under different component names (`messaging` vs `messaging-sw`) and re-export identical `Messaging` / `GetTokenOptions` / `MessagePayload` / `NotificationPayload` / `FcmOptions` type declarations.","status":"conforms","evidence":["Upstream typings (`@firebase/messaging` 0.12.26 `index.d.ts` / `index.sw.d.ts`) plus Window and real module-ServiceWorker boundary replay `messaging-app-boundary.pw.ts`.","packages/pyric/test/messaging/oracle-conformance.test.ts","packages/cli/test/e2e/messaging-app-boundary.pw.ts"],"assurance":"eligible"}]},{"feature":"FacebookAuthProvider","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"FacebookAuthProvider is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"auth:runtime:FacebookAuthProvider","kind":"runtime-export","surface":"auth","behavior":"FacebookAuthProvider is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth:type:FacebookAuthProvider","kind":"type-export","surface":"auth","behavior":"FacebookAuthProvider is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"FactorId","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"FactorId is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["MFA / phone / reCAPTCHA is deferred, not out of scope — reCAPTCHA/SMS are external infrastructure Pyric can mock with the OAuth resolver pattern, and TOTP is pure algorithm work."],"claims":[{"id":"auth:runtime:FactorId","kind":"runtime-export","surface":"auth","behavior":"MFA / phone / reCAPTCHA is deferred, not out of scope — reCAPTCHA/SMS are external infrastructure Pyric can mock with the OAuth resolver pattern, and TOTP is pure algorithm work.","status":"deferred","evidence":["registry:auth#180"],"assurance":"not-applicable"}]},{"feature":"FcmOptions","surface":"messaging","importPaths":["pyric/messaging","pyric/messaging/sw"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"FcmOptions is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"messaging-sw:type:FcmOptions","kind":"type-export","surface":"messaging-sw","behavior":"FcmOptions is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"messaging:type:FcmOptions","kind":"type-export","surface":"messaging","behavior":"FcmOptions is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"FcmOptions","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"FcmOptions is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#17","kind":"registry-row","surface":"messaging-admin","behavior":"Platform-independent FCM options (`analyticsLabel`).","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `messaging-api`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"fetchSignInMethodsForEmail","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"out-of-scope","fidelity":"not-applicable","assurance":"not-applicable","summary":"fetchSignInMethodsForEmail is out-of-scope; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Deprecated upstream as a security retraction, not a cosmetic one: the shipped @firebase/auth declaration states it \"returns an empty list when Email Enumeration Protection is enabled, irrespective of the number of authentication methods available\", and that \"migrating off of this method is recommended as a security best-practice\". Enumeration protection is on by default, so against a modern project the production function always returns []. A mirror that reproduced the pre-deprecation behavior would be MORE capable than prod and would silently mislead agent code that branches on the result; a mirror that reproduced the post-deprecation behavior would be a no-op. Same criterion applied to Imagen in firebase/ai — an API whose production counterpart is retiring is out of scope, because mirroring it freezes dead behavior.","Not implemented; disposition `auth.email-enumeration` owns the reviewed availability and rationale.","disposition:auth.email-enumeration; the `auth-fetchsigninmethodsforemail-deprecated` capture is retained but inconclusive because the oracle project's Email/Password provider is disabled."],"claims":[{"id":"auth:runtime:fetchSignInMethodsForEmail","kind":"runtime-export","surface":"auth","behavior":"Deprecated upstream as a security retraction, not a cosmetic one: the shipped @firebase/auth declaration states it \"returns an empty list when Email Enumeration Protection is enabled, irrespective of the number of authentication methods available\", and that \"migrating off of this method is recommended as a security best-practice\". Enumeration protection is on by default, so against a modern project the production function always returns []. A mirror that reproduced the pre-deprecation behavior would be MORE capable than prod and would silently mislead agent code that branches on the result; a mirror that reproduced the post-deprecation behavior would be a no-op. Same criterion applied to Imagen in firebase/ai — an API whose production counterpart is retiring is out of scope, because mirroring it freezes dead behavior.","status":"out-of-scope","evidence":["registry:auth#175","upstream:firebase/auth"],"assurance":"not-applicable"},{"id":"auth#175","kind":"registry-row","surface":"auth","behavior":"Not implemented; disposition `auth.email-enumeration` owns the reviewed availability and rationale.","status":"unsupported","evidence":["disposition:auth.email-enumeration; the `auth-fetchsigninmethodsforemail-deprecated` capture is retained but inconclusive because the oracle project's Email/Password provider is disabled.","observation:auth-fetchsigninmethodsforemail-deprecated"],"assurance":"ineligible"}]},{"feature":"FieldPath","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"FieldPath is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:FieldPath","kind":"runtime-export","surface":"firestore","behavior":"FieldPath is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore:type:FieldPath","kind":"type-export","surface":"firestore","behavior":"FieldPath is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#106","kind":"registry-row","surface":"firestore","behavior":"The sandbox mirror owns compatible scalar constructors — `Bytes.fromUint8Array(...)`, `new GeoPoint(lat, lng)`, `new FieldPath(...)`, and `documentId()` — without importing `firebase/firestore`","status":"conforms","evidence":["`unit:sandbox-target.test.ts` (constructibility + round trips), `package-edge:package-dependencies.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts","packages/cli/test/package-dependencies.test.ts"],"assurance":"eligible"},{"id":"firestore#108","kind":"registry-row","surface":"firestore","behavior":"`FieldPath` (nested) works in queries against sandbox","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"FieldValue","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"FieldValue is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:FieldValue","kind":"runtime-export","surface":"firestore","behavior":"FieldValue is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore:type:FieldValue","kind":"type-export","surface":"firestore","behavior":"FieldValue is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#105","kind":"registry-row","surface":"firestore","behavior":"`FieldValue` re-exported from `pyric-admin` (alias of `ChainFieldValue`)","status":"conforms","evidence":["type-only smoke"],"assurance":"eligible"}]},{"feature":"FileData","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"FileData is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:FileData","kind":"type-export","surface":"ai","behavior":"FileData is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"FileDataPart","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"FileDataPart is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:FileDataPart","kind":"type-export","surface":"ai","behavior":"FileDataPart is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"FinishReason","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"FinishReason is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:FinishReason","kind":"runtime-export","surface":"ai","behavior":"FinishReason is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:FinishReason","kind":"type-export","surface":"ai","behavior":"FinishReason is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"FirebaseApp","surface":"app","importPaths":["pyric/app"],"evidenceSlug":"app-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"FirebaseApp is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"app:type:FirebaseApp","kind":"type-export","surface":"app","behavior":"FirebaseApp is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"FirebaseAppSettings","surface":"app","importPaths":["pyric/app"],"evidenceSlug":"app-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"FirebaseAppSettings is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"app:type:FirebaseAppSettings","kind":"type-export","surface":"app","behavior":"FirebaseAppSettings is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"FirebaseError","surface":"app","importPaths":["pyric/app"],"evidenceSlug":"app-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"FirebaseError is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"app:runtime:FirebaseError","kind":"runtime-export","surface":"app","behavior":"FirebaseError is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"app:type:FirebaseError","kind":"type-export","surface":"app","behavior":"FirebaseError is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"app#12","kind":"registry-row","surface":"app","behavior":"`FirebaseError` is an app-owned Error subclass: `instanceof Error`, `constructor.name` is `'FirebaseError'`, and it preserves `.code` and `.message` without loading `firebase/app`","status":"conforms","evidence":["oracle: `app-registry-firebaseerror-shape` (firebase 12.13.0) + replay: `oracle-conformance.test.ts`","observation:app-registry-firebaseerror-shape","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"FirebaseMessagingError","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"FirebaseMessagingError is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#38","kind":"registry-row","surface":"messaging-admin","behavior":"The exported admin messaging error type.","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `lib/messaging/index`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"FirebaseOptions","surface":"app","importPaths":["pyric/app"],"evidenceSlug":"app-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"FirebaseOptions is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"app:type:FirebaseOptions","kind":"type-export","surface":"app","behavior":"FirebaseOptions is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"FirebaseServerApp","surface":"app","importPaths":["pyric/app"],"evidenceSlug":"app-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"FirebaseServerApp is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"app:type:FirebaseServerApp","kind":"type-export","surface":"app","behavior":"FirebaseServerApp is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"FirebaseServerAppSettings","surface":"app","importPaths":["pyric/app"],"evidenceSlug":"app-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"FirebaseServerAppSettings is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"app:type:FirebaseServerAppSettings","kind":"type-export","surface":"app","behavior":"FirebaseServerAppSettings is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"FirebaseStorage","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"FirebaseStorage is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"storage:type:FirebaseStorage","kind":"type-export","surface":"storage","behavior":"FirebaseStorage is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"Firestore","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"Firestore is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors."],"claims":[{"id":"firestore:runtime:Firestore","kind":"runtime-export","surface":"firestore","behavior":"These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"},{"id":"firestore:type:Firestore","kind":"type-export","surface":"firestore","behavior":"Firestore is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"firestore.exists","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"firestore.exists is available, has conforms fidelity, and is eligible for assurance.","caveats":["Discrepancy: firestore.exists() — same standalone limitation as firestore.get(); resolved only with an injected FirestoreLookup, otherwise denies-with-reason."],"claims":[{"id":"storage-rules#115","kind":"registry-row","surface":"storage-rules","behavior":"Cross-service `firestore.get()` / `firestore.exists()` lookups from a Storage ruleset, with `$(expr)` path interpolation and qualified function-mock names","status":"conforms","evidence":["NEW ROW, 2026-07-10: production capture proves the evaluator resolves cross-service Firestore lookups from Storage rules, including interpolated document paths and both the map-returning `get()` and bool-returning `exists()` forms. `oracle:rules-storage-firestore-lookup` matches production verdict-for-verdict on all 4 cases.","observation:rules-storage-firestore-lookup","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.function.firestore.exists","kind":"rules-construct","surface":"storage-rules","behavior":"Discrepancy: firestore.exists() — same standalone limitation as firestore.get(); resolved only with an injected FirestoreLookup, otherwise denies-with-reason.","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions#firestore"],"assurance":"eligible"}]},{"feature":"firestore.get","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"firestore.get is available, has conforms fidelity, and is eligible for assurance.","caveats":["Discrepancy: firestore.get() is in the official Storage rules language, but the standalone evaluator only resolves it when the enforcement layer injects a FirestoreLookup; the pure/test evaluator denies-with-reason (cross-document lookups are out of the standalone subset)."],"claims":[{"id":"storage-rules#115","kind":"registry-row","surface":"storage-rules","behavior":"Cross-service `firestore.get()` / `firestore.exists()` lookups from a Storage ruleset, with `$(expr)` path interpolation and qualified function-mock names","status":"conforms","evidence":["NEW ROW, 2026-07-10: production capture proves the evaluator resolves cross-service Firestore lookups from Storage rules, including interpolated document paths and both the map-returning `get()` and bool-returning `exists()` forms. `oracle:rules-storage-firestore-lookup` matches production verdict-for-verdict on all 4 cases.","observation:rules-storage-firestore-lookup","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.function.firestore.get","kind":"rules-construct","surface":"storage-rules","behavior":"Discrepancy: firestore.get() is in the official Storage rules language, but the standalone evaluator only resolves it when the enforcement layer injects a FirestoreLookup; the pure/test evaluator denies-with-reason (cross-document lookups are out of the standalone subset).","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions#firestore"],"assurance":"eligible"}]},{"feature":"FirestoreDataConverter","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"FirestoreDataConverter is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"firestore:type:FirestoreDataConverter","kind":"type-export","surface":"firestore","behavior":"FirestoreDataConverter is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"FirestoreError","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"FirestoreError is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","Public type export is not mirrored."],"claims":[{"id":"firestore:runtime:FirestoreError","kind":"runtime-export","surface":"firestore","behavior":"These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"},{"id":"firestore:type:FirestoreError","kind":"type-export","surface":"firestore","behavior":"FirestoreError is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"FirestoreErrorCode","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"FirestoreErrorCode is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:FirestoreErrorCode","kind":"type-export","surface":"firestore","behavior":"FirestoreErrorCode is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"FirestoreLocalCache","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"FirestoreLocalCache is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:FirestoreLocalCache","kind":"type-export","surface":"firestore","behavior":"FirestoreLocalCache is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"FirestoreSettings","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"FirestoreSettings is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"firestore:type:FirestoreSettings","kind":"type-export","surface":"firestore","behavior":"FirestoreSettings is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"float","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"float is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#180","kind":"registry-row","surface":"firestore-rules","behavior":"`request.time` Timestamp accessors (year/month/day/hours/minutes/seconds/nanos/dayOfWeek/dayOfYear/toMillis/date/time), `math.floor/round/sqrt/pow/isNaN`, `int()/float()/string()` casts, `request.method`, and `>=` / `*` operators in rules","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 3 cases (request.time pinned via requestTime for determinism). `oracle:rules-firestore-time-math-and-casts` — replayed by `unit:rules/oracle-conformance.test.ts`.","observation:rules-firestore-time-math-and-casts","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"forceLongPolling","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"forceLongPolling is available, has diverged fidelity, and is qualified for assurance.","caveats":["`forceLongPolling()` — accepted no-op: transport selection is not applicable to the in-process/worker sandbox (it never opens a real socket). Accepted so init code that calls it compiles + runs","`unit:modular/fruit-aliases.test.ts`"],"claims":[{"id":"database:runtime:forceLongPolling","kind":"runtime-export","surface":"database","behavior":"forceLongPolling is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#171","kind":"registry-row","surface":"rtdb-modular","behavior":"`forceLongPolling()` — accepted no-op: transport selection is not applicable to the in-process/worker sandbox (it never opens a real socket). Accepted so init code that calls it compiles + runs","status":"diverged-documented","evidence":["`unit:modular/fruit-aliases.test.ts`","packages/pyric/test/database/modular/fruit-aliases.test.ts"],"assurance":"qualified"}]},{"feature":"forceWebSockets","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"forceWebSockets is available, has diverged fidelity, and is qualified for assurance.","caveats":["`forceWebSockets()` — accepted no-op: transport selection is not applicable to the in-process/worker sandbox (see `forceLongPolling`)","`unit:modular/fruit-aliases.test.ts`"],"claims":[{"id":"database:runtime:forceWebSockets","kind":"runtime-export","surface":"database","behavior":"forceWebSockets is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#172","kind":"registry-row","surface":"rtdb-modular","behavior":"`forceWebSockets()` — accepted no-op: transport selection is not applicable to the in-process/worker sandbox (see `forceLongPolling`)","status":"diverged-documented","evidence":["`unit:modular/fruit-aliases.test.ts`","packages/pyric/test/database/modular/fruit-aliases.test.ts"],"assurance":"qualified"}]},{"feature":"FullMetadata","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"FullMetadata is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"storage:type:FullMetadata","kind":"type-export","surface":"storage","behavior":"FullMetadata is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"function","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"function is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#182","kind":"registry-row","surface":"firestore-rules","behavior":"User-defined `function`/`let`, granular `allow get/list/update/write` verbs, the ternary operator, and a recursive `{document=**}` match in rules","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 7 cases (role-gated docs + public recursive subtree). `oracle:rules-firestore-functions-verbs-and-recursive` — replayed by `unit:rules/oracle-conformance.test.ts`.","observation:rules-firestore-functions-verbs-and-recursive","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"function","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"function is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#104","kind":"registry-row","surface":"storage-rules","behavior":"User-defined `function` definitions — `let` bindings, functions calling functions, and match-block-scoped helper functions (lexical scoping)","status":"conforms","evidence":["STALE ROW, corrected 2026-07-10: production capture proves the evaluator supports user-defined functions with `let` bindings, nested function calls, and block-scoped helpers. `oracle:rules-storage-functions-let-scope` matches production verdict-for-verdict on all 5 cases. Same-name shadowing and undefined-function calls are compile-time rejections in production and are covered by evaluator unit tests instead (they cannot be captured as a clean production verdict).","observation:rules-storage-functions-let-scope","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"FunctionCall","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"FunctionCall is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:FunctionCall","kind":"type-export","surface":"ai","behavior":"FunctionCall is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"functionCall","surface":"ai","importPaths":[],"evidenceSlug":"ai-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"functionCall is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"ai#fncall-id-present","kind":"registry-row","surface":"ai","behavior":"`functionCall.id` is present on the GoogleAI wire; the mirror emits an id on synthesized calls","status":"conforms","evidence":["Capture ai-function-call-shape (id in functionCallKeySet) replayed by packages/pyric/test/ai/function-calling.test.ts test `ai#fncall-id-present`","observation:ai-function-call-shape","packages/pyric/test/ai/function-calling.test.ts"],"assurance":"eligible"},{"id":"ai#fncall-mode-any","kind":"registry-row","surface":"ai","behavior":"Mode `ANY` forces a functionCall part in the response and the candidate finishes `STOP`","status":"conforms","evidence":["Capture ai-function-call-shape (captured under mode ANY, finishReason STOP) replayed by packages/pyric/test/ai/function-calling.test.ts test `ai#fncall-mode-any`","observation:ai-function-call-shape","packages/pyric/test/ai/function-calling.test.ts"],"assurance":"eligible"},{"id":"ai#fncall-part-shape","kind":"registry-row","surface":"ai","behavior":"A functionCall part carries the key set `args`, `id`, `name`, and `args` arrives as a parsed JSON object, not a string","status":"conforms","evidence":["Capture ai-function-call-shape (functionCallKeySet, argsIsObjectNotString) replayed by packages/pyric/test/ai/function-calling.test.ts test `ai#fncall-part-shape`","observation:ai-function-call-shape","packages/pyric/test/ai/function-calling.test.ts"],"assurance":"eligible"},{"id":"ai#fncall-round-trip","kind":"registry-row","surface":"ai","behavior":"A round trip that threads the model functionCall turn back verbatim, thoughtSignature preserved, is accepted: the answer has a text part and no further functionCall part","status":"conforms","evidence":["Capture ai-function-response-round replayed by packages/pyric/test/ai/function-calling.test.ts test `ai#fncall-round-trip`","observation:ai-function-response-round","packages/pyric/test/ai/function-calling.test.ts"],"assurance":"eligible"},{"id":"ai#fncall-signature-minted","kind":"registry-row","surface":"ai","behavior":"The engine mints a `thoughtSignature` on every functionCall part it synthesizes, so scripted tool round trips replay cleanly","status":"conforms","evidence":["`unit:function-calling.test.ts` test `ai#fncall-signature-minted` (capture ai-error-fncall-missing-thought-signature cited as the motivating rejection)","observation:ai-error-fncall-missing-thought-signature","packages/pyric/test/ai/function-calling.test.ts"],"assurance":"eligible"},{"id":"ai#fncall-thought-signature-required","kind":"registry-row","surface":"ai","behavior":"A replayed model functionCall turn lacking `thoughtSignature` is rejected 400 INVALID_ARGUMENT with the thought-signature message","status":"conforms","evidence":["Capture ai-error-fncall-missing-thought-signature replayed by packages/pyric/test/ai/function-calling.test.ts test `ai#fncall-thought-signature-required`","observation:ai-error-fncall-missing-thought-signature","packages/pyric/test/ai/function-calling.test.ts"],"assurance":"eligible"}]},{"feature":"FunctionCallingConfig","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"FunctionCallingConfig is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:FunctionCallingConfig","kind":"type-export","surface":"ai","behavior":"FunctionCallingConfig is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"FunctionCallingMode","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"FunctionCallingMode is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:FunctionCallingMode","kind":"runtime-export","surface":"ai","behavior":"FunctionCallingMode is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:FunctionCallingMode","kind":"type-export","surface":"ai","behavior":"FunctionCallingMode is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"FunctionCallPart","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"FunctionCallPart is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:FunctionCallPart","kind":"type-export","surface":"ai","behavior":"FunctionCallPart is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"functionCalls","surface":"ai","importPaths":[],"evidenceSlug":"ai-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"functionCalls is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"ai#helper-functioncalls","kind":"registry-row","surface":"ai","behavior":"`functionCalls()` returns the `FunctionCall` array from the functionCall parts, args as parsed objects","status":"conforms","evidence":["`unit:upstream-ai-probes.test.ts` (I3 text+functionCall mix) + Capture ai-function-call-shape replayed by `unit:helpers-schema.test.ts` test `ai#helper-functioncalls`","observation:ai-function-call-shape","packages/pyric/test/ai/upstream-ai-probes.test.ts","packages/pyric/test/ai/helpers-schema.test.ts"],"assurance":"eligible"}]},{"feature":"FunctionDeclaration","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"FunctionDeclaration is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:FunctionDeclaration","kind":"type-export","surface":"ai","behavior":"FunctionDeclaration is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"FunctionDeclarationsTool","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"FunctionDeclarationsTool is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:FunctionDeclarationsTool","kind":"type-export","surface":"ai","behavior":"FunctionDeclarationsTool is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"FunctionResponse","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"FunctionResponse is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:FunctionResponse","kind":"type-export","surface":"ai","behavior":"FunctionResponse is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"FunctionResponsePart","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"FunctionResponsePart is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:FunctionResponsePart","kind":"type-export","surface":"ai","behavior":"FunctionResponsePart is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"generateContent","surface":"ai","importPaths":[],"evidenceSlug":"ai-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"generateContent is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"ai#error-bad-api-key","kind":"registry-row","surface":"ai","behavior":"An invalid API key fails 400 INVALID_ARGUMENT, not 401, with ErrorInfo plus LocalizedMessage details and the message `API key not valid. Please pass a valid API key.`","status":"conforms","evidence":["Capture ai-error-bad-api-key replayed by packages/pyric/test/ai/errors-counttokens.test.ts test `ai#error-bad-api-key`","observation:ai-error-bad-api-key","packages/pyric/test/ai/errors-counttokens.test.ts"],"assurance":"eligible"},{"id":"ai#error-bad-role","kind":"registry-row","surface":"ai","behavior":"An invalid content role fails 400 INVALID_ARGUMENT and the message lists the production role vocabulary: SYSTEM, SYSTEM_1, USER, ASSISTANT, DEVELOPER, CONTEXT, USER_CONTEXT, MODEL, USER","status":"conforms","evidence":["Capture ai-error-bad-role replayed by packages/pyric/test/ai/errors-counttokens.test.ts test `ai#error-bad-role`","observation:ai-error-bad-role","packages/pyric/test/ai/errors-counttokens.test.ts"],"assurance":"eligible"},{"id":"ai#error-empty-contents","kind":"registry-row","surface":"ai","behavior":"An empty `contents` array fails 400 INVALID_ARGUMENT with the message `contents is not specified`","status":"conforms","evidence":["Capture ai-error-empty-contents replayed by packages/pyric/test/ai/errors-counttokens.test.ts test `ai#error-empty-contents`","observation:ai-error-empty-contents","packages/pyric/test/ai/errors-counttokens.test.ts"],"assurance":"eligible"},{"id":"ai#error-retired-model","kind":"registry-row","surface":"ai","behavior":"A retired model family (Gemini 1.5) fails 404 NOT_FOUND with an ErrorInfo detail and a retirement message distinct from unknown-model","status":"conforms","evidence":["Capture ai-error-retired-model replayed by packages/pyric/test/ai/errors-counttokens.test.ts test `ai#error-retired-model`","observation:ai-error-retired-model","packages/pyric/test/ai/errors-counttokens.test.ts"],"assurance":"eligible"},{"id":"ai#error-unknown-model","kind":"registry-row","surface":"ai","behavior":"A model name production has never served fails 404 NOT_FOUND with the error key set `code`, `message`, `status` and no details","status":"conforms","evidence":["Capture ai-error-unknown-model replayed by packages/pyric/test/ai/errors-counttokens.test.ts test `ai#error-unknown-model`","observation:ai-error-unknown-model","packages/pyric/test/ai/errors-counttokens.test.ts"],"assurance":"eligible"},{"id":"ai#generate-abort-signal","kind":"registry-row","surface":"ai","behavior":"A pre-aborted `SingleRequestOptions.signal` rejects the call","status":"conforms","evidence":["`unit:generate-content.test.ts` test `ai#generate-abort-signal` (no capture; upstream SingleRequestOptions contract)","packages/pyric/test/ai/generate-content.test.ts"],"assurance":"eligible"},{"id":"ai#generate-candidate-keys","kind":"registry-row","surface":"ai","behavior":"The candidate key set is `content`, `finishReason`, `index`, and `index` is present on the wire (0 for the single candidate)","status":"conforms","evidence":["Capture ai-generate-minimal-envelope (candidateHasIndexOnWire) replayed by packages/pyric/test/ai/generate-content.test.ts test `ai#generate-candidate-keys`","observation:ai-generate-minimal-envelope","packages/pyric/test/ai/generate-content.test.ts"],"assurance":"eligible"},{"id":"ai#generate-decoration-synthesized","kind":"registry-row","surface":"ai","behavior":"Token counts are minted without a tokenizer, and the minimal envelope omits `safetyRatings`, matching the captured candidate key set","status":"conforms","evidence":["Capture ai-generate-minimal-envelope replayed by packages/pyric/test/ai/generate-content.test.ts test `ai#generate-decoration-synthesized`","observation:ai-generate-minimal-envelope","packages/pyric/test/ai/generate-content.test.ts"],"assurance":"eligible"},{"id":"ai#generate-envelope-keys","kind":"registry-row","surface":"ai","behavior":"The response envelope top-level key set is exactly `candidates`, `modelVersion`, `responseId`, `usageMetadata`","status":"conforms","evidence":["Capture ai-generate-minimal-envelope replayed by packages/pyric/test/ai/generate-content.test.ts test `ai#generate-envelope-keys`","observation:ai-generate-minimal-envelope","packages/pyric/test/ai/generate-content.test.ts"],"assurance":"eligible"},{"id":"ai#generate-finish-stop","kind":"registry-row","surface":"ai","behavior":"A normal completion finishes with `finishReason` `STOP`","status":"conforms","evidence":["Capture ai-generate-minimal-envelope replayed by packages/pyric/test/ai/generate-content.test.ts test `ai#generate-finish-stop`","observation:ai-generate-minimal-envelope","packages/pyric/test/ai/generate-content.test.ts"],"assurance":"eligible"},{"id":"ai#generate-modelversion-responseid","kind":"registry-row","surface":"ai","behavior":"`modelVersion` and `responseId` are present nonempty strings; the sandbox mints them deterministically","status":"conforms","evidence":["Capture ai-generate-minimal-envelope replayed by packages/pyric/test/ai/generate-content.test.ts test `ai#generate-modelversion-responseid`","observation:ai-generate-minimal-envelope","packages/pyric/test/ai/generate-content.test.ts"],"assurance":"eligible"},{"id":"ai#generate-role-model","kind":"registry-row","surface":"ai","behavior":"Candidate content carries role `model` and the content key set is `parts`, `role`","status":"conforms","evidence":["Capture ai-generate-minimal-envelope replayed by packages/pyric/test/ai/generate-content.test.ts test `ai#generate-role-model`","observation:ai-generate-minimal-envelope","packages/pyric/test/ai/generate-content.test.ts"],"assurance":"eligible"},{"id":"ai#generate-string-request","kind":"registry-row","surface":"ai","behavior":"A plain string request is wrapped as a single user turn before it reaches the engine","status":"conforms","evidence":["`unit:generate-content.test.ts` test `ai#generate-string-request` (no capture; upstream request formatting claim)","packages/pyric/test/ai/generate-content.test.ts"],"assurance":"eligible"},{"id":"ai#generate-structured-output","kind":"registry-row","surface":"ai","behavior":"`responseMimeType` `application/json` plus a `responseSchema` yields a text part that parses as JSON with the schema key set","status":"conforms","evidence":["Capture ai-structured-output-shape replayed by packages/pyric/test/ai/generate-content.test.ts test `ai#generate-structured-output`","observation:ai-structured-output-shape","packages/pyric/test/ai/generate-content.test.ts"],"assurance":"eligible"},{"id":"ai#generate-system-instruction","kind":"registry-row","surface":"ai","behavior":"A top-level `systemInstruction` is accepted and the response envelope shape is unaffected","status":"conforms","evidence":["Capture ai-system-instruction-accepted replayed by packages/pyric/test/ai/generate-content.test.ts test `ai#generate-system-instruction`","observation:ai-system-instruction-accepted","packages/pyric/test/ai/generate-content.test.ts"],"assurance":"eligible"},{"id":"ai#generate-thinking-signature","kind":"registry-row","surface":"ai","behavior":"With `thinkingConfig` on the probe model, text parts carry `thoughtSignature` and no part is flagged `thought: true`","status":"conforms","evidence":["Capture ai-thinking-thought-parts (partKeySets, anyThoughtPart false) replayed by packages/pyric/test/ai/generate-content.test.ts test `ai#generate-thinking-signature`","observation:ai-thinking-thought-parts","packages/pyric/test/ai/generate-content.test.ts"],"assurance":"eligible"},{"id":"ai#generate-usage-key-set","kind":"registry-row","surface":"ai","behavior":"The usageMetadata key set on a minimal text call is `candidatesTokenCount`, `promptTokenCount`, `promptTokensDetails`, `serviceTier`, `totalTokenCount`","status":"conforms","evidence":["Capture ai-generate-minimal-envelope replayed by packages/pyric/test/ai/generate-content.test.ts test `ai#generate-usage-key-set`","observation:ai-generate-minimal-envelope","packages/pyric/test/ai/generate-content.test.ts"],"assurance":"eligible"},{"id":"ai#generate-usage-service-tier","kind":"registry-row","surface":"ai","behavior":"`usageMetadata.serviceTier` rides the wire even though the 2.12.0 SDK typings do not declare it","status":"conforms","evidence":["Capture ai-generate-minimal-envelope (usageServiceTierPresent) replayed by packages/pyric/test/ai/generate-content.test.ts test `ai#generate-usage-service-tier`","observation:ai-generate-minimal-envelope","packages/pyric/test/ai/generate-content.test.ts"],"assurance":"eligible"}]},{"feature":"GenerateContentCandidate","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"GenerateContentCandidate is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:GenerateContentCandidate","kind":"type-export","surface":"ai","behavior":"GenerateContentCandidate is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"GenerateContentRequest","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"GenerateContentRequest is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:GenerateContentRequest","kind":"type-export","surface":"ai","behavior":"GenerateContentRequest is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"GenerateContentResponse","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"GenerateContentResponse is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:GenerateContentResponse","kind":"type-export","surface":"ai","behavior":"GenerateContentResponse is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"GenerateContentResult","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"GenerateContentResult is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:GenerateContentResult","kind":"type-export","surface":"ai","behavior":"GenerateContentResult is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"generateContentStream","surface":"ai","importPaths":[],"evidenceSlug":"ai-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"generateContentStream is available, has diverged fidelity, and is qualified for assurance.","caveats":["The aggregated response carries the final chunk `finishReason` and `usageMetadata`","`unit:streaming.test.ts` test `ai#stream-aggregate-final-meta` (aggregation semantics derived from the framing capture)"],"claims":[{"id":"ai#error-bad-api-key","kind":"registry-row","surface":"ai","behavior":"An invalid API key fails 400 INVALID_ARGUMENT, not 401, with ErrorInfo plus LocalizedMessage details and the message `API key not valid. Please pass a valid API key.`","status":"conforms","evidence":["Capture ai-error-bad-api-key replayed by packages/pyric/test/ai/errors-counttokens.test.ts test `ai#error-bad-api-key`","observation:ai-error-bad-api-key","packages/pyric/test/ai/errors-counttokens.test.ts"],"assurance":"eligible"},{"id":"ai#error-bad-role","kind":"registry-row","surface":"ai","behavior":"An invalid content role fails 400 INVALID_ARGUMENT and the message lists the production role vocabulary: SYSTEM, SYSTEM_1, USER, ASSISTANT, DEVELOPER, CONTEXT, USER_CONTEXT, MODEL, USER","status":"conforms","evidence":["Capture ai-error-bad-role replayed by packages/pyric/test/ai/errors-counttokens.test.ts test `ai#error-bad-role`","observation:ai-error-bad-role","packages/pyric/test/ai/errors-counttokens.test.ts"],"assurance":"eligible"},{"id":"ai#error-empty-contents","kind":"registry-row","surface":"ai","behavior":"An empty `contents` array fails 400 INVALID_ARGUMENT with the message `contents is not specified`","status":"conforms","evidence":["Capture ai-error-empty-contents replayed by packages/pyric/test/ai/errors-counttokens.test.ts test `ai#error-empty-contents`","observation:ai-error-empty-contents","packages/pyric/test/ai/errors-counttokens.test.ts"],"assurance":"eligible"},{"id":"ai#error-retired-model","kind":"registry-row","surface":"ai","behavior":"A retired model family (Gemini 1.5) fails 404 NOT_FOUND with an ErrorInfo detail and a retirement message distinct from unknown-model","status":"conforms","evidence":["Capture ai-error-retired-model replayed by packages/pyric/test/ai/errors-counttokens.test.ts test `ai#error-retired-model`","observation:ai-error-retired-model","packages/pyric/test/ai/errors-counttokens.test.ts"],"assurance":"eligible"},{"id":"ai#error-unknown-model","kind":"registry-row","surface":"ai","behavior":"A model name production has never served fails 404 NOT_FOUND with the error key set `code`, `message`, `status` and no details","status":"conforms","evidence":["Capture ai-error-unknown-model replayed by packages/pyric/test/ai/errors-counttokens.test.ts test `ai#error-unknown-model`","observation:ai-error-unknown-model","packages/pyric/test/ai/errors-counttokens.test.ts"],"assurance":"eligible"},{"id":"ai#stream-aggregate-final-meta","kind":"registry-row","surface":"ai","behavior":"The aggregated response carries the final chunk `finishReason` and `usageMetadata`","status":"diverged-documented","evidence":["`unit:streaming.test.ts` test `ai#stream-aggregate-final-meta` (aggregation semantics derived from the framing capture)","packages/pyric/test/ai/streaming.test.ts"],"assurance":"qualified"},{"id":"ai#stream-async-iterable","kind":"registry-row","surface":"ai","behavior":"`result.stream` async-iterates response chunks via `for await`; each chunk is a complete GenerateContentResponse","status":"conforms","evidence":["Capture ai-generate-stream-framing replayed by packages/pyric/test/ai/streaming.test.ts test `ai#stream-async-iterable`","observation:ai-generate-stream-framing","packages/pyric/test/ai/streaming.test.ts"],"assurance":"eligible"},{"id":"ai#stream-chunk-envelope","kind":"registry-row","surface":"ai","behavior":"Every chunk carries `candidates` or `usageMetadata`","status":"conforms","evidence":["Capture ai-generate-stream-framing (everyEventHasCandidatesOrUsage) replayed by packages/pyric/test/ai/streaming.test.ts test `ai#stream-chunk-envelope`","observation:ai-generate-stream-framing","packages/pyric/test/ai/streaming.test.ts"],"assurance":"eligible"},{"id":"ai#stream-data-prefixed","kind":"registry-row","surface":"ai","behavior":"Every SSE event is `data: ` prefixed and its payload parses as a complete JSON document","status":"conforms","evidence":["Capture ai-generate-stream-framing (allEventsDataPrefixed) replayed byte-level by packages/pyric/test/ai/streaming.test.ts test `ai#stream-data-prefixed`","observation:ai-generate-stream-framing","packages/pyric/test/ai/streaming.test.ts"],"assurance":"eligible"},{"id":"ai#stream-finish-last-chunk","kind":"registry-row","surface":"ai","behavior":"`finishReason` appears only on the last chunk of a stream","status":"conforms","evidence":["Capture ai-generate-stream-framing (finishReasonOnlyOnLastChunk) replayed by packages/pyric/test/ai/streaming.test.ts test `ai#stream-finish-last-chunk`","observation:ai-generate-stream-framing","packages/pyric/test/ai/streaming.test.ts"],"assurance":"eligible"},{"id":"ai#stream-response-aggregate","kind":"registry-row","surface":"ai","behavior":"`result.response` resolves to an aggregated response whose text is the concatenation of the streamed text parts","status":"conforms","evidence":["`unit:streaming.test.ts` test `ai#stream-response-aggregate` (aggregation semantics; text values come from an explicit script)","packages/pyric/test/ai/streaming.test.ts"],"assurance":"eligible"},{"id":"ai#stream-separator-crlf","kind":"registry-row","surface":"ai","behavior":"SSE events are separated by CRLF CRLF","status":"conforms","evidence":["Capture ai-generate-stream-framing (separatorIsCrlfCrlf) replayed byte-level by packages/pyric/test/ai/streaming.test.ts test `ai#stream-separator-crlf`","observation:ai-generate-stream-framing","packages/pyric/test/ai/streaming.test.ts"],"assurance":"eligible"},{"id":"ai#stream-usage-every-chunk","kind":"registry-row","surface":"ai","behavior":"`usageMetadata` rides every chunk, not only the last one","status":"conforms","evidence":["Capture ai-generate-stream-framing (usageMetadataChunkIndexes covers all chunks) replayed by packages/pyric/test/ai/streaming.test.ts test `ai#stream-usage-every-chunk`","observation:ai-generate-stream-framing","packages/pyric/test/ai/streaming.test.ts"],"assurance":"eligible"}]},{"feature":"GenerateContentStreamResult","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"GenerateContentStreamResult is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:GenerateContentStreamResult","kind":"type-export","surface":"ai","behavior":"GenerateContentStreamResult is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"GenerationConfig","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"GenerationConfig is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:GenerationConfig","kind":"type-export","surface":"ai","behavior":"GenerationConfig is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"GenerativeContentBlob","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"GenerativeContentBlob is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:GenerativeContentBlob","kind":"type-export","surface":"ai","behavior":"GenerativeContentBlob is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"GenerativeModel","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"GenerativeModel is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:GenerativeModel","kind":"runtime-export","surface":"ai","behavior":"GenerativeModel is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:GenerativeModel","kind":"type-export","surface":"ai","behavior":"GenerativeModel is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"GeoPoint","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"GeoPoint is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:GeoPoint","kind":"runtime-export","surface":"firestore","behavior":"GeoPoint is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore:type:GeoPoint","kind":"type-export","surface":"firestore","behavior":"GeoPoint is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#106","kind":"registry-row","surface":"firestore","behavior":"The sandbox mirror owns compatible scalar constructors — `Bytes.fromUint8Array(...)`, `new GeoPoint(lat, lng)`, `new FieldPath(...)`, and `documentId()` — without importing `firebase/firestore`","status":"conforms","evidence":["`unit:sandbox-target.test.ts` (constructibility + round trips), `package-edge:package-dependencies.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts","packages/cli/test/package-dependencies.test.ts"],"assurance":"eligible"},{"id":"firestore#110","kind":"registry-row","surface":"firestore","behavior":"`GeoPoint` round-trip through the sandbox wire encoder — `GeoPoint` written via `setDoc` reads back as a `GeoPoint` instance with the same latitude / longitude","status":"conforms","evidence":["`unit:packages/pyric/test/sandbox/firestore/wire-encoder-bytes-geopoint.test.ts` + `unit:packages/pyric/test/firestore/sandbox-target.test.ts` (\"Bytes + GeoPoint round-trip\"), oracle: `packages/conformance/observations/firestore/firestore-row-110-geopoint-roundtrip.json` — `setDoc({loc: new GeoPoint(37.7749, -122.4194)})` then `getDoc` yields `loc instanceof GeoPoint === true`, `loc.constructor.name === 'GeoPoint'`, `loc.latitude === 37.7749`, `loc.longitude === -122.4194` against blockingfun. Sandbox storage uses the rules `LatLng` wrapper; `pyric/firestore` finalizes reads into its locally owned `GeoPoint` class.","observation:firestore-row-110-geopoint-roundtrip","packages/pyric/test/firestore/sandbox-target.test.ts","packages/pyric/test/sandbox/firestore/wire-encoder-bytes-geopoint.test.ts"],"assurance":"eligible"}]},{"feature":"get","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"get is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["`get()` of a missing document (RULES-B8) in rules — resource identity (`id`/`__name__`) exposure on a mocked/missing get() result","`oracle:rules-firestore-get-missing-doc` — production Firestore Rules Test API verdicts for corpus scenario \"get-missing-doc\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator synthesizes a resource identity (`id`, `__name__`) for mocked get() results that production leaves absent, on 2 scenario cases — pinned KNOWN_DIVERGENCE"],"claims":[{"id":"firestore-rules#165","kind":"registry-row","surface":"firestore-rules","behavior":"`get()` of a missing document (RULES-B8) in rules — resource identity (`id`/`__name__`) exposure on a mocked/missing get() result","status":"diverged-documented","evidence":["`oracle:rules-firestore-get-missing-doc` — production Firestore Rules Test API verdicts for corpus scenario \"get-missing-doc\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator synthesizes a resource identity (`id`, `__name__`) for mocked get() results that production leaves absent, on 2 scenario cases — pinned KNOWN_DIVERGENCE","observation:rules-firestore-get-missing-doc","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"ineligible"},{"id":"firestore.function.get","kind":"rules-construct","surface":"firestore-rules","behavior":"get is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.firestore#function_get_"],"assurance":"ineligible"}]},{"feature":"get","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"get is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"database:runtime:get","kind":"runtime-export","surface":"database","behavior":"get is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#106","kind":"registry-row","surface":"rtdb-modular","behavior":"Returns a `DataSnapshot` carrying `.val()`, `.exists()`, `.key`, `.ref`, `.size` (getter, returns child count), `.hasChildren()`, `.hasChild(path)`, `.forEach(cb)`. The legacy namespaced-SDK method `.numChildren()` is **NOT** on the modular DataSnapshot — use `.size` instead. Observed: `hasNumChildren: false`, `size: 3` for a `{a,b,c}` object, `forEachKeys: ['a','b','c']` against blockingfun, fb-js-sdk 12.13.0.","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-get-snapshot-shape.json`","observation:rtdb-modular-get-snapshot-shape","packages/pyric/test/database/modular/snapshot-shape.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#107","kind":"registry-row","surface":"rtdb-modular","behavior":"`snap.val()` returns `null` for a missing path (NOT a thrown error — RTDB diverges from Firestore here; `getDoc` returns `exists()===false` but `get` on RTDB just returns a `null`-val snapshot)","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-get-missing-path.json` — observed `threw: false, val: null, exists: false` on a never-written path against blockingfun.","observation:rtdb-modular-get-missing-path"],"assurance":"eligible"},{"id":"rtdb-modular#108","kind":"registry-row","surface":"rtdb-modular","behavior":"`snap.exists()` is `false` when `val() === null`, `true` otherwise","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-get-missing-path.json` — observed `exists: false` for `val: null`.","observation:rtdb-modular-get-missing-path"],"assurance":"eligible"},{"id":"rtdb-modular#109","kind":"registry-row","surface":"rtdb-modular","behavior":"Round-trip: `set(ref, payload)` then `get(ref)` returns the payload (lock the basic write→read invariant)","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb/rtdb-set-then-get-roundtrip.json` — the payload round-trips structurally on both sides (this row's claim holds). NOTE — adjacent divergence pinned in `oracle-conformance.test.ts`: prod returns object children in LEXICOGRAPHIC key order (the capture's `roundTripEqual: false` — a `JSON.stringify` round-trip against a non-sorted payload fails), while the sandbox preserves insertion order (stringify round-trip succeeds). Key-order-sensitive consumers behave differently.","observation:rtdb-set-then-get-roundtrip","packages/pyric/test/database/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#110","kind":"registry-row","surface":"rtdb-modular","behavior":"Rules-denied read throws a plain `Error` (NOT a `FirebaseError`) with `code: 'PERMISSION_DENIED'` (uppercase snake-case) — matches the agent-tool rows #15/#20","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb/rtdb-rules-denied-error-code.json`","observation:rtdb-rules-denied-error-code"],"assurance":"eligible"},{"id":"rtdb-modular#M24","kind":"registry-row","surface":"rtdb-modular","behavior":"Rules-denied read throws the same plain-`Error` `PERMISSION_DENIED` shape as a denied write","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-target.test.ts` (\"rules-denied get throws the same plain Error shape\"); matches oracle observation `packages/conformance/observations/rtdb/rtdb-rules-denied-error-code.json`","observation:rtdb-rules-denied-error-code","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M37e","kind":"registry-row","surface":"rtdb-modular","behavior":"Rules-denied transaction rejects with a plain `Error` whose `message === 'permission_denied'` (lowercase) and NO `.code` field — DIFFERENT from `set`/`get`'s `'PERMISSION_DENIED: Permission denied'` shape with uppercase `.code`.","status":"conforms","evidence":["Sandbox aligned: `unit:modular/transaction.test.ts` (\"rejects with a plain Error whose message is \\\"permission_denied\\\"\"); matches oracle observation `packages/conformance/observations/rtdb-modular/rtdb-modular-runtransaction-on-rules-denied-path.json` (against blockingfun: `message: 'permission_denied', code: null, constructorName: 'Error'`).","observation:rtdb-modular-runtransaction-on-rules-denied-path","packages/pyric/test/database/modular/transaction.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M66","kind":"registry-row","surface":"rtdb-modular","behavior":"Read-side array coercion: a dense integer-keyed object renders back as an array on `snap.val()` (`allIntegerKeys && maxKey < 2 * numKeys`) (DB-B2)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/normalization.test.ts` (\"a dense integer-keyed object reads back as an array\"); upstream `core/snap/ChildrenNode.ts:196-230`","packages/pyric/test/database/modular/normalization.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M8","kind":"registry-row","surface":"rtdb-modular","behavior":"`get(ref)` returns a `DataSnapshot`-shaped object with `val()`, `exists()`, `key`, `child()`, `hasChildren()`, `numChildren()`, `toJSON()`","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (snapshot shape tests)","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M9","kind":"registry-row","surface":"rtdb-modular","behavior":"`get` on an absent path resolves to `{ val: null, exists: false }` (matches `DataSnapshot.val()` contract)","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"reads return null for an absent path\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"getAdditionalUserInfo","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"getAdditionalUserInfo is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:getAdditionalUserInfo","kind":"runtime-export","surface":"auth","behavior":"getAdditionalUserInfo is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#171","kind":"registry-row","surface":"auth","behavior":"Returns `{ isNewUser, profile, providerId }`. For a fresh anonymous sign-in prod reports `{ isNewUser: true, providerId: null, profile: {} }` — `providerId` is NULL, not `'anonymous'`, because anonymous is not a federated provider. `isNewUser` is `true` for `createUserWithEmailAndPassword`, a first-time email-link sign-in, and a custom-token sign-in that minted the account; `false` for a returning `signInWithEmailAndPassword` and for every `link` / `reauthenticate`.","status":"conforms","evidence":["ORACLE-BACKED on the anonymous shape: `auth-additional-user-info-shape` captured `{isNewUser: true, providerId: null, profile: {}}` against prod. Replayed in `unit:oracle-conformance.test.ts`. Email create/sign-in + custom-token mint/return isNewUser matrix (providerId null per AUTH-B2): `unit:upstream-auth-probes.test.ts`. Email-link + link/reauth arms: `unit:sandbox-email-link.test.ts`, `unit:sandbox-linking-reauth.test.ts`.","observation:auth-additional-user-info-shape","packages/pyric/test/auth/oracle-conformance.test.ts","packages/pyric/test/auth/sandbox-email-link.test.ts","packages/pyric/test/auth/sandbox-linking-reauth.test.ts","packages/pyric/test/auth/upstream-auth-probes.test.ts"],"assurance":"eligible"}]},{"feature":"getAfter","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"diverged","assurance":"ineligible","summary":"getAfter is available, has diverged fidelity, and is ineligible for assurance.","caveats":["`getAfter()`/`existsAfter()` (Item 7) in rules — post-write document identity and existence semantics","`oracle:rules-firestore-get-after-and-exists-after` — production Firestore Rules Test API verdicts for corpus scenario \"get-after-and-exists-after\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator does not model the post-write document identity/existence production compares against on 4 scenario cases (getAfter target identity, existsAfter on create/delete, existsAfter over an unrelated mocked path) — pinned KNOWN_DIVERGENCE"],"claims":[{"id":"firestore-rules#164","kind":"registry-row","surface":"firestore-rules","behavior":"`getAfter()`/`existsAfter()` (Item 7) in rules — post-write document identity and existence semantics","status":"diverged-documented","evidence":["`oracle:rules-firestore-get-after-and-exists-after` — production Firestore Rules Test API verdicts for corpus scenario \"get-after-and-exists-after\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator does not model the post-write document identity/existence production compares against on 4 scenario cases (getAfter target identity, existsAfter on create/delete, existsAfter over an unrelated mocked path) — pinned KNOWN_DIVERGENCE","observation:rules-firestore-get-after-and-exists-after","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"ineligible"},{"id":"firestore.function.getAfter","kind":"rules-construct","surface":"firestore-rules","behavior":"getAfter is enumerated in the firestore rules-language inventory","status":"rejected","evidence":["https://firebase.google.com/docs/reference/rules/rules.firestore#function_getAfter_","Error: firestore.rules line [5], column [23]. Function not found error: Name: [getAfter]."],"assurance":"ineligible"}]},{"feature":"getAggregateFromServer","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"getAggregateFromServer is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:getAggregateFromServer","kind":"runtime-export","surface":"firestore","behavior":"getAggregateFromServer is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#76","kind":"registry-row","surface":"firestore","behavior":"`getAggregateFromServer(query, spec)` returns `{ data: () => Record<alias, number|null> }`","status":"conforms","evidence":["`unit:sandbox-target.test.ts`; collectionGroup + nested paths: `unit:upstream-write-aggregate-probes.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts","packages/pyric/test/firestore/upstream-write-aggregate-probes.test.ts"],"assurance":"eligible"}]},{"feature":"getAI","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"getAI is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"ai:runtime:getAI","kind":"runtime-export","surface":"ai","behavior":"getAI is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai#getai-app-dispatch","kind":"registry-row","surface":"ai","behavior":"After package resolution selects the mirror, `getAI(app)` uses the app's sandbox and the returned handle carries the app","status":"conforms","evidence":["`unit:instances.test.ts` test `ai#getai-app-dispatch` (package-resolution dispatch claim)","packages/pyric/test/ai/instances.test.ts"],"assurance":"eligible"},{"id":"ai#getai-default-backend","kind":"registry-row","surface":"ai","behavior":"With no options the backend defaults to `GoogleAIBackend`, `backendType` is `GOOGLE_AI`, and the AI handle location is the empty string","status":"conforms","evidence":["`unit:instances.test.ts` test `ai#getai-default-backend` (matches upstream AIOptions default)","packages/pyric/test/ai/instances.test.ts"],"assurance":"eligible"},{"id":"ai#getai-engine-option","kind":"registry-row","surface":"ai","behavior":"`getAI(sandbox, { backend: new GoogleAIBackend(), engine: { kind: \"scripted\" } })` selects the scripted engine explicitly and behaves identically to the zero-config default","status":"conforms","evidence":["`unit:instances.test.ts` test `ai#getai-engine-option` (engine seam per packages/conformance/docs/ai/cdd-deltas.md)","packages/pyric/test/ai/instances.test.ts"],"assurance":"eligible"},{"id":"ai#getai-idempotent","kind":"registry-row","surface":"ai","behavior":"Repeat `getAI` calls with the same target return a stable handle","status":"conforms","evidence":["`unit:instances.test.ts` test `ai#getai-idempotent` (no capture; structural claim)","packages/pyric/test/ai/instances.test.ts"],"assurance":"eligible"},{"id":"ai#getai-sandbox-dispatch","kind":"registry-row","surface":"ai","behavior":"`getAI(sandbox)` returns an AI handle bound to the sandbox target; a model minted from it answers through the in-process answer engine","status":"conforms","evidence":["`unit:instances.test.ts` test `ai#getai-sandbox-dispatch` (no capture; structural dispatch claim)","packages/pyric/test/ai/instances.test.ts"],"assurance":"eligible"},{"id":"ai#getai-sandbox-no-network","kind":"registry-row","surface":"ai","behavior":"The sandbox target with the scripted engine performs no network I/O for generateContent","status":"conforms","evidence":["`unit:instances.test.ts` test `ai#getai-sandbox-no-network` (ruling 1 of the engine placement deltas: the scripted engine does no I/O anywhere)","packages/pyric/test/ai/instances.test.ts"],"assurance":"eligible"}]},{"feature":"getAI","surface":"app","importPaths":[],"evidenceSlug":"app-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"getAI is available, has unverified fidelity, and is qualified for assurance.","caveats":["Served worker mode rejects page-local custom AnswerEngine objects; a model retained from a deleted app rejects, while an equal-config sibling model remains usable through its own app-scoped worker port","`packages/cli/test/e2e/app-deletion.pw.ts` observes AI code `unsupported` for a custom engine, then exercises retained and sibling models through canonical served imports after deleting one app; `packages/pyric/src/ai/sandbox-plane.ts` guards every model operation. A credentialed production AI lifecycle capture is still needed"],"claims":[{"id":"app#25","kind":"registry-row","surface":"app","behavior":"After deletion, fresh Auth/Firestore/RTDB/Storage factories reject; cached factories return retained handles; retained Auth sign-out resolves but a new anonymous sign-in rejects `app/app-deleted`; Firestore reads report termination, RTDB refuses new refs, Storage refs remain constructible, and `getAI(deletedApp)` returns an app-associated handle","status":"conforms","evidence":["oracles: `app-registry-deleted-service-factories` and real-Chromium `app-production-multi-app-topology` (firebase 12.13.0) + replays: `oracle-conformance.test.ts`, `deleted-service-lifecycle.test.ts`, and `production-multi-app-oracle.test.ts`","observation:app-registry-deleted-service-factories","observation:app-production-multi-app-topology","packages/pyric/test/app/oracle-conformance.test.ts","packages/pyric/test/app/deleted-service-lifecycle.test.ts","packages/pyric/test/app/production-multi-app-oracle.test.ts"],"assurance":"eligible"},{"id":"app#27","kind":"registry-row","surface":"app","behavior":"Served worker mode rejects page-local custom AnswerEngine objects; a model retained from a deleted app rejects, while an equal-config sibling model remains usable through its own app-scoped worker port","status":"unverified","evidence":["`packages/cli/test/e2e/app-deletion.pw.ts` observes AI code `unsupported` for a custom engine, then exercises retained and sibling models through canonical served imports after deleting one app; `packages/pyric/src/ai/sandbox-plane.ts` guards every model operation. A credentialed production AI lifecycle capture is still needed"],"assurance":"qualified"}]},{"feature":"getApp","surface":"app","importPaths":["pyric/app"],"evidenceSlug":"app-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"getApp is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"app:runtime:getApp","kind":"runtime-export","surface":"app","behavior":"getApp is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"app#5","kind":"registry-row","surface":"app","behavior":"`getApp()` with no name resolves the default app instance; its name is `'[DEFAULT]'`","status":"conforms","evidence":["oracle: `app-registry-getapp-default` (firebase 12.13.0) + replay: `oracle-conformance.test.ts`","observation:app-registry-getapp-default","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"app#6","kind":"registry-row","surface":"app","behavior":"`getApp('secondary')` resolves the named app instance; its name is `'secondary'`","status":"conforms","evidence":["oracle: `app-registry-getapp-named` (firebase 12.13.0) + replay: `oracle-conformance.test.ts`","observation:app-registry-getapp-named","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"app#7","kind":"registry-row","surface":"app","behavior":"`getApp(name)` for a name that was never initialized throws `FirebaseError` code `app/no-app`, directing the caller to `initializeApp()`","status":"conforms","evidence":["oracle: `app-registry-getapp-unknown-name` (firebase 12.13.0) + replay: `oracle-conformance.test.ts`","observation:app-registry-getapp-unknown-name","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"getApps","surface":"app","importPaths":["pyric/app"],"evidenceSlug":"app-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"getApps is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"app:runtime:getApps","kind":"runtime-export","surface":"app","behavior":"getApps is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"app#8","kind":"registry-row","surface":"app","behavior":"`getApps()` returns an array containing every registered app by identity (the exact instances, not copies)","status":"conforms","evidence":["oracle: `app-registry-getapps-contents` (firebase 12.13.0) + replay: `oracle-conformance.test.ts`","observation:app-registry-getapps-contents","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"getAuth","surface":"app","importPaths":[],"evidenceSlug":"app-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"getAuth is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"app#18","kind":"registry-row","surface":"app","behavior":"Equal-config named apps own distinct app-associated service handles while resolving the same configured RTDB and Storage backend locators","status":"conforms","evidence":["oracle: `app-registry-multi-app-service-containers` (firebase 12.13.0) + replay: `oracle-conformance.test.ts`","observation:app-registry-multi-app-service-containers","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"app#22","kind":"registry-row","surface":"app","behavior":"With a registered default app, each no-argument service factory resolves a service associated with that exact default app","status":"conforms","evidence":["oracle: `app-registry-default-service-factories` (firebase 12.13.0) + replay: `oracle-conformance.test.ts`","observation:app-registry-default-service-factories","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"app#25","kind":"registry-row","surface":"app","behavior":"After deletion, fresh Auth/Firestore/RTDB/Storage factories reject; cached factories return retained handles; retained Auth sign-out resolves but a new anonymous sign-in rejects `app/app-deleted`; Firestore reads report termination, RTDB refuses new refs, Storage refs remain constructible, and `getAI(deletedApp)` returns an app-associated handle","status":"conforms","evidence":["oracles: `app-registry-deleted-service-factories` and real-Chromium `app-production-multi-app-topology` (firebase 12.13.0) + replays: `oracle-conformance.test.ts`, `deleted-service-lifecycle.test.ts`, and `production-multi-app-oracle.test.ts`","observation:app-registry-deleted-service-factories","observation:app-production-multi-app-topology","packages/pyric/test/app/oracle-conformance.test.ts","packages/pyric/test/app/deleted-service-lifecycle.test.ts","packages/pyric/test/app/production-multi-app-oracle.test.ts"],"assurance":"eligible"}]},{"feature":"getAuth","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"getAuth is available, has unverified fidelity, and is qualified for assurance.","caveats":["Without sandbox package swapping, canonical `firebase/auth` imports remain Firebase and never enter this mirror","Direct mirror rejection is locked by `unit:package-resolution.test.ts`; an unswapped production-resolution observation is still needed"],"claims":[{"id":"auth:runtime:getAuth","kind":"runtime-export","surface":"auth","behavior":"getAuth is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#1","kind":"registry-row","surface":"auth","behavior":"Returns a stable `Auth` handle for repeated calls with the same input","status":"conforms","evidence":["`unit:sandbox-anonymous.test.ts` + canonical Node register child (`register-child.test.ts`)","packages/pyric/test/auth/sandbox-anonymous.test.ts","packages/cli/test/register/register-child.test.ts"],"assurance":"eligible"},{"id":"auth#183","kind":"registry-row","surface":"auth","behavior":"Equal-config Firebase apps have independent active Auth sessions; signing in or out on one app does not change another app's currentUser","status":"conforms","evidence":["oracle: `app-production-multi-app-topology` (firebase 12.13.0, real Chromium against production) + twin replay: `packages/pyric/test/app/production-multi-app-oracle.test.ts`","observation:app-production-multi-app-topology","packages/pyric/test/app/production-multi-app-oracle.test.ts"],"assurance":"eligible"},{"id":"auth#2","kind":"registry-row","surface":"auth","behavior":"`getAuth(sandbox)` dispatches to the sandbox backend","status":"conforms","evidence":["`unit:sandbox-anonymous.test.ts`","packages/pyric/test/auth/sandbox-anonymous.test.ts"],"assurance":"eligible"},{"id":"auth#3","kind":"registry-row","surface":"auth","behavior":"Without sandbox package swapping, canonical `firebase/auth` imports remain Firebase and never enter this mirror","status":"unverified","evidence":["Direct mirror rejection is locked by `unit:package-resolution.test.ts`; an unswapped production-resolution observation is still needed"],"assurance":"qualified"},{"id":"auth#4","kind":"registry-row","surface":"auth","behavior":"After package swapping, bare `getAuth()` resolves the registered default sandbox app; without swapping, Firebase retains its `app/no-app` behavior when no default app exists","status":"conforms","evidence":["canonical Node register child (`register-child.test.ts`) + oracle: `packages/conformance/observations/auth/auth-bare-getauth-no-default-app.json` (`code: 'app/no-app'` against blockingfun, fb-js-sdk 12.13.0 — confirms unswapped Firebase behavior)","observation:auth-bare-getauth-no-default-app","packages/cli/test/register/register-child.test.ts"],"assurance":"eligible"},{"id":"auth#5","kind":"registry-row","surface":"auth","behavior":"`auth.currentUser` is a live getter, not a snapshot — reads through to the backend on every access","status":"conforms","evidence":["implicit in `unit:sandbox-anonymous.test.ts`","packages/pyric/test/auth/sandbox-anonymous.test.ts"],"assurance":"eligible"}]},{"feature":"getBlob","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"getBlob is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage:runtime:getBlob","kind":"runtime-export","surface":"storage","behavior":"getBlob is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"storage#58","kind":"registry-row","surface":"storage","behavior":"Returns the stored bytes wrapped as a `Blob` (with `.type` from metadata)","status":"conforms","evidence":["`unit:reference.test.ts` (\"accepts a Blob and round-trips through getBlob\")","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#59","kind":"registry-row","surface":"storage","behavior":"Throws `storage/object-not-found` for missing paths","status":"conforms","evidence":["`unit:reference.test.ts` (\"throws storage/object-not-found for missing paths\")","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#60","kind":"registry-row","surface":"storage","behavior":"Honors `maxDownloadSize` same as `getBytes`","status":"conforms","evidence":["`unit:upstream-storage-probes.test.ts` (\"getBytes / getBlob return a truncated prefix when the object exceeds the cap\"; shared `fetchBlob` helper in `download.ts`)","packages/pyric/test/storage/upstream-storage-probes.test.ts"],"assurance":"eligible"},{"id":"storage#61","kind":"registry-row","surface":"storage","behavior":"Root-ref read throws `storage/invalid-root-operation`","status":"conforms","evidence":["shared via `guardNonRoot` in `download.ts`"],"assurance":"eligible"}]},{"feature":"getBytes","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"getBytes is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage:runtime:getBytes","kind":"runtime-export","surface":"storage","behavior":"getBytes is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"storage#53","kind":"registry-row","surface":"storage","behavior":"Returns the blob's contents as an `ArrayBuffer`","status":"conforms","evidence":["`unit:reference.test.ts` (\"accepts a Uint8Array\" round-trip via `getBytes`)","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#54","kind":"registry-row","surface":"storage","behavior":"Throws `storage/object-not-found` when no object exists at the path","status":"conforms","evidence":["`unit:reference.test.ts` (\"throws storage/object-not-found for missing paths\") + oracle: `packages/conformance/observations/storage/storage-delete-then-get-throws.json` (against blockingfun, fb-js-sdk 12.13.0: upload → delete → `getDownloadURL` on the deleted ref throws `FirebaseError` with `code: 'storage/object-not-found'`)","observation:storage-delete-then-get-throws","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#55","kind":"registry-row","surface":"storage","behavior":"When the object exceeds `maxDownloadSize`, returns a truncated prefix of that byte length (does not throw)","status":"conforms","evidence":["`unit:upstream-storage-probes.test.ts` (\"getBytes / getBlob return a truncated prefix when the object exceeds the cap\"). Matches upstream `getBytesInternal` / `getBlobInternal` post-fetch slice (GCS may ignore Range on small files). Prior COMPAT claim that the cap throws was wrong.","packages/pyric/test/storage/upstream-storage-probes.test.ts"],"assurance":"eligible"},{"id":"storage#56","kind":"registry-row","surface":"storage","behavior":"Just-under-cap reads succeed and return the full byte length","status":"conforms","evidence":["`unit:upstream-storage-probes.test.ts` (\"just-under-cap reads return the full object\") + `unit:reference.test.ts` (\"honors maxDownloadSizeBytes when the blob is too large\")","packages/pyric/test/storage/upstream-storage-probes.test.ts","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#57","kind":"registry-row","surface":"storage","behavior":"Throws `storage/invalid-root-operation` when called on the root reference","status":"conforms","evidence":["`unit:reference.test.ts` (\"throws invalid-root-operation on root reads\")","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"}]},{"feature":"getCountFromServer","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"getCountFromServer is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:getCountFromServer","kind":"runtime-export","surface":"firestore","behavior":"getCountFromServer is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#74","kind":"registry-row","surface":"firestore","behavior":"`getCountFromServer(query)` returns `{ data: () => ({ count: N }) }`","status":"conforms","evidence":["`unit:sandbox-target.test.ts`; collectionGroup: `unit:upstream-write-aggregate-probes.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts","packages/pyric/test/firestore/upstream-write-aggregate-probes.test.ts"],"assurance":"eligible"},{"id":"firestore#75","kind":"registry-row","surface":"firestore","behavior":"`getCountFromServer` honors `where` filters","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"getDatabase","surface":"app","importPaths":[],"evidenceSlug":"app-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"getDatabase is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"app#18","kind":"registry-row","surface":"app","behavior":"Equal-config named apps own distinct app-associated service handles while resolving the same configured RTDB and Storage backend locators","status":"conforms","evidence":["oracle: `app-registry-multi-app-service-containers` (firebase 12.13.0) + replay: `oracle-conformance.test.ts`","observation:app-registry-multi-app-service-containers","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"app#22","kind":"registry-row","surface":"app","behavior":"With a registered default app, each no-argument service factory resolves a service associated with that exact default app","status":"conforms","evidence":["oracle: `app-registry-default-service-factories` (firebase 12.13.0) + replay: `oracle-conformance.test.ts`","observation:app-registry-default-service-factories","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"app#25","kind":"registry-row","surface":"app","behavior":"After deletion, fresh Auth/Firestore/RTDB/Storage factories reject; cached factories return retained handles; retained Auth sign-out resolves but a new anonymous sign-in rejects `app/app-deleted`; Firestore reads report termination, RTDB refuses new refs, Storage refs remain constructible, and `getAI(deletedApp)` returns an app-associated handle","status":"conforms","evidence":["oracles: `app-registry-deleted-service-factories` and real-Chromium `app-production-multi-app-topology` (firebase 12.13.0) + replays: `oracle-conformance.test.ts`, `deleted-service-lifecycle.test.ts`, and `production-multi-app-oracle.test.ts`","observation:app-registry-deleted-service-factories","observation:app-production-multi-app-topology","packages/pyric/test/app/oracle-conformance.test.ts","packages/pyric/test/app/deleted-service-lifecycle.test.ts","packages/pyric/test/app/production-multi-app-oracle.test.ts"],"assurance":"eligible"}]},{"feature":"getDatabase","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"getDatabase is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["An in-module production target is intentionally absent; direct calls with a real `FirebaseApp` reject with package-resolution guidance","`unit:modular.test.ts`; production remains the responsibility of the unchanged `firebase/database` package","`getDatabase(ctx)` returns a tagged sandbox-target handle (frozen identity)","Phase 3","`getDatabase(sandbox)` returns a tagged sandbox-live handle (per-op identity)","Inactive canonical `firebase/database` imports remain the upstream package; the mirror does not create tagged production targets","package-resolution boundary; inactive RTDB canonical-import isolation is not yet claimed by this row","Two `getDatabase(sandbox)` calls share state (same underlying `LocalEnvironment`)","Handle dispatch by `TARGET_SYMBOL` brand — refs route to their owning target via a `refToTarget` WeakMap (mirror of firestore's pattern)"],"claims":[{"id":"database:runtime:getDatabase","kind":"runtime-export","surface":"database","behavior":"getDatabase is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#94","kind":"registry-row","surface":"rtdb-modular","behavior":"`getDatabase(ctx)` returns a tagged sandbox-target handle (frozen identity)","status":"unsupported","evidence":["Phase 3"],"assurance":"ineligible"},{"id":"rtdb-modular#95","kind":"registry-row","surface":"rtdb-modular","behavior":"`getDatabase(sandbox)` returns a tagged sandbox-live handle (per-op identity)","status":"unsupported","evidence":["Phase 3"],"assurance":"ineligible"},{"id":"rtdb-modular#96","kind":"registry-row","surface":"rtdb-modular","behavior":"Inactive canonical `firebase/database` imports remain the upstream package; the mirror does not create tagged production targets","status":"unverified","evidence":["package-resolution boundary; inactive RTDB canonical-import isolation is not yet claimed by this row"],"assurance":"qualified"},{"id":"rtdb-modular#97","kind":"registry-row","surface":"rtdb-modular","behavior":"`getDatabase()` (no argument) — wrapped in the playground preview to supply the sandbox; a raw mirror call rejects with package-resolution guidance","status":"conforms","evidence":["Phase 3 Tier 5: virtualized in the playground preview scope. Wired at `packages/playground/src/components/AppPreview.tsx` (slot install with bare-call wrap), `packages/playground/src/lib/preview/virtual-imports-plugin.ts` (alias map), and `packages/playground/src/lib/preview/preview-scope.ts` (type-level slot). Mirrors the `getAuth` / `getFirestore` wrap pattern. Demo fixture: `packages/playground/scripts/fixtures/rtdb-set-get-roundtrip.tsx` (bare `getDatabase()` + `set`/`get`/`remove` round-trip with anonymous sign-in) passes end-to-end through the `bun run debug:fixtures` Playwright suite."],"assurance":"eligible"},{"id":"rtdb-modular#98","kind":"registry-row","surface":"rtdb-modular","behavior":"Two `getDatabase(sandbox)` calls share state (same underlying `LocalEnvironment`)","status":"unsupported","evidence":["Phase 3"],"assurance":"ineligible"},{"id":"rtdb-modular#99","kind":"registry-row","surface":"rtdb-modular","behavior":"Handle dispatch by `TARGET_SYMBOL` brand — refs route to their owning target via a `refToTarget` WeakMap (mirror of firestore's pattern)","status":"unsupported","evidence":["Phase 3"],"assurance":"ineligible"},{"id":"rtdb-modular#M1","kind":"registry-row","surface":"rtdb-modular","behavior":"`getDatabase(ctx)` builds a sandbox-target `Database`; frozen `ctx.auth` baked in","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"getDatabase(ctx) returns a tagged Database handle\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M2","kind":"registry-row","surface":"rtdb-modular","behavior":"`getDatabase(sandbox)` builds a sandbox-live target; reads `sandbox.currentUser` per op","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"reads sandbox.currentUser at op time, not at getDatabase time\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M3","kind":"registry-row","surface":"rtdb-modular","behavior":"An in-module production target is intentionally absent; direct calls with a real `FirebaseApp` reject with package-resolution guidance","status":"unsupported","evidence":["`unit:modular.test.ts`; production remains the responsibility of the unchanged `firebase/database` package"],"assurance":"ineligible"},{"id":"rtdb-modular#M38","kind":"registry-row","surface":"rtdb-modular","behavior":"Identity-aware sandbox-live op routing — sign-in/sign-out via `pyric/auth` is observed by the next RTDB op without re-binding","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"reads sandbox.currentUser at op time, not at getDatabase time\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M39","kind":"registry-row","surface":"rtdb-modular","behavior":"Backend identity is per-`Sandbox` — two `getDatabase(sandbox)` calls on the same sandbox share data, two on different sandboxes don't","status":"conforms","evidence":["implicit via the WeakMap binding; tested transitively by `sandbox.setData` + `get` round-trips in the same test suite"],"assurance":"eligible"}]},{"feature":"getDoc","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"getDoc is available, has diverged fidelity, and is qualified for assurance.","caveats":["Rules denial throws `SandboxError('permission-denied', …)` on sandbox; `FirebaseError('permission-denied')` on prod","divergence: same code, different class — both expose `.code === 'permission-denied'`. Oracle-locked: `packages/conformance/observations/firestore/firestore-rules-denied-error.json` — prod throws a `FirebaseError` (name + constructor name both `FirebaseError`), `.code === 'permission-denied'`, `.message === '7 PERMISSION_DENIED: Missing or insufficient permissions.'`, and the value is an `instanceof Error`."],"claims":[{"id":"firestore:runtime:getDoc","kind":"runtime-export","surface":"firestore","behavior":"getDoc is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#16","kind":"registry-row","surface":"firestore","behavior":"Returns `DocumentSnapshot` with `id`, `exists` (method form), `data()`","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#17","kind":"registry-row","surface":"firestore","behavior":"`snap.exists` is normalized to method form (`snap.exists()` returns boolean) to match the modular SDK","status":"conforms","evidence":["`playground:firestore-onsnapshot` (bundled, assertion-shape compat) + `playground:firestore-row-17-snap-exists-method` (one-claim)"],"assurance":"eligible"},{"id":"firestore#18","kind":"registry-row","surface":"firestore","behavior":"`snap.data()` returns `undefined` for missing doc","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#19","kind":"registry-row","surface":"firestore","behavior":"`snap.ref` is tagged so it routes through `targetOf` in follow-up ops","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#20","kind":"registry-row","surface":"firestore","behavior":"Re-evaluates rules under current user on every call (sandbox-live) — read denied throws `permission-denied`","status":"conforms","evidence":["`unit:sandbox-live-identity.test.ts` (\"doc read denied when current user lacks read access\"), oracle: `packages/conformance/observations/firestore/firestore-read-denied-error-code.json` (prod `getDoc` on a denied path throws a `FirebaseError` with `.code === 'permission-denied'`, `.message === 'Missing or insufficient permissions.'`, `instanceof Error`)","observation:firestore-read-denied-error-code","packages/pyric/test/firestore/sandbox-live-identity.test.ts","packages/pyric/test/sandbox/firestore/admin-compat/query-rules-enforcement.test.ts"],"assurance":"eligible"},{"id":"firestore#21","kind":"registry-row","surface":"firestore","behavior":"Rules denial throws `SandboxError('permission-denied', …)` on sandbox; `FirebaseError('permission-denied')` on prod","status":"diverged-documented","evidence":["divergence: same code, different class — both expose `.code === 'permission-denied'`. Oracle-locked: `packages/conformance/observations/firestore/firestore-rules-denied-error.json` — prod throws a `FirebaseError` (name + constructor name both `FirebaseError`), `.code === 'permission-denied'`, `.message === '7 PERMISSION_DENIED: Missing or insufficient permissions.'`, and the value is an `instanceof Error`.","observation:firestore-rules-denied-error"],"assurance":"qualified"}]},{"feature":"getDocFromCache","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"getDocFromCache is available, has diverged fidelity, and is qualified for assurance.","caveats":["Delegates to `getDoc` / `getDocs` in the sandbox mirror. Real Firebase THROWS `'unavailable'` here on a genuine cache miss; pyric never misses — the local store always has the answer (or a non-existent snapshot) — so it never throws for that reason","`unit:firestore/tier1-cache-init-align.test.ts`"],"claims":[{"id":"firestore:runtime:getDocFromCache","kind":"runtime-export","surface":"firestore","behavior":"getDocFromCache is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#148","kind":"registry-row","surface":"firestore","behavior":"Delegates to `getDoc` / `getDocs` in the sandbox mirror. Real Firebase THROWS `'unavailable'` here on a genuine cache miss; pyric never misses — the local store always has the answer (or a non-existent snapshot) — so it never throws for that reason","status":"diverged-documented","evidence":["`unit:firestore/tier1-cache-init-align.test.ts`","packages/pyric/test/firestore/tier1-cache-init-align.test.ts"],"assurance":"qualified"}]},{"feature":"getDocFromServer","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"getDocFromServer is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:getDocFromServer","kind":"runtime-export","surface":"firestore","behavior":"getDocFromServer is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#147","kind":"registry-row","surface":"firestore","behavior":"Delegates to `getDoc` / `getDocs` in the sandbox mirror — the sandbox store IS the authoritative source, so there is no separate server round-trip to force and no observable divergence from the default read","status":"conforms","evidence":["`unit:firestore/tier1-cache-init-align.test.ts`","packages/pyric/test/firestore/tier1-cache-init-align.test.ts"],"assurance":"eligible"}]},{"feature":"getDocs","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"getDocs is available, has diverged fidelity, and is qualified for assurance.","caveats":["Query-proof **prover scope is conservative, with full accounting and a fail-closed classifier** — user functions are inlined (nested helper-calling-helper and multi-parameter helpers included, matching production's rules-function inlining), and a `list` rule is provable only when its **entire** doc-dependence reduces to top-level AND-conjunct `resource.data.<field> == <literal>` equalities (with `request.auth.uid` pinned to the caller) each discharged by a `where(field, '==', value)` filter. Doc-dependence is decided by a fail-closed classifier: an expression counts as doc-independent only when every node is positively recognized as such — any touch of the `resource` root in any syntactic form (`resource.data`, `resource['data']`, slices, `resource.id`, path-literal segments feeding `exists`/`get` lookups) and any unrecognized node shape classifies doc-dependent. Any doc-dependent conjunct that is not a discharged equality — disjunctions over doc data, inequality/range predicates (`resource.data.score > 10` + `where('score','>',10)`), `in` / negated-`in` membership checks, `get(key, default)`, `keys().hasOnly(...)`, `is` type checks, nested-path predicates, data-keyed document lookups — makes the whole query conservatively DENY, even when every equality conjunct is discharged; production's prover may allow some of these. Divergence is deny-only: mixed equality + non-equality shapes are rejected up front rather than trusted to a residual evaluation that absent-tolerant predicates could pass vacuously.","`unit:rules/simulator/query-proof.test.ts` (function-inlining provable cases; full-accounting rejections for mixed equality + `in`/`get`/`hasOnly`/range/`is` shapes in inline and helper form; fail-closed classifier probes: bracket-access `resource['data']`, `exists()` keyed by `resource.data` through path-literal segments, slice access, `resource.id`, and an unrecognized node shape), `unit:firestore/query-proof-enforcement.test.ts` (seeded end-to-end denials of the demonstrated attacks: forbidden-field absence check in member and bracket form, banned-owner `exists()` lookup, slice conjunct — each returning zero documents)"],"claims":[{"id":"firestore:runtime:getDocs","kind":"runtime-export","surface":"firestore","behavior":"getDocs is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#22","kind":"registry-row","surface":"firestore","behavior":"Returns `QuerySnapshot` with `size`, `empty`, `docs` (`QueryDocumentSnapshot[]`)","status":"conforms","evidence":["`unit:sandbox-target.test.ts`, `playground:firestore-query`","packages/pyric/test/firestore/sandbox-target.test.ts","packages/pyric/test/firestore/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"firestore#23","kind":"registry-row","surface":"firestore","behavior":"Each `snap.docs[i].ref` is tagged for follow-up ops","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#24","kind":"registry-row","surface":"firestore","behavior":"Sandbox-live: re-evaluates filters under the current user (different docs visible per identity)","status":"conforms","evidence":["`unit:sandbox-live-identity.test.ts` (\"query results re-evaluate under the current user\")","packages/pyric/test/firestore/sandbox-live-identity.test.ts"],"assurance":"eligible"},{"id":"firestore#24a","kind":"registry-row","surface":"firestore","behavior":"**Query reads enforce security rules (FS-B1)** — a deny-all / auth-gated rule set throws `permission-denied`. Pre-FS-B1 query reads went through the rules-bypassing `listDocuments` and returned the whole collection.","status":"conforms","evidence":["`unit:admin-compat/query-rules-enforcement.test.ts` (deny-all + auth-gated `getDocs`/aggregate), `unit:admin-compat/per-op-auth.test.ts` (\"Query.get enforces rules\")","packages/pyric/test/sandbox/firestore/admin-compat/per-op-auth.test.ts","packages/pyric/test/sandbox/firestore/admin-compat/query-rules-enforcement.test.ts"],"assurance":"eligible"},{"id":"firestore#24b","kind":"registry-row","surface":"firestore","behavior":"**Enforcement follows production's QUERY-PROOF model (RULES-B11)** — \"rules are not filters\": a doc-data-dependent `list` rule (`resource.data.visibility == 'public'`, `resource.data.owner == request.auth.uid`) is ALLOWED when the query's `where()` equalities discharge it and the whole query is `permission-denied` otherwise — never silently truncated to the readable subset. Per-doc `get` rules do NOT filter query results (the `list` rule alone governs queries — granular-operations docs). Applies to `getDocs`, aggregates, and `onSnapshot` alike. Pre-fix: rules-as-filters (per-doc `get` omission) + blanket denial of every doc-data-dependent list, even provable ones.","status":"conforms","evidence":["`unit:firestore/query-proof-enforcement.test.ts` (provable/unprovable getDocs + onSnapshot, owner-pinned uid, get-rules-don't-filter, request.query.limit; verified failing pre-fix), `unit:simulator/local-environment.test.ts` (Slice 6 — flipped from per-doc-filter assertions); prod truth: firebase.google.com/docs/firestore/security/rules-query","packages/pyric/test/firestore/query-proof-enforcement.test.ts","packages/pyric/test/sandbox/firestore/simulator/local-environment.test.ts"],"assurance":"eligible"},{"id":"firestore#24c","kind":"registry-row","surface":"firestore","behavior":"Query-proof **prover scope is conservative, with full accounting and a fail-closed classifier** — user functions are inlined (nested helper-calling-helper and multi-parameter helpers included, matching production's rules-function inlining), and a `list` rule is provable only when its **entire** doc-dependence reduces to top-level AND-conjunct `resource.data.<field> == <literal>` equalities (with `request.auth.uid` pinned to the caller) each discharged by a `where(field, '==', value)` filter. Doc-dependence is decided by a fail-closed classifier: an expression counts as doc-independent only when every node is positively recognized as such — any touch of the `resource` root in any syntactic form (`resource.data`, `resource['data']`, slices, `resource.id`, path-literal segments feeding `exists`/`get` lookups) and any unrecognized node shape classifies doc-dependent. Any doc-dependent conjunct that is not a discharged equality — disjunctions over doc data, inequality/range predicates (`resource.data.score > 10` + `where('score','>',10)`), `in` / negated-`in` membership checks, `get(key, default)`, `keys().hasOnly(...)`, `is` type checks, nested-path predicates, data-keyed document lookups — makes the whole query conservatively DENY, even when every equality conjunct is discharged; production's prover may allow some of these. Divergence is deny-only: mixed equality + non-equality shapes are rejected up front rather than trusted to a residual evaluation that absent-tolerant predicates could pass vacuously.","status":"diverged-documented","evidence":["`unit:rules/simulator/query-proof.test.ts` (function-inlining provable cases; full-accounting rejections for mixed equality + `in`/`get`/`hasOnly`/range/`is` shapes in inline and helper form; fail-closed classifier probes: bracket-access `resource['data']`, `exists()` keyed by `resource.data` through path-literal segments, slice access, `resource.id`, and an unrecognized node shape), `unit:firestore/query-proof-enforcement.test.ts` (seeded end-to-end denials of the demonstrated attacks: forbidden-field absence check in member and bracket form, banned-owner `exists()` lookup, slice conjunct — each returning zero documents)","packages/pyric/test/rules/simulator/query-proof.test.ts","packages/pyric/test/firestore/query-proof-enforcement.test.ts"],"assurance":"qualified"},{"id":"firestore#25","kind":"registry-row","surface":"firestore","behavior":"Empty result for a collection with no docs (`size === 0`, `empty === true`)","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"getDocsFromCache","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"getDocsFromCache is available, has diverged fidelity, and is qualified for assurance.","caveats":["Delegates to `getDoc` / `getDocs` in the sandbox mirror. Real Firebase THROWS `'unavailable'` here on a genuine cache miss; pyric never misses — the local store always has the answer (or a non-existent snapshot) — so it never throws for that reason","`unit:firestore/tier1-cache-init-align.test.ts`"],"claims":[{"id":"firestore:runtime:getDocsFromCache","kind":"runtime-export","surface":"firestore","behavior":"getDocsFromCache is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#148","kind":"registry-row","surface":"firestore","behavior":"Delegates to `getDoc` / `getDocs` in the sandbox mirror. Real Firebase THROWS `'unavailable'` here on a genuine cache miss; pyric never misses — the local store always has the answer (or a non-existent snapshot) — so it never throws for that reason","status":"diverged-documented","evidence":["`unit:firestore/tier1-cache-init-align.test.ts`","packages/pyric/test/firestore/tier1-cache-init-align.test.ts"],"assurance":"qualified"}]},{"feature":"getDocsFromServer","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"getDocsFromServer is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:getDocsFromServer","kind":"runtime-export","surface":"firestore","behavior":"getDocsFromServer is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#147","kind":"registry-row","surface":"firestore","behavior":"Delegates to `getDoc` / `getDocs` in the sandbox mirror — the sandbox store IS the authoritative source, so there is no separate server round-trip to force and no observable divergence from the default read","status":"conforms","evidence":["`unit:firestore/tier1-cache-init-align.test.ts`","packages/pyric/test/firestore/tier1-cache-init-align.test.ts"],"assurance":"eligible"}]},{"feature":"getDownloadURL","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"getDownloadURL is available, has diverged fidelity, and is qualified for assurance.","caveats":["Exported by `firebase/storage`; returns a token-signed HTTPS URL that fetches the blob","Implemented with a two-sided pin. Production observation `storage-upload-bytes-roundtrip` records `urlIsHttps: true` and a byte-identical fetch. The sandbox oracle replay now calls the same public `getDownloadURL` + `fetch` path and proves byte-identical content, while explicitly asserting its URL starts with `blob:`. The client↔host integration proves SharedWorker mode creates that URL in the calling page after the rules-checked Blob crosses the port. The remaining divergence is URL identity and lifetime: the sandbox URL is a page-local snapshot, not token-signed HTTPS and not shareable outside that page."],"claims":[{"id":"storage:runtime:getDownloadURL","kind":"runtime-export","surface":"storage","behavior":"getDownloadURL is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"storage#51","kind":"registry-row","surface":"storage","behavior":"Exported by `firebase/storage`; returns a token-signed HTTPS URL that fetches the blob","status":"diverged-documented","evidence":["Implemented with a two-sided pin. Production observation `storage-upload-bytes-roundtrip` records `urlIsHttps: true` and a byte-identical fetch. The sandbox oracle replay now calls the same public `getDownloadURL` + `fetch` path and proves byte-identical content, while explicitly asserting its URL starts with `blob:`. The client↔host integration proves SharedWorker mode creates that URL in the calling page after the rules-checked Blob crosses the port. The remaining divergence is URL identity and lifetime: the sandbox URL is a page-local snapshot, not token-signed HTTPS and not shareable outside that page.","observation:storage-upload-bytes-roundtrip","packages/pyric/test/storage/oracle-conformance.test.ts","packages/cli/test/serve/worker/integration.test.ts"],"assurance":"qualified"},{"id":"storage#52","kind":"registry-row","surface":"storage","behavior":"Throws `storage/object-not-found` for missing objects","status":"conforms","evidence":["Production observation `storage-delete-then-get-throws` records `getDownloadURL` throwing `storage/object-not-found` after deletion. The sandbox oracle replay now invokes `getDownloadURL` itself and matches that code; the public error-code suite also pins the never-existing-object case.","observation:storage-delete-then-get-throws","packages/pyric/test/storage/error-codes.test.ts","packages/pyric/test/storage/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"getFirestore","surface":"app","importPaths":[],"evidenceSlug":"app-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"getFirestore is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"app#18","kind":"registry-row","surface":"app","behavior":"Equal-config named apps own distinct app-associated service handles while resolving the same configured RTDB and Storage backend locators","status":"conforms","evidence":["oracle: `app-registry-multi-app-service-containers` (firebase 12.13.0) + replay: `oracle-conformance.test.ts`","observation:app-registry-multi-app-service-containers","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"app#22","kind":"registry-row","surface":"app","behavior":"With a registered default app, each no-argument service factory resolves a service associated with that exact default app","status":"conforms","evidence":["oracle: `app-registry-default-service-factories` (firebase 12.13.0) + replay: `oracle-conformance.test.ts`","observation:app-registry-default-service-factories","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"app#25","kind":"registry-row","surface":"app","behavior":"After deletion, fresh Auth/Firestore/RTDB/Storage factories reject; cached factories return retained handles; retained Auth sign-out resolves but a new anonymous sign-in rejects `app/app-deleted`; Firestore reads report termination, RTDB refuses new refs, Storage refs remain constructible, and `getAI(deletedApp)` returns an app-associated handle","status":"conforms","evidence":["oracles: `app-registry-deleted-service-factories` and real-Chromium `app-production-multi-app-topology` (firebase 12.13.0) + replays: `oracle-conformance.test.ts`, `deleted-service-lifecycle.test.ts`, and `production-multi-app-oracle.test.ts`","observation:app-registry-deleted-service-factories","observation:app-production-multi-app-topology","packages/pyric/test/app/oracle-conformance.test.ts","packages/pyric/test/app/deleted-service-lifecycle.test.ts","packages/pyric/test/app/production-multi-app-oracle.test.ts"],"assurance":"eligible"}]},{"feature":"getFirestore","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"getFirestore is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:getFirestore","kind":"runtime-export","surface":"firestore","behavior":"getFirestore is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#1","kind":"registry-row","surface":"firestore","behavior":"`getFirestore(ctx)` returns a tagged sandbox-target handle (frozen identity)","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#2","kind":"registry-row","surface":"firestore","behavior":"`getFirestore(sandbox)` returns a tagged sandbox-live handle (per-op identity)","status":"conforms","evidence":["`unit:sandbox-live-identity.test.ts`","packages/pyric/test/firestore/sandbox-live-identity.test.ts"],"assurance":"eligible"},{"id":"firestore#3","kind":"registry-row","surface":"firestore","behavior":"Package resolution owns production selection: direct `pyric/firestore` rejects a real `FirebaseApp`, while inactive canonical `firebase/firestore` imports remain the real Firebase SDK","status":"conforms","evidence":["`unit:package-resolution.test.ts`, `node-register:register-child.test.ts` (inactive canonical imports are not rewritten)","packages/pyric/test/firestore/package-resolution.test.ts","packages/cli/test/register/register-child.test.ts"],"assurance":"eligible"},{"id":"firestore#4","kind":"registry-row","surface":"firestore","behavior":"`getFirestore(undefined)` is wrapped in the playground preview to default to the sandbox; production's unactivated canonical SDK still throws `app/no-app`, while a direct mirror call rejects the missing sandbox owner","status":"conforms","evidence":["`playground:firestore-bare-getfirestore` — fix from PR #397 + oracle: `packages/conformance/observations/firestore/firestore-bare-getfirestore-no-default-app.json` (`code: 'app/no-app'` against blockingfun, fb-js-sdk 12.13.0 — confirms prod throw shape)","observation:firestore-bare-getfirestore-no-default-app"],"assurance":"eligible"},{"id":"firestore#5","kind":"registry-row","surface":"firestore","behavior":"Two `getFirestore(sandbox)` calls share state (same underlying `LocalEnvironment`)","status":"conforms","evidence":["`unit:sandbox-live-identity.test.ts` (\"two handles share the same sandbox\")","packages/pyric/test/firestore/sandbox-live-identity.test.ts"],"assurance":"eligible"},{"id":"firestore#6","kind":"registry-row","surface":"firestore","behavior":"Handle dispatch by `TARGET_SYMBOL` brand — refs/queries route to their owning target via `refToTarget` WeakMap","status":"conforms","evidence":["`unit:sandbox-target.test.ts` (\"throws TypeError for refs not produced by this package\")","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"getGenerativeModel","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"getGenerativeModel is available, has diverged fidelity, and is qualified for assurance.","caveats":["A `models/`-prefixed name is accepted without double prefixing","`unit:instances.test.ts` test `ai#model-name-prefixed` (no capture; normalization claim)"],"claims":[{"id":"ai:runtime:getGenerativeModel","kind":"runtime-export","surface":"ai","behavior":"getGenerativeModel is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai#model-name-prefixed","kind":"registry-row","surface":"ai","behavior":"A `models/`-prefixed name is accepted without double prefixing","status":"diverged-documented","evidence":["`unit:instances.test.ts` test `ai#model-name-prefixed` (no capture; normalization claim)","packages/pyric/test/ai/instances.test.ts"],"assurance":"qualified"},{"id":"ai#model-name-required","kind":"registry-row","surface":"ai","behavior":"`getGenerativeModel` without `modelParams.model` throws an `AIError` with code `no-model`","status":"conforms","evidence":["`unit:instances.test.ts` test `ai#model-name-required` (upstream throw contract)","packages/pyric/test/ai/instances.test.ts"],"assurance":"eligible"},{"id":"ai#model-name-short","kind":"registry-row","surface":"ai","behavior":"A short model name such as `gemini-flash-lite-latest` normalizes to the `models/` resource name on `GenerativeModel.model`","status":"conforms","evidence":["`unit:instances.test.ts` test `ai#model-name-short` (upstream AIModel normalization on the GoogleAI backend)","packages/pyric/test/ai/instances.test.ts"],"assurance":"eligible"}]},{"feature":"getHistory","surface":"ai","importPaths":[],"evidenceSlug":"ai-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"getHistory is available, has diverged fidelity, and is qualified for assurance.","caveats":["`sendMessage` appends the user turn and the model turn; `getHistory()` returns the ordered `Content[]` with alternating roles","`unit:chat-session.test.ts` test `ai#chat-history-threads` (no capture; history threading claim)","Blocked prompts and blocked candidates are excluded from `getHistory()`","`unit:chat-session.test.ts` test `ai#chat-history-excludes-blocked` (upstream JSDoc contract; exercised with a scripted blocked envelope)"],"claims":[{"id":"ai#chat-history-excludes-blocked","kind":"registry-row","surface":"ai","behavior":"Blocked prompts and blocked candidates are excluded from `getHistory()`","status":"diverged-documented","evidence":["`unit:chat-session.test.ts` test `ai#chat-history-excludes-blocked` (upstream JSDoc contract; exercised with a scripted blocked envelope)","packages/pyric/test/ai/chat-session.test.ts"],"assurance":"qualified"},{"id":"ai#chat-history-threads","kind":"registry-row","surface":"ai","behavior":"`sendMessage` appends the user turn and the model turn; `getHistory()` returns the ordered `Content[]` with alternating roles","status":"diverged-documented","evidence":["`unit:chat-session.test.ts` test `ai#chat-history-threads` (no capture; history threading claim)","packages/pyric/test/ai/chat-session.test.ts"],"assurance":"qualified"}]},{"feature":"getIdToken","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"getIdToken is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"auth:runtime:getIdToken","kind":"runtime-export","surface":"auth","behavior":"getIdToken is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"getIdTokenResult","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"getIdTokenResult is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"auth:runtime:getIdTokenResult","kind":"runtime-export","surface":"auth","behavior":"getIdTokenResult is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"getImagenModel","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"out-of-scope","fidelity":"not-applicable","assurance":"not-applicable","summary":"getImagenModel is out-of-scope; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Imagen is deprecated upstream; all Imagen models shut down as early as June 2026 (upstream 2.11.0 deprecation). Mirroring an API whose production counterpart is retiring would freeze dead behavior."],"claims":[{"id":"ai:runtime:getImagenModel","kind":"runtime-export","surface":"ai","behavior":"Imagen is deprecated upstream; all Imagen models shut down as early as June 2026 (upstream 2.11.0 deprecation). Mirroring an API whose production counterpart is retiring would freeze dead behavior.","status":"out-of-scope","evidence":["upstream:firebase/ai@2.11.0"],"assurance":"not-applicable"}]},{"feature":"getLiveGenerativeModel","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"getLiveGenerativeModel is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Live API is deferred, not out of scope — it is a bidirectional websocket protocol the sandbox can model with a scripted session engine, the same seam pattern the REST plane already uses; the work has not happened yet."],"claims":[{"id":"ai:runtime:getLiveGenerativeModel","kind":"runtime-export","surface":"ai","behavior":"Live API is deferred, not out of scope — it is a bidirectional websocket protocol the sandbox can model with a scripted session engine, the same seam pattern the REST plane already uses; the work has not happened yet.","status":"deferred","evidence":["upstream:firebase/ai"],"assurance":"not-applicable"}]},{"feature":"getMessaging","surface":"messaging","importPaths":["pyric/messaging","pyric/messaging/sw"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"getMessaging is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-sw:runtime:getMessaging","kind":"runtime-export","surface":"messaging-sw","behavior":"getMessaging is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"messaging:runtime:getMessaging","kind":"runtime-export","surface":"messaging","behavior":"getMessaging is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"messaging#13","kind":"registry-row","surface":"messaging","behavior":"Returns the FCM instance within a service-worker context (bound to `getMessagingInSw`); registers under the component name `messaging-sw`.","status":"conforms","evidence":["Upstream typings (`@firebase/messaging` 0.12.26 `sw/index-public`) plus real module-ServiceWorker served-entry replay `messaging-app-boundary.pw.ts`.","packages/pyric/test/messaging/oracle-conformance.test.ts","packages/cli/test/e2e/messaging-app-boundary.pw.ts"],"assurance":"eligible"},{"id":"messaging#17","kind":"registry-row","surface":"messaging","behavior":"The sw entry exports `onBackgroundMessage`, `getMessaging`, `experimentalSetDeliveryMetricsExportedToBigQueryEnabled`, and `isSupported`, but NOT `getToken` / `deleteToken` / `onMessage`; the client entry exports the latter but NOT `onBackgroundMessage` / the metrics toggle. The two modules register under different component names (`messaging` vs `messaging-sw`) and re-export identical `Messaging` / `GetTokenOptions` / `MessagePayload` / `NotificationPayload` / `FcmOptions` type declarations.","status":"conforms","evidence":["Upstream typings (`@firebase/messaging` 0.12.26 `index.d.ts` / `index.sw.d.ts`) plus Window and real module-ServiceWorker boundary replay `messaging-app-boundary.pw.ts`.","packages/pyric/test/messaging/oracle-conformance.test.ts","packages/cli/test/e2e/messaging-app-boundary.pw.ts"],"assurance":"eligible"}]},{"feature":"getMessaging","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"getMessaging is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#2","kind":"registry-row","surface":"messaging-admin","behavior":"Namespaced / legacy accessor equivalent of `getMessaging`, exposed by the compat entry alongside the `namespace messaging` type aliases.","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `messaging-namespace`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"getMetadata","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"getMetadata is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["`FullMetadata.md5Hash` populated on uploads","divergence: sandbox does NOT compute `md5Hash`. Oracle-locked: `packages/conformance/observations/storage/storage-upload-then-getmetadata.json` confirms prod sets `md5Hash` (`hasMd5Hash: true` after a vanilla `uploadBytes`). Both sides pinned in `oracle-conformance.test.ts`. Aligning the sandbox is a one-spot fix in `upload.ts`'s `buildStoredMetadata`.","`FullMetadata.ref` lazy population (prod populates lazily)","not modeled in `pyric/storage` — `metadata.ts` explicitly omits `ref` from `FullMetadata`"],"claims":[{"id":"storage:runtime:getMetadata","kind":"runtime-export","surface":"storage","behavior":"getMetadata is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"storage#79","kind":"registry-row","surface":"storage","behavior":"`getMetadata(ref)` returns the same `FullMetadata` shape `uploadBytes` produced","status":"conforms","evidence":["`unit:metadata.test.ts` (\"returns the FullMetadata uploadBytes wrote\")","packages/pyric/test/storage/metadata.test.ts"],"assurance":"eligible"},{"id":"storage#80","kind":"registry-row","surface":"storage","behavior":"`getMetadata(ref)` throws `storage/object-not-found` for missing paths","status":"conforms","evidence":["`unit:metadata.test.ts` (\"throws object-not-found for missing paths\")","packages/pyric/test/storage/metadata.test.ts"],"assurance":"eligible"},{"id":"storage#81","kind":"registry-row","surface":"storage","behavior":"`getMetadata(ref)` throws `storage/invalid-root-operation` on the root","status":"conforms","evidence":["`unit:metadata.test.ts` (\"throws invalid-root-operation on the root reference\")","packages/pyric/test/storage/metadata.test.ts"],"assurance":"eligible"},{"id":"storage#89","kind":"registry-row","surface":"storage","behavior":"Prod: `getMetadata` after `uploadBytes` returns `contentType` and `size` matching what was uploaded","status":"conforms","evidence":["oracle: `packages/conformance/observations/storage/storage-upload-then-getmetadata.json` (against blockingfun, fb-js-sdk 12.13.0: upload 128-byte payload with `contentType: 'application/octet-stream'`, getMetadata returns `metadataSize: 128`, `metadataContentType: 'application/octet-stream'`, `metadataBucket: 'blockingfun.firebasestorage.app'`, `metadataMetageneration: '1'`, `fullPathMatches: true`)","observation:storage-upload-then-getmetadata"],"assurance":"eligible"},{"id":"storage#90","kind":"registry-row","surface":"storage","behavior":"Prod: `updateMetadata({customMetadata: {...}})` round-trips through a follow-up `getMetadata`","status":"conforms","evidence":["oracle: `packages/conformance/observations/storage/storage-update-metadata-roundtrip.json` (against blockingfun, fb-js-sdk 12.13.0: post-update `getMetadata` returns the exact `customMetadata` object, `metageneration` bumps `'1'` → `'2'`, `customSurvived: true`, `metagenerationBumped: true`)","observation:storage-update-metadata-roundtrip"],"assurance":"eligible"},{"id":"storage#91","kind":"registry-row","surface":"storage","behavior":"`FullMetadata.md5Hash` populated on uploads","status":"diverged-documented","evidence":["divergence: sandbox does NOT compute `md5Hash`. Oracle-locked: `packages/conformance/observations/storage/storage-upload-then-getmetadata.json` confirms prod sets `md5Hash` (`hasMd5Hash: true` after a vanilla `uploadBytes`). Both sides pinned in `oracle-conformance.test.ts`. Aligning the sandbox is a one-spot fix in `upload.ts`'s `buildStoredMetadata`.","observation:storage-upload-then-getmetadata","packages/pyric/test/storage/oracle-conformance.test.ts"],"assurance":"qualified"},{"id":"storage#92","kind":"registry-row","surface":"storage","behavior":"`FullMetadata.ref` lazy population (prod populates lazily)","status":"unsupported","evidence":["not modeled in `pyric/storage` — `metadata.ts` explicitly omits `ref` from `FullMetadata`"],"assurance":"ineligible"}]},{"feature":"getMultiFactorResolver","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"getMultiFactorResolver is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["MFA / phone / reCAPTCHA is deferred, not out of scope — reCAPTCHA/SMS are external infrastructure Pyric can mock with the OAuth resolver pattern, and TOTP is pure algorithm work."],"claims":[{"id":"auth:runtime:getMultiFactorResolver","kind":"runtime-export","surface":"auth","behavior":"MFA / phone / reCAPTCHA is deferred, not out of scope — reCAPTCHA/SMS are external infrastructure Pyric can mock with the OAuth resolver pattern, and TOTP is pure algorithm work.","status":"deferred","evidence":["registry:auth#180"],"assurance":"not-applicable"}]},{"feature":"getPersistentCacheIndexManager","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"getPersistentCacheIndexManager is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Index-tuning / GC-policy APIs have no real knob to turn in an in-memory sandbox today, but sibling cache-factory tokens are already honest inert tokens; these are buildable the same way and not genuinely out of scope."],"claims":[{"id":"firestore:runtime:getPersistentCacheIndexManager","kind":"runtime-export","surface":"firestore","behavior":"Index-tuning / GC-policy APIs have no real knob to turn in an in-memory sandbox today, but sibling cache-factory tokens are already honest inert tokens; these are buildable the same way and not genuinely out of scope.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"}]},{"feature":"getPriority","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"getPriority is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"rtdb-rules#13","kind":"registry-row","surface":"rtdb-rules","behavior":"`getPriority()` on a plain `set` (an unset priority reads null) and the `.indexOn` query-planner directive","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves a plain `set` leaves a node's priority unset, so `getPriority()` reports null in production exactly as the simulator does, and that a ruleset carrying `.indexOn` deploys and evaluates with every verdict intact. The scope is exactly that: `.indexOn` never changes an allow/deny verdict, so the twin evidences only that production's compiler accepts and deploys the directive, and it says nothing about query behavior. A NON-null priority stays unverified because writing one requires `setWithPriority`, outside the corpus op vocabulary of read and set. `oracle:rules-rtdb-r13-priority-and-index-directive` matches production verdict-for-verdict on all 4 cases.","observation:rules-rtdb-r13-priority-and-index-directive","packages/pyric/test/rules/rtdb/rules-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"getRedirectResult","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"getRedirectResult is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:getRedirectResult","kind":"runtime-export","surface":"auth","behavior":"getRedirectResult is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#49a","kind":"registry-row","surface":"auth","behavior":"`signInWithRedirect(auth, provider, resolver?)` resolves the flow (per-call resolver → injected → one-shot mock → `auth/argument-error`), signs the user in, and stashes the credential for one `getRedirectResult`","status":"conforms","evidence":["`unit:sandbox-resolver.test.ts`","packages/pyric/test/auth/sandbox-resolver.test.ts"],"assurance":"eligible"},{"id":"auth#49b","kind":"registry-row","surface":"auth","behavior":"`getRedirectResult(auth)` returns the stashed credential once, then `null` (one-shot, matches prod)","status":"conforms","evidence":["`unit:sandbox-resolver.test.ts`","packages/pyric/test/auth/sandbox-resolver.test.ts"],"assurance":"eligible"},{"id":"auth#49c","kind":"registry-row","surface":"auth","behavior":"`sandbox.setAuthFlowResolver(auth, resolver | null)` installs / clears the popup/redirect resolver (the analog of browser `getAuth` wiring `browserPopupRedirectResolver`)","status":"conforms","evidence":["`unit:sandbox-resolver.test.ts`","packages/pyric/test/auth/sandbox-resolver.test.ts"],"assurance":"eligible"},{"id":"auth#49d","kind":"registry-row","surface":"auth","behavior":"`sandbox.listIdentities(auth)` snapshots every seeded/created identity for a host account-picker (sandbox-only — no `firebase/auth` equivalent)","status":"conforms","evidence":["`unit:sandbox-resolver.test.ts`","packages/pyric/test/auth/sandbox-resolver.test.ts"],"assurance":"eligible"}]},{"feature":"getStorage","surface":"app","importPaths":[],"evidenceSlug":"app-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"getStorage is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"app#18","kind":"registry-row","surface":"app","behavior":"Equal-config named apps own distinct app-associated service handles while resolving the same configured RTDB and Storage backend locators","status":"conforms","evidence":["oracle: `app-registry-multi-app-service-containers` (firebase 12.13.0) + replay: `oracle-conformance.test.ts`","observation:app-registry-multi-app-service-containers","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"app#22","kind":"registry-row","surface":"app","behavior":"With a registered default app, each no-argument service factory resolves a service associated with that exact default app","status":"conforms","evidence":["oracle: `app-registry-default-service-factories` (firebase 12.13.0) + replay: `oracle-conformance.test.ts`","observation:app-registry-default-service-factories","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"app#25","kind":"registry-row","surface":"app","behavior":"After deletion, fresh Auth/Firestore/RTDB/Storage factories reject; cached factories return retained handles; retained Auth sign-out resolves but a new anonymous sign-in rejects `app/app-deleted`; Firestore reads report termination, RTDB refuses new refs, Storage refs remain constructible, and `getAI(deletedApp)` returns an app-associated handle","status":"conforms","evidence":["oracles: `app-registry-deleted-service-factories` and real-Chromium `app-production-multi-app-topology` (firebase 12.13.0) + replays: `oracle-conformance.test.ts`, `deleted-service-lifecycle.test.ts`, and `production-multi-app-oracle.test.ts`","observation:app-registry-deleted-service-factories","observation:app-production-multi-app-topology","packages/pyric/test/app/oracle-conformance.test.ts","packages/pyric/test/app/deleted-service-lifecycle.test.ts","packages/pyric/test/app/production-multi-app-oracle.test.ts"],"assurance":"eligible"}]},{"feature":"getStorage","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"getStorage is available, has diverged fidelity, and is qualified for assurance.","caveats":["`getStorage(app, bucketUrl?)` accepts Firebase's bucket argument; the sandbox remains bound to its configured single bucket","Package resolution owns production selection. The sandbox accepts the canonical argument but does not model production multi-bucket routing; `unit:service.test.ts` pins the configured `pyric-default` bucket."],"claims":[{"id":"storage:runtime:getStorage","kind":"runtime-export","surface":"storage","behavior":"getStorage is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"storage#10","kind":"registry-row","surface":"storage","behavior":"Unrecognized handle (not produced by a factory) → `TypeError` \"not a FirebaseStorage handle\"","status":"conforms","evidence":["`unit:service.test.ts` (\"rejects an object that was not produced by a factory\")","packages/pyric/test/storage/service.test.ts"],"assurance":"eligible"},{"id":"storage#11","kind":"registry-row","surface":"storage","behavior":"`getStorage(app, bucketUrl?)` accepts Firebase's bucket argument; the sandbox remains bound to its configured single bucket","status":"diverged-documented","evidence":["Package resolution owns production selection. The sandbox accepts the canonical argument but does not model production multi-bucket routing; `unit:service.test.ts` pins the configured `pyric-default` bucket.","packages/pyric/test/storage/service.test.ts"],"assurance":"qualified"},{"id":"storage#12","kind":"registry-row","surface":"storage","behavior":"The served `firebase/storage` entry accepts bare `getStorage()` and returns the page's shared sandbox handle","status":"conforms","evidence":["The canonical served entry supplies the page sandbox when the app argument is omitted; the entry-path and bundler suites execute the public package shape.","packages/conformance/entry-path/storage.ts","packages/cli/test/serve/bundler.test.ts"],"assurance":"eligible"},{"id":"storage#3","kind":"registry-row","surface":"storage","behavior":"`getStorage(app)` returns the sandbox handle selected by package resolution","status":"conforms","evidence":["`entry-path:storage` runs the canonical `initializeApp` → `getStorage(app)` → `ref` → `uploadBytes` flow","packages/conformance/entry-path/storage.ts"],"assurance":"eligible"},{"id":"storage#5","kind":"registry-row","surface":"storage","behavior":"Two different `SandboxContext`s on the same `Sandbox` get DIFFERENT handles but share the underlying `StorageService` (IDB)","status":"conforms","evidence":["`unit:service.test.ts` (\"shares the underlying StorageService across contexts on the same sandbox\")","packages/pyric/test/storage/service.test.ts"],"assurance":"eligible"},{"id":"storage#6","kind":"registry-row","surface":"storage","behavior":"`options.bucket` round-trips on metadata records; v1 has a single implicit bucket but the field is preserved","status":"conforms","evidence":["`unit:service.test.ts` (\"records the bucket value on the handle\")","packages/pyric/test/storage/service.test.ts"],"assurance":"eligible"},{"id":"storage#7","kind":"registry-row","surface":"storage","behavior":"`options.dbName` honored on the FIRST call per `Sandbox`; second-call overrides ignored","status":"conforms","evidence":["`unit:service.test.ts` (\"dbName only takes effect on the sandbox's first getStorage call\")","packages/pyric/test/storage/service.test.ts"],"assurance":"eligible"},{"id":"storage#8","kind":"registry-row","surface":"storage","behavior":"`options.rules` parsed eagerly — malformed rules throw `SyntaxError` at config time","status":"conforms","evidence":["`unit:rules.test.ts` (parse errors propagate from `parseStorageRules`)","packages/pyric/test/storage/rules.test.ts"],"assurance":"eligible"},{"id":"storage#9","kind":"registry-row","surface":"storage","behavior":"The `TARGET_SYMBOL` brand keeps each handle bound to its owning sandbox service and identity","status":"conforms","evidence":["`unit:service.test.ts` (distinct contexts share one service while retaining distinct handles)","packages/pyric/test/storage/service.test.ts"],"assurance":"eligible"}]},{"feature":"getStorageSandbox","surface":"storage","importPaths":[],"evidenceSlug":"storage-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"getStorageSandbox is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage#1","kind":"registry-row","surface":"storage","behavior":"`getStorageSandbox(ctx)` returns a tagged sandbox-target handle (frozen identity)","status":"conforms","evidence":["`unit:service.test.ts`","packages/pyric/test/storage/service.test.ts"],"assurance":"eligible"},{"id":"storage#10","kind":"registry-row","surface":"storage","behavior":"Unrecognized handle (not produced by a factory) → `TypeError` \"not a FirebaseStorage handle\"","status":"conforms","evidence":["`unit:service.test.ts` (\"rejects an object that was not produced by a factory\")","packages/pyric/test/storage/service.test.ts"],"assurance":"eligible"},{"id":"storage#2","kind":"registry-row","surface":"storage","behavior":"`getStorageSandbox(sandbox)` wraps a bare Sandbox with an anonymous context (`auth: null`)","status":"conforms","evidence":["`unit:service.test.ts`","packages/pyric/test/storage/service.test.ts"],"assurance":"eligible"},{"id":"storage#4","kind":"registry-row","surface":"storage","behavior":"Two `getStorageSandbox(ctx)` calls on the same context return the SAME wrapper (identity-stable)","status":"conforms","evidence":["`unit:service.test.ts` (\"returns the same handle for repeated calls on the same context\")","packages/pyric/test/storage/service.test.ts"],"assurance":"eligible"},{"id":"storage#4a","kind":"registry-row","surface":"storage","behavior":"Two `getStorageSandbox(sandbox)` calls on a bare `Sandbox` return the SAME wrapper (identity-stable)","status":"conforms","evidence":["ST-B3 fixed: `withAuth(null)` mints a fresh context per call, so the per-context cache missed and bare-Sandbox calls returned different handles. A `Sandbox`-keyed cache makes the convenience path stable, matching the docstring. Probe: `unit:service.test.ts` (\"ST-B3: returns the same handle for repeated bare-Sandbox calls\").","packages/pyric/test/storage/service.test.ts"],"assurance":"eligible"},{"id":"storage#5","kind":"registry-row","surface":"storage","behavior":"Two different `SandboxContext`s on the same `Sandbox` get DIFFERENT handles but share the underlying `StorageService` (IDB)","status":"conforms","evidence":["`unit:service.test.ts` (\"shares the underlying StorageService across contexts on the same sandbox\")","packages/pyric/test/storage/service.test.ts"],"assurance":"eligible"},{"id":"storage#6","kind":"registry-row","surface":"storage","behavior":"`options.bucket` round-trips on metadata records; v1 has a single implicit bucket but the field is preserved","status":"conforms","evidence":["`unit:service.test.ts` (\"records the bucket value on the handle\")","packages/pyric/test/storage/service.test.ts"],"assurance":"eligible"},{"id":"storage#7","kind":"registry-row","surface":"storage","behavior":"`options.dbName` honored on the FIRST call per `Sandbox`; second-call overrides ignored","status":"conforms","evidence":["`unit:service.test.ts` (\"dbName only takes effect on the sandbox's first getStorage call\")","packages/pyric/test/storage/service.test.ts"],"assurance":"eligible"},{"id":"storage#8","kind":"registry-row","surface":"storage","behavior":"`options.rules` parsed eagerly — malformed rules throw `SyntaxError` at config time","status":"conforms","evidence":["`unit:rules.test.ts` (parse errors propagate from `parseStorageRules`)","packages/pyric/test/storage/rules.test.ts"],"assurance":"eligible"},{"id":"storage#9","kind":"registry-row","surface":"storage","behavior":"The `TARGET_SYMBOL` brand keeps each handle bound to its owning sandbox service and identity","status":"conforms","evidence":["`unit:service.test.ts` (distinct contexts share one service while retaining distinct handles)","packages/pyric/test/storage/service.test.ts"],"assurance":"eligible"}]},{"feature":"getStream","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"getStream is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["The Node-stream variant is deferred — not part of the browser-shaped v1 scope yet, but not genuinely un-modelable.","Exported by `firebase/storage` (Node entry only); returns a Node `Readable`","No `pyric/storage` implementation or behavioral probe exists; availability is classified by the owning surface contract."],"claims":[{"id":"storage:runtime:getStream","kind":"runtime-export","surface":"storage","behavior":"The Node-stream variant is deferred — not part of the browser-shaped v1 scope yet, but not genuinely un-modelable.","status":"deferred","evidence":["registry:storage#62"],"assurance":"not-applicable"},{"id":"storage#62","kind":"registry-row","surface":"storage","behavior":"Exported by `firebase/storage` (Node entry only); returns a Node `Readable`","status":"unsupported","evidence":["No `pyric/storage` implementation or behavioral probe exists; availability is classified by the owning surface contract."],"assurance":"ineligible"}]},{"feature":"getTemplateGenerativeModel","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"getTemplateGenerativeModel is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Server-side templates are deferred, not out of scope — hosting template state is exactly the kind of server infrastructure the sandbox exists to model; the template store has not been built yet."],"claims":[{"id":"ai:runtime:getTemplateGenerativeModel","kind":"runtime-export","surface":"ai","behavior":"Server-side templates are deferred, not out of scope — hosting template state is exactly the kind of server infrastructure the sandbox exists to model; the template store has not been built yet.","status":"deferred","evidence":["upstream:firebase/ai"],"assurance":"not-applicable"}]},{"feature":"getTemplateImagenModel","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"out-of-scope","fidelity":"not-applicable","assurance":"not-applicable","summary":"getTemplateImagenModel is out-of-scope; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Template-served Imagen models retire with the rest of Imagen (deprecated upstream, June 2026 shutdown); the template transport does not outlive the model family it serves."],"claims":[{"id":"ai:runtime:getTemplateImagenModel","kind":"runtime-export","surface":"ai","behavior":"Template-served Imagen models retire with the rest of Imagen (deprecated upstream, June 2026 shutdown); the template transport does not outlive the model family it serves.","status":"out-of-scope","evidence":["upstream:firebase/ai@2.11.0"],"assurance":"not-applicable"}]},{"feature":"getToken","surface":"messaging","importPaths":["pyric/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"getToken is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging:runtime:getToken","kind":"runtime-export","surface":"messaging","behavior":"getToken is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"messaging#2","kind":"registry-row","surface":"messaging","behavior":"Subscribes the instance to push and resolves with an FCM registration token; requests notification permission if not already granted and rejects if denied. Production tokens are colon-separated, URL-safe, ~142 chars, with the suffix after the colon beginning `APA91b`, and are stable across repeated `getToken` calls on the same service-worker registration (no per-call rotation).","status":"conforms","evidence":["oracle: `messaging-web-token-shape.json` (minted, length 142, colon-separated, suffix starts `APA91b`, URL-safe) + `messaging-web-token-stability.json` (second `getToken` on the same registration returns the same token). Replayed by the conformance suite.","observation:messaging-web-token-shape","observation:messaging-web-token-stability","packages/pyric/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"messaging#7","kind":"registry-row","surface":"messaging","behavior":"Options for `getToken`: an optional `vapidKey` (Web Push certificate public key) and an optional `serviceWorkerRegistration`.","status":"conforms","evidence":["Upstream typings (`@firebase/messaging` 0.12.26 `public-types`); no observation yet.","packages/pyric/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"GetTokenOptions","surface":"messaging","importPaths":["pyric/messaging","pyric/messaging/sw"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"GetTokenOptions is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"messaging-sw:type:GetTokenOptions","kind":"type-export","surface":"messaging-sw","behavior":"GetTokenOptions is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"messaging:type:GetTokenOptions","kind":"type-export","surface":"messaging","behavior":"GetTokenOptions is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"GithubAuthProvider","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"GithubAuthProvider is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"auth:runtime:GithubAuthProvider","kind":"runtime-export","surface":"auth","behavior":"GithubAuthProvider is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth:type:GithubAuthProvider","kind":"type-export","surface":"auth","behavior":"GithubAuthProvider is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"goOffline","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"goOffline is available, has diverged fidelity, and is qualified for assurance.","caveats":["`goOffline(db)` — accepted no-op: there is no network connection in the local sandbox to toggle, so nothing is disconnected (we deliberately do NOT simulate a disconnect — pending writes, listeners, and `get()` keep working)","`unit:modular/fruit-aliases.test.ts`"],"claims":[{"id":"database:runtime:goOffline","kind":"runtime-export","surface":"database","behavior":"goOffline is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#163","kind":"registry-row","surface":"rtdb-modular","behavior":"`goOffline(db)` — accepted no-op: there is no network connection in the local sandbox to toggle, so nothing is disconnected (we deliberately do NOT simulate a disconnect — pending writes, listeners, and `get()` keep working)","status":"diverged-documented","evidence":["`unit:modular/fruit-aliases.test.ts`","packages/pyric/test/database/modular/fruit-aliases.test.ts"],"assurance":"qualified"}]},{"feature":"GoogleAIBackend","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"GoogleAIBackend is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:GoogleAIBackend","kind":"runtime-export","surface":"ai","behavior":"GoogleAIBackend is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:GoogleAIBackend","kind":"type-export","surface":"ai","behavior":"GoogleAIBackend is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"GoogleAuthProvider","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"GoogleAuthProvider is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["Custom scopes / params / language code","sandbox ignores; prod forwards"],"claims":[{"id":"auth:runtime:GoogleAuthProvider","kind":"runtime-export","surface":"auth","behavior":"GoogleAuthProvider is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth:type:GoogleAuthProvider","kind":"type-export","surface":"auth","behavior":"GoogleAuthProvider is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#50","kind":"registry-row","surface":"auth","behavior":"Exports the same constructor signatures as `firebase/auth` for each provider","status":"conforms","evidence":["type-only smoke in `unit:types.test.ts`","packages/pyric/test/auth/types.test.ts"],"assurance":"eligible"},{"id":"auth#51","kind":"registry-row","surface":"auth","behavior":"`Provider.credential(...)` static factories produce `AuthCredential`-shaped objects","status":"conforms","evidence":["`unit:sandbox-providers.test.ts`","packages/pyric/test/auth/sandbox-providers.test.ts"],"assurance":"eligible"},{"id":"auth#52","kind":"registry-row","surface":"auth","behavior":"`GoogleAuthProvider.providerId === 'google.com'` (and per-provider analogs)","status":"conforms","evidence":["`unit:sandbox-providers.test.ts`","packages/pyric/test/auth/sandbox-providers.test.ts"],"assurance":"eligible"},{"id":"auth#53","kind":"registry-row","surface":"auth","behavior":"Custom scopes / params / language code","status":"unsupported","evidence":["sandbox ignores; prod forwards"],"assurance":"ineligible"}]},{"feature":"GoogleMaps","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"GoogleMaps is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:GoogleMaps","kind":"type-export","surface":"ai","behavior":"GoogleMaps is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"GoogleMapsGroundingChunk","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"GoogleMapsGroundingChunk is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:GoogleMapsGroundingChunk","kind":"type-export","surface":"ai","behavior":"GoogleMapsGroundingChunk is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"GoogleMapsTool","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"GoogleMapsTool is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:GoogleMapsTool","kind":"type-export","surface":"ai","behavior":"GoogleMapsTool is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"GoogleSearch","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"GoogleSearch is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:GoogleSearch","kind":"type-export","surface":"ai","behavior":"GoogleSearch is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"GoogleSearchTool","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"GoogleSearchTool is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:GoogleSearchTool","kind":"type-export","surface":"ai","behavior":"GoogleSearchTool is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"goOnline","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"goOnline is available, has diverged fidelity, and is qualified for assurance.","caveats":["`goOnline(db)` — accepted no-op: there is no connection to reopen (see `goOffline`)","`unit:modular/fruit-aliases.test.ts`"],"claims":[{"id":"database:runtime:goOnline","kind":"runtime-export","surface":"database","behavior":"goOnline is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#164","kind":"registry-row","surface":"rtdb-modular","behavior":"`goOnline(db)` — accepted no-op: there is no connection to reopen (see `goOffline`)","status":"diverged-documented","evidence":["`unit:modular/fruit-aliases.test.ts`","packages/pyric/test/database/modular/fruit-aliases.test.ts"],"assurance":"qualified"}]},{"feature":"GroundingChunk","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"GroundingChunk is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:GroundingChunk","kind":"type-export","surface":"ai","behavior":"GroundingChunk is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"GroundingMetadata","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"GroundingMetadata is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:GroundingMetadata","kind":"type-export","surface":"ai","behavior":"GroundingMetadata is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"GroundingSupport","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"GroundingSupport is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:GroundingSupport","kind":"type-export","surface":"ai","behavior":"GroundingSupport is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"HarmBlockMethod","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"HarmBlockMethod is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:HarmBlockMethod","kind":"runtime-export","surface":"ai","behavior":"HarmBlockMethod is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:HarmBlockMethod","kind":"type-export","surface":"ai","behavior":"HarmBlockMethod is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"HarmBlockThreshold","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"HarmBlockThreshold is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:HarmBlockThreshold","kind":"runtime-export","surface":"ai","behavior":"HarmBlockThreshold is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:HarmBlockThreshold","kind":"type-export","surface":"ai","behavior":"HarmBlockThreshold is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"HarmCategory","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"HarmCategory is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:HarmCategory","kind":"runtime-export","surface":"ai","behavior":"HarmCategory is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:HarmCategory","kind":"type-export","surface":"ai","behavior":"HarmCategory is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"HarmProbability","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"HarmProbability is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:HarmProbability","kind":"runtime-export","surface":"ai","behavior":"HarmProbability is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:HarmProbability","kind":"type-export","surface":"ai","behavior":"HarmProbability is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"HarmSeverity","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"HarmSeverity is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:HarmSeverity","kind":"runtime-export","surface":"ai","behavior":"HarmSeverity is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:HarmSeverity","kind":"type-export","surface":"ai","behavior":"HarmSeverity is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"hashing.crc32","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"hashing.crc32 is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["`Bytes`, `String.toUtf8()`, and `hashing.{md5,sha256,crc32,crc32c}()` (Item 5.3) in rules","`oracle:rules-firestore-bytes-toutf8-and-hashing` — production Firestore Rules Test API verdicts for corpus scenario \"bytes-toutf8-and-hashing\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator's toUtf8/md5/sha256/crc32/crc32c byte-encoding and reference-hash implementations diverge from production on all 5 scenario cases, so a rule that should DENY on hash mismatch ALLOWs locally — pinned KNOWN_DIVERGENCE"],"claims":[{"id":"firestore-rules#161","kind":"registry-row","surface":"firestore-rules","behavior":"`Bytes`, `String.toUtf8()`, and `hashing.{md5,sha256,crc32,crc32c}()` (Item 5.3) in rules","status":"diverged-documented","evidence":["`oracle:rules-firestore-bytes-toutf8-and-hashing` — production Firestore Rules Test API verdicts for corpus scenario \"bytes-toutf8-and-hashing\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator's toUtf8/md5/sha256/crc32/crc32c byte-encoding and reference-hash implementations diverge from production on all 5 scenario cases, so a rule that should DENY on hash mismatch ALLOWs locally — pinned KNOWN_DIVERGENCE","observation:rules-firestore-bytes-toutf8-and-hashing","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"ineligible"},{"id":"firestore.function.hashing.crc32","kind":"rules-construct","surface":"firestore-rules","behavior":"hashing.crc32 is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.hashing#function_crc32_"],"assurance":"ineligible"}]},{"feature":"hashing.crc32c","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"hashing.crc32c is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["`Bytes`, `String.toUtf8()`, and `hashing.{md5,sha256,crc32,crc32c}()` (Item 5.3) in rules","`oracle:rules-firestore-bytes-toutf8-and-hashing` — production Firestore Rules Test API verdicts for corpus scenario \"bytes-toutf8-and-hashing\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator's toUtf8/md5/sha256/crc32/crc32c byte-encoding and reference-hash implementations diverge from production on all 5 scenario cases, so a rule that should DENY on hash mismatch ALLOWs locally — pinned KNOWN_DIVERGENCE"],"claims":[{"id":"firestore-rules#161","kind":"registry-row","surface":"firestore-rules","behavior":"`Bytes`, `String.toUtf8()`, and `hashing.{md5,sha256,crc32,crc32c}()` (Item 5.3) in rules","status":"diverged-documented","evidence":["`oracle:rules-firestore-bytes-toutf8-and-hashing` — production Firestore Rules Test API verdicts for corpus scenario \"bytes-toutf8-and-hashing\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator's toUtf8/md5/sha256/crc32/crc32c byte-encoding and reference-hash implementations diverge from production on all 5 scenario cases, so a rule that should DENY on hash mismatch ALLOWs locally — pinned KNOWN_DIVERGENCE","observation:rules-firestore-bytes-toutf8-and-hashing","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"ineligible"},{"id":"firestore.function.hashing.crc32c","kind":"rules-construct","surface":"firestore-rules","behavior":"hashing.crc32c is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.hashing#function_crc32c_"],"assurance":"ineligible"}]},{"feature":"hashing.md5","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"hashing.md5 is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["`Bytes`, `String.toUtf8()`, and `hashing.{md5,sha256,crc32,crc32c}()` (Item 5.3) in rules","`oracle:rules-firestore-bytes-toutf8-and-hashing` — production Firestore Rules Test API verdicts for corpus scenario \"bytes-toutf8-and-hashing\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator's toUtf8/md5/sha256/crc32/crc32c byte-encoding and reference-hash implementations diverge from production on all 5 scenario cases, so a rule that should DENY on hash mismatch ALLOWs locally — pinned KNOWN_DIVERGENCE"],"claims":[{"id":"firestore-rules#161","kind":"registry-row","surface":"firestore-rules","behavior":"`Bytes`, `String.toUtf8()`, and `hashing.{md5,sha256,crc32,crc32c}()` (Item 5.3) in rules","status":"diverged-documented","evidence":["`oracle:rules-firestore-bytes-toutf8-and-hashing` — production Firestore Rules Test API verdicts for corpus scenario \"bytes-toutf8-and-hashing\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator's toUtf8/md5/sha256/crc32/crc32c byte-encoding and reference-hash implementations diverge from production on all 5 scenario cases, so a rule that should DENY on hash mismatch ALLOWs locally — pinned KNOWN_DIVERGENCE","observation:rules-firestore-bytes-toutf8-and-hashing","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"ineligible"},{"id":"firestore.function.hashing.md5","kind":"rules-construct","surface":"firestore-rules","behavior":"hashing.md5 is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.hashing#function_md5_"],"assurance":"ineligible"}]},{"feature":"hashing.sha256","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"hashing.sha256 is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["`Bytes`, `String.toUtf8()`, and `hashing.{md5,sha256,crc32,crc32c}()` (Item 5.3) in rules","`oracle:rules-firestore-bytes-toutf8-and-hashing` — production Firestore Rules Test API verdicts for corpus scenario \"bytes-toutf8-and-hashing\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator's toUtf8/md5/sha256/crc32/crc32c byte-encoding and reference-hash implementations diverge from production on all 5 scenario cases, so a rule that should DENY on hash mismatch ALLOWs locally — pinned KNOWN_DIVERGENCE"],"claims":[{"id":"firestore-rules#161","kind":"registry-row","surface":"firestore-rules","behavior":"`Bytes`, `String.toUtf8()`, and `hashing.{md5,sha256,crc32,crc32c}()` (Item 5.3) in rules","status":"diverged-documented","evidence":["`oracle:rules-firestore-bytes-toutf8-and-hashing` — production Firestore Rules Test API verdicts for corpus scenario \"bytes-toutf8-and-hashing\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator's toUtf8/md5/sha256/crc32/crc32c byte-encoding and reference-hash implementations diverge from production on all 5 scenario cases, so a rule that should DENY on hash mismatch ALLOWs locally — pinned KNOWN_DIVERGENCE","observation:rules-firestore-bytes-toutf8-and-hashing","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"ineligible"},{"id":"firestore.function.hashing.sha256","kind":"rules-construct","surface":"firestore-rules","behavior":"hashing.sha256 is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.hashing#function_sha256_"],"assurance":"ineligible"}]},{"feature":"HybridParams","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"HybridParams is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:HybridParams","kind":"type-export","surface":"ai","behavior":"HybridParams is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"IdTokenResult","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"IdTokenResult is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"auth:type:IdTokenResult","kind":"type-export","surface":"auth","behavior":"IdTokenResult is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ImageConfig","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"ImageConfig is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:ImageConfig","kind":"type-export","surface":"ai","behavior":"ImageConfig is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ImageConfigAspectRatio","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"ImageConfigAspectRatio is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:ImageConfigAspectRatio","kind":"runtime-export","surface":"ai","behavior":"ImageConfigAspectRatio is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:ImageConfigAspectRatio","kind":"type-export","surface":"ai","behavior":"ImageConfigAspectRatio is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ImageConfigImageSize","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"ImageConfigImageSize is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:ImageConfigImageSize","kind":"runtime-export","surface":"ai","behavior":"ImageConfigImageSize is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:ImageConfigImageSize","kind":"type-export","surface":"ai","behavior":"ImageConfigImageSize is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ImagenAspectRatio","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"out-of-scope","fidelity":"not-applicable","assurance":"not-applicable","summary":"ImagenAspectRatio is out-of-scope; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Imagen is deprecated upstream; all Imagen models shut down as early as June 2026 (upstream 2.11.0 deprecation). Mirroring an API whose production counterpart is retiring would freeze dead behavior.","Public type export is not mirrored."],"claims":[{"id":"ai:runtime:ImagenAspectRatio","kind":"runtime-export","surface":"ai","behavior":"Imagen is deprecated upstream; all Imagen models shut down as early as June 2026 (upstream 2.11.0 deprecation). Mirroring an API whose production counterpart is retiring would freeze dead behavior.","status":"out-of-scope","evidence":["upstream:firebase/ai@2.11.0"],"assurance":"not-applicable"},{"id":"ai:type:ImagenAspectRatio","kind":"type-export","surface":"ai","behavior":"ImagenAspectRatio is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ImagenGCSImage","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"ImagenGCSImage is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:ImagenGCSImage","kind":"type-export","surface":"ai","behavior":"ImagenGCSImage is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ImagenGenerationConfig","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"ImagenGenerationConfig is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:ImagenGenerationConfig","kind":"type-export","surface":"ai","behavior":"ImagenGenerationConfig is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ImagenGenerationResponse","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"ImagenGenerationResponse is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:ImagenGenerationResponse","kind":"type-export","surface":"ai","behavior":"ImagenGenerationResponse is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ImagenImageFormat","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"out-of-scope","fidelity":"not-applicable","assurance":"not-applicable","summary":"ImagenImageFormat is out-of-scope; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Imagen is deprecated upstream; all Imagen models shut down as early as June 2026 (upstream 2.11.0 deprecation). Mirroring an API whose production counterpart is retiring would freeze dead behavior.","Public type export is not mirrored."],"claims":[{"id":"ai:runtime:ImagenImageFormat","kind":"runtime-export","surface":"ai","behavior":"Imagen is deprecated upstream; all Imagen models shut down as early as June 2026 (upstream 2.11.0 deprecation). Mirroring an API whose production counterpart is retiring would freeze dead behavior.","status":"out-of-scope","evidence":["upstream:firebase/ai@2.11.0"],"assurance":"not-applicable"},{"id":"ai:type:ImagenImageFormat","kind":"type-export","surface":"ai","behavior":"ImagenImageFormat is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ImagenInlineImage","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"ImagenInlineImage is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:ImagenInlineImage","kind":"type-export","surface":"ai","behavior":"ImagenInlineImage is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ImagenModel","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"out-of-scope","fidelity":"not-applicable","assurance":"not-applicable","summary":"ImagenModel is out-of-scope; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Imagen is deprecated upstream; all Imagen models shut down as early as June 2026 (upstream 2.11.0 deprecation). Mirroring an API whose production counterpart is retiring would freeze dead behavior.","Public type export is not mirrored."],"claims":[{"id":"ai:runtime:ImagenModel","kind":"runtime-export","surface":"ai","behavior":"Imagen is deprecated upstream; all Imagen models shut down as early as June 2026 (upstream 2.11.0 deprecation). Mirroring an API whose production counterpart is retiring would freeze dead behavior.","status":"out-of-scope","evidence":["upstream:firebase/ai@2.11.0"],"assurance":"not-applicable"},{"id":"ai:type:ImagenModel","kind":"type-export","surface":"ai","behavior":"ImagenModel is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ImagenModelParams","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"ImagenModelParams is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:ImagenModelParams","kind":"type-export","surface":"ai","behavior":"ImagenModelParams is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ImagenPersonFilterLevel","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"out-of-scope","fidelity":"not-applicable","assurance":"not-applicable","summary":"ImagenPersonFilterLevel is out-of-scope; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Imagen is deprecated upstream; all Imagen models shut down as early as June 2026 (upstream 2.11.0 deprecation). Mirroring an API whose production counterpart is retiring would freeze dead behavior.","Public type export is not mirrored."],"claims":[{"id":"ai:runtime:ImagenPersonFilterLevel","kind":"runtime-export","surface":"ai","behavior":"Imagen is deprecated upstream; all Imagen models shut down as early as June 2026 (upstream 2.11.0 deprecation). Mirroring an API whose production counterpart is retiring would freeze dead behavior.","status":"out-of-scope","evidence":["upstream:firebase/ai@2.11.0"],"assurance":"not-applicable"},{"id":"ai:type:ImagenPersonFilterLevel","kind":"type-export","surface":"ai","behavior":"ImagenPersonFilterLevel is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ImagenSafetyFilterLevel","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"out-of-scope","fidelity":"not-applicable","assurance":"not-applicable","summary":"ImagenSafetyFilterLevel is out-of-scope; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Imagen is deprecated upstream; all Imagen models shut down as early as June 2026 (upstream 2.11.0 deprecation). Mirroring an API whose production counterpart is retiring would freeze dead behavior.","Public type export is not mirrored."],"claims":[{"id":"ai:runtime:ImagenSafetyFilterLevel","kind":"runtime-export","surface":"ai","behavior":"Imagen is deprecated upstream; all Imagen models shut down as early as June 2026 (upstream 2.11.0 deprecation). Mirroring an API whose production counterpart is retiring would freeze dead behavior.","status":"out-of-scope","evidence":["upstream:firebase/ai@2.11.0"],"assurance":"not-applicable"},{"id":"ai:type:ImagenSafetyFilterLevel","kind":"type-export","surface":"ai","behavior":"ImagenSafetyFilterLevel is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ImagenSafetySettings","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"ImagenSafetySettings is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:ImagenSafetySettings","kind":"type-export","surface":"ai","behavior":"ImagenSafetySettings is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"increment","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"increment is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:increment","kind":"runtime-export","surface":"firestore","behavior":"increment is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#100","kind":"registry-row","surface":"firestore","behavior":"`increment(n)` atomically bumps a numeric field; `null`/missing field starts from 0","status":"conforms","evidence":["`unit:sandbox-target.test.ts`, `playground:firestore-sentinels` (bundled) + `playground:firestore-row-100-increment-bumps-numeric` (one-claim), oracle: `packages/conformance/observations/firestore/firestore-row-100-increment-bumps-numeric.json` — `setDoc` with no `count` field then `updateDoc({count: increment(5)})` yields `count === 5` (starts from 0). Follow-up `increment(3)` → 8, then `increment(-2)` → 6 (negative deltas apply, increments accumulate). Merge-create + int↔double + batch-across-docs: `unit:upstream-transform-txn-listener-probes.test.ts`","observation:firestore-row-100-increment-bumps-numeric","packages/pyric/test/firestore/sandbox-target.test.ts","packages/pyric/test/firestore/upstream-transform-txn-listener-probes.test.ts"],"assurance":"eligible"},{"id":"firestore#105a","kind":"registry-row","surface":"firestore","behavior":"**Sentinel overwrite on type mismatch (FS-B11)** — `increment(n)` on a non-numeric (or absent) prior OVERWRITES using a base value of 0 (result `n`); `arrayUnion`/`arrayRemove` on a non-array prior coerce the base to `[]`. Pre-FS-B11 these threw and surfaced as `invalid-argument` denials. Mirrors `clones/.../model/transform_operation.ts` (`computeTransformOperationBaseValue`, `coercedFieldValuesArray`).","status":"conforms","evidence":["`unit:simulator/converters/fieldvalue.test.ts` (FS-B11 overwrite block + flipped unit/integration/batch cases; verified failing pre-fix)","packages/pyric/test/sandbox/firestore/simulator/converters/fieldvalue.test.ts"],"assurance":"eligible"}]},{"feature":"increment","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"increment is available, has unverified fidelity, and is qualified for assurance.","caveats":["Two concurrent `increment` calls interleave correctly (last-write-wins is NOT the contract — both deltas accumulate)","hard to observe deterministically from a single client; documented contract"],"claims":[{"id":"database:runtime:increment","kind":"runtime-export","surface":"database","behavior":"increment is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#155","kind":"registry-row","surface":"rtdb-modular","behavior":"`increment(n)` against a **missing** field starts at 0 (so `increment(5)` lands as `5`)","status":"conforms","evidence":["Sandbox aligned (modular `increment` export now present): `unit:modular/increment.test.ts` (\"increment against a missing field starts from 0\"); matches oracle `packages/conformance/observations/rtdb-modular/rtdb-modular-increment-from-missing.json` — observed `afterFirst: 5` from `increment(5)` against an absent `count` field.","observation:rtdb-modular-increment-from-missing","packages/pyric/test/database/modular/increment.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#156","kind":"registry-row","surface":"rtdb-modular","behavior":"`increment(n)` against an existing numeric field adds atomically; negative deltas subtract","status":"conforms","evidence":["Sandbox aligned: `unit:modular/increment.test.ts` (\"subsequent increments accumulate (positive then negative)\" + \"nested inside an update patch resolves per-field\"); matches oracle `packages/conformance/observations/rtdb-modular/rtdb-modular-increment-from-missing.json` — observed `afterSecond: 8` (5+3) then `afterNegative: 6` (8-2).","observation:rtdb-modular-increment-from-missing","packages/pyric/test/database/modular/increment.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#157","kind":"registry-row","surface":"rtdb-modular","behavior":"Two concurrent `increment` calls interleave correctly (last-write-wins is NOT the contract — both deltas accumulate)","status":"unverified","evidence":["hard to observe deterministically from a single client; documented contract"],"assurance":"qualified"}]},{"feature":"Index","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"Index is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:Index","kind":"type-export","surface":"firestore","behavior":"Index is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"IndexConfiguration","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"IndexConfiguration is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:IndexConfiguration","kind":"type-export","surface":"firestore","behavior":"IndexConfiguration is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"indexedDBLocalPersistence","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"indexedDBLocalPersistence is available, has diverged fidelity, and is qualified for assurance.","caveats":["Inert configuration tokens, accepted so the idiomatic `initializeAuth(app, { persistence: indexedDBLocalPersistence })` and `setPersistence(auth, browserCookiePersistence)` compile, run, and behave identically. The `.type` discriminant matches upstream exactly (`NONE` / `SESSION` / `LOCAL` / `LOCAL` / `COOKIE`) because consumer code branches on it. `browserPopupRedirectResolver` is accepted and ignored — the sandbox has its own first-class pluggable equivalent (`sandbox.setAuthFlowResolver`). `prodErrorMap` is accepted and DELIBERATELY not honored: installing it upstream strips error messages, and doing that in a sandbox whose purpose is to tell a developer what went wrong would be actively hostile.","In an in-memory sandbox the persistence CHOICE has no observable consequence, so accepting the token and recording the mode is the honest behavior — the same inert-token pattern `pyric/firestore` uses for its cache-factory tokens. `unit:types.test.ts` + `unit:sandbox-email-link.test.ts` cover the exports. Oracle caveat recorded on auth#172: the `persistenceTypes` block of `auth-mechanical-surface-constants` reports `NONE` for every token including `browserLocalPersistence` — a Node-build stub artifact, not the browser contract, so the `.type` values here follow the documented `Persistence.type` union instead."],"claims":[{"id":"auth:runtime:indexedDBLocalPersistence","kind":"runtime-export","surface":"auth","behavior":"indexedDBLocalPersistence is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#178","kind":"registry-row","surface":"auth","behavior":"Inert configuration tokens, accepted so the idiomatic `initializeAuth(app, { persistence: indexedDBLocalPersistence })` and `setPersistence(auth, browserCookiePersistence)` compile, run, and behave identically. The `.type` discriminant matches upstream exactly (`NONE` / `SESSION` / `LOCAL` / `LOCAL` / `COOKIE`) because consumer code branches on it. `browserPopupRedirectResolver` is accepted and ignored — the sandbox has its own first-class pluggable equivalent (`sandbox.setAuthFlowResolver`). `prodErrorMap` is accepted and DELIBERATELY not honored: installing it upstream strips error messages, and doing that in a sandbox whose purpose is to tell a developer what went wrong would be actively hostile.","status":"diverged-documented","evidence":["In an in-memory sandbox the persistence CHOICE has no observable consequence, so accepting the token and recording the mode is the honest behavior — the same inert-token pattern `pyric/firestore` uses for its cache-factory tokens. `unit:types.test.ts` + `unit:sandbox-email-link.test.ts` cover the exports. Oracle caveat recorded on auth#172: the `persistenceTypes` block of `auth-mechanical-surface-constants` reports `NONE` for every token including `browserLocalPersistence` — a Node-build stub artifact, not the browser contract, so the `.type` values here follow the documented `Persistence.type` union instead.","packages/pyric/test/auth/types.test.ts","packages/pyric/test/auth/sandbox-email-link.test.ts"],"assurance":"qualified"}]},{"feature":"IndexField","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"IndexField is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:IndexField","kind":"type-export","surface":"firestore","behavior":"IndexField is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"indexOn","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"indexOn is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"rtdb-rules#13","kind":"registry-row","surface":"rtdb-rules","behavior":"`getPriority()` on a plain `set` (an unset priority reads null) and the `.indexOn` query-planner directive","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves a plain `set` leaves a node's priority unset, so `getPriority()` reports null in production exactly as the simulator does, and that a ruleset carrying `.indexOn` deploys and evaluates with every verdict intact. The scope is exactly that: `.indexOn` never changes an allow/deny verdict, so the twin evidences only that production's compiler accepts and deploys the directive, and it says nothing about query behavior. A NON-null priority stays unverified because writing one requires `setWithPriority`, outside the corpus op vocabulary of read and set. `oracle:rules-rtdb-r13-priority-and-index-directive` matches production verdict-for-verdict on all 4 cases.","observation:rules-rtdb-r13-priority-and-index-directive","packages/pyric/test/rules/rtdb/rules-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"InferenceMode","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"InferenceMode is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Hybrid/on-device inference is deferred, not out of scope — the sandbox runs in the browser and can model the on-device path through the answer-engine seam; the mode has not been wired yet.","Public type export is not mirrored."],"claims":[{"id":"ai:runtime:InferenceMode","kind":"runtime-export","surface":"ai","behavior":"Hybrid/on-device inference is deferred, not out of scope — the sandbox runs in the browser and can model the on-device path through the answer-engine seam; the mode has not been wired yet.","status":"deferred","evidence":["upstream:firebase/ai"],"assurance":"not-applicable"},{"id":"ai:type:InferenceMode","kind":"type-export","surface":"ai","behavior":"InferenceMode is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"InferenceSource","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"InferenceSource is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Deferred with hybrid/on-device inference — the source marker is meaningful once the hybrid mode lands.","Public type export is not mirrored."],"claims":[{"id":"ai:runtime:InferenceSource","kind":"runtime-export","surface":"ai","behavior":"Deferred with hybrid/on-device inference — the source marker is meaningful once the hybrid mode lands.","status":"deferred","evidence":["disposition:ai.hybrid-inference"],"assurance":"not-applicable"},{"id":"ai:type:InferenceSource","kind":"type-export","surface":"ai","behavior":"InferenceSource is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"initializeApp","surface":"app","importPaths":["pyric/app"],"evidenceSlug":"app-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"initializeApp is available, has diverged fidelity, and is qualified for assurance.","caveats":["Production permits a differently configured named app; Pyric rejects it because one runtime currently owns exactly one sandbox backend","oracle: `app-registry-initializeapp-named-different-config` (firebase 12.13.0) + replay pins `app/multiple-configs-not-supported`; `packages/cli/test/e2e/app-multi-app.pw.ts` proves the same lock is enforced by the authoritative SharedWorker across same-origin tabs, not only by one page registry","Production permits a different configuration after deletion; Pyric retains the runtime backend lock and rejects the reinitialization","oracle: `app-registry-delete-reinitialize-different-config` (firebase 12.13.0) + replay pins `app/multiple-configs-not-supported`"],"claims":[{"id":"app:runtime:initializeApp","kind":"runtime-export","surface":"app","behavior":"initializeApp is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"app#1","kind":"registry-row","surface":"app","behavior":"Registers the default app under the name `'[DEFAULT]'`; `getApps()` has length 1 and `getApp()` (no arg) resolves the same instance","status":"conforms","evidence":["oracle: `app-registry-initializeapp-default` (firebase 12.13.0) + replay: `oracle-conformance.test.ts`","observation:app-registry-initializeapp-default","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"app#16","kind":"registry-row","surface":"app","behavior":"`initializeApp` snapshots options, accepts a settings object, initializes `automaticDataCollectionEnabled`, and leaves that app property mutable","status":"conforms","evidence":["oracle: `app-registry-initializeapp-settings-options` (firebase 12.13.0) + replay: `oracle-conformance.test.ts`","observation:app-registry-initializeapp-settings-options","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"app#17","kind":"registry-row","surface":"app","behavior":"Equal-config named apps are distinct app containers with equal option values and independent name-keyed registry identity","status":"conforms","evidence":["oracle: `app-registry-initializeapp-named-equal-config` (firebase 12.13.0) + replay: `oracle-conformance.test.ts`","observation:app-registry-initializeapp-named-equal-config","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"app#19","kind":"registry-row","surface":"app","behavior":"Production permits a differently configured named app; Pyric rejects it because one runtime currently owns exactly one sandbox backend","status":"diverged-documented","evidence":["oracle: `app-registry-initializeapp-named-different-config` (firebase 12.13.0) + replay pins `app/multiple-configs-not-supported`; `packages/cli/test/e2e/app-multi-app.pw.ts` proves the same lock is enforced by the authoritative SharedWorker across same-origin tabs, not only by one page registry","observation:app-registry-initializeapp-named-different-config","packages/pyric/test/app/oracle-conformance.test.ts","packages/cli/test/e2e/app-multi-app.pw.ts"],"assurance":"qualified"},{"id":"app#2","kind":"registry-row","surface":"app","behavior":"Registers a named app alongside the default; `getApp('secondary')` resolves it and `getApps()` has length 2 (default + named)","status":"conforms","evidence":["oracle: `app-registry-initializeapp-named` (firebase 12.13.0) + replay: `oracle-conformance.test.ts`","observation:app-registry-initializeapp-named","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"app#20","kind":"registry-row","surface":"app","behavior":"Production permits a different configuration after deletion; Pyric retains the runtime backend lock and rejects the reinitialization","status":"diverged-documented","evidence":["oracle: `app-registry-delete-reinitialize-different-config` (firebase 12.13.0) + replay pins `app/multiple-configs-not-supported`","observation:app-registry-delete-reinitialize-different-config","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"qualified"},{"id":"app#21","kind":"registry-row","surface":"app","behavior":"Without Hosting-provided defaults, omitting options throws FirebaseError code `app/no-options` with the production message","status":"conforms","evidence":["oracle: `app-registry-initializeapp-no-options` (firebase 12.13.0) + replay: `oracle-conformance.test.ts`","observation:app-registry-initializeapp-no-options","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"app#23","kind":"registry-row","surface":"app","behavior":"Equal-config app instances connect to one logical backend: data written through one app is readable through another, while their active Auth sessions remain independent","status":"conforms","evidence":["oracle: `app-production-multi-app-topology` (firebase 12.13.0, real Chromium against production) + twin replay: `production-multi-app-oracle.test.ts`; served SharedWorker replay: `app-multi-app.pw.ts`","observation:app-production-multi-app-topology","packages/pyric/test/app/production-multi-app-oracle.test.ts","packages/cli/test/e2e/app-multi-app.pw.ts"],"assurance":"eligible"},{"id":"app#3","kind":"registry-row","surface":"app","behavior":"A same-name re-initialization with a DIFFERENT config throws `FirebaseError` code `app/duplicate-app`, with the app name embedded in the message","status":"conforms","evidence":["oracle: `app-registry-initializeapp-duplicate-name` (firebase 12.13.0) + replay: `oracle-conformance.test.ts`","observation:app-registry-initializeapp-duplicate-name","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"app#4","kind":"registry-row","surface":"app","behavior":"A same-name re-initialization with EQUAL config is idempotent — no throw, returns the existing instance, and `getApps()` stays length 1","status":"conforms","evidence":["oracle: `app-registry-initializeapp-duplicate-config` (firebase 12.13.0) + replay: `oracle-conformance.test.ts`","observation:app-registry-initializeapp-duplicate-config","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"initializeAuth","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"initializeAuth is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:initializeAuth","kind":"runtime-export","surface":"auth","behavior":"initializeAuth is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#82","kind":"registry-row","surface":"auth","behavior":"Aliases `getAuth(app)` and returns the same stable `Auth` handle — an app that calls `initializeAuth` instead of `getAuth` gets an equivalent, working instance. The optional `Dependencies` arg (persistence / popupRedirectResolver) is accepted for signature parity but not applied (persistence is already a documented sandbox no-op). Repeated calls return the cached handle rather than throwing `auth/already-initialized`","status":"conforms","evidence":["`unit:fruit-aliases.test.ts` — returns the same instance as `getAuth`, with a live `currentUser`","packages/pyric/test/auth/fruit-aliases.test.ts"],"assurance":"eligible"}]},{"feature":"initializeFirestore","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"initializeFirestore is available, has diverged fidelity, and is qualified for assurance.","caveats":["Delegates to sandbox `getFirestore(app)` and returns the same handle. Accepts the `settings` argument (so the explicit-init pattern doesn't crash at import) but no-ops the cache/network settings — persistence is always on","`unit:firestore/tier1-cache-init-align.test.ts`"],"claims":[{"id":"firestore:runtime:initializeFirestore","kind":"runtime-export","surface":"firestore","behavior":"initializeFirestore is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#145","kind":"registry-row","surface":"firestore","behavior":"Delegates to sandbox `getFirestore(app)` and returns the same handle. Accepts the `settings` argument (so the explicit-init pattern doesn't crash at import) but no-ops the cache/network settings — persistence is always on","status":"diverged-documented","evidence":["`unit:firestore/tier1-cache-init-align.test.ts`","packages/pyric/test/firestore/tier1-cache-init-align.test.ts"],"assurance":"qualified"}]},{"feature":"initializeRecaptchaConfig","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"initializeRecaptchaConfig is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["MFA / phone / reCAPTCHA is deferred, not out of scope — reCAPTCHA/SMS are external infrastructure Pyric can mock with the OAuth resolver pattern, and TOTP is pure algorithm work."],"claims":[{"id":"auth:runtime:initializeRecaptchaConfig","kind":"runtime-export","surface":"auth","behavior":"MFA / phone / reCAPTCHA is deferred, not out of scope — reCAPTCHA/SMS are external infrastructure Pyric can mock with the OAuth resolver pattern, and TOTP is pure algorithm work.","status":"deferred","evidence":["registry:auth#180"],"assurance":"not-applicable"}]},{"feature":"initializeServerApp","surface":"app","importPaths":["pyric/app"],"evidenceSlug":"app-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"initializeServerApp is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Server-app (SSR) initialization: a FirebaseServerApp carries per-request auth/heartbeat state with no decided sandbox mirror pattern yet. Deferred, not out of scope — tracked as an unsupported registry row (registry/app.ts app#15).","Not implemented; disposition `app.server-app` owns the reviewed availability and rationale","disposition:app.server-app"],"claims":[{"id":"app:runtime:initializeServerApp","kind":"runtime-export","surface":"app","behavior":"Server-app (SSR) initialization: a FirebaseServerApp carries per-request auth/heartbeat state with no decided sandbox mirror pattern yet. Deferred, not out of scope — tracked as an unsupported registry row (registry/app.ts app#15).","status":"deferred","evidence":["registry:app#15"],"assurance":"not-applicable"},{"id":"app#15","kind":"registry-row","surface":"app","behavior":"Not implemented; disposition `app.server-app` owns the reviewed availability and rationale","status":"unsupported","evidence":["disposition:app.server-app"],"assurance":"ineligible"}]},{"feature":"InlineDataPart","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"InlineDataPart is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:InlineDataPart","kind":"type-export","surface":"ai","behavior":"InlineDataPart is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"inlineDataParts","surface":"ai","importPaths":[],"evidenceSlug":"ai-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"inlineDataParts is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"ai#helper-inlinedataparts","kind":"registry-row","surface":"ai","behavior":"`inlineDataParts()` returns the `InlineDataPart` array when inlineData parts exist and undefined when none do","status":"conforms","evidence":["`unit:helpers-schema.test.ts` test `ai#helper-inlinedataparts` (exercised with a scripted raw envelope)","packages/pyric/test/ai/helpers-schema.test.ts"],"assurance":"eligible"}]},{"feature":"inMemoryPersistence","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"inMemoryPersistence is available, has diverged fidelity, and is qualified for assurance.","caveats":["Inert configuration tokens, accepted so the idiomatic `initializeAuth(app, { persistence: indexedDBLocalPersistence })` and `setPersistence(auth, browserCookiePersistence)` compile, run, and behave identically. The `.type` discriminant matches upstream exactly (`NONE` / `SESSION` / `LOCAL` / `LOCAL` / `COOKIE`) because consumer code branches on it. `browserPopupRedirectResolver` is accepted and ignored — the sandbox has its own first-class pluggable equivalent (`sandbox.setAuthFlowResolver`). `prodErrorMap` is accepted and DELIBERATELY not honored: installing it upstream strips error messages, and doing that in a sandbox whose purpose is to tell a developer what went wrong would be actively hostile.","In an in-memory sandbox the persistence CHOICE has no observable consequence, so accepting the token and recording the mode is the honest behavior — the same inert-token pattern `pyric/firestore` uses for its cache-factory tokens. `unit:types.test.ts` + `unit:sandbox-email-link.test.ts` cover the exports. Oracle caveat recorded on auth#172: the `persistenceTypes` block of `auth-mechanical-surface-constants` reports `NONE` for every token including `browserLocalPersistence` — a Node-build stub artifact, not the browser contract, so the `.type` values here follow the documented `Persistence.type` union instead."],"claims":[{"id":"auth:runtime:inMemoryPersistence","kind":"runtime-export","surface":"auth","behavior":"inMemoryPersistence is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#178","kind":"registry-row","surface":"auth","behavior":"Inert configuration tokens, accepted so the idiomatic `initializeAuth(app, { persistence: indexedDBLocalPersistence })` and `setPersistence(auth, browserCookiePersistence)` compile, run, and behave identically. The `.type` discriminant matches upstream exactly (`NONE` / `SESSION` / `LOCAL` / `LOCAL` / `COOKIE`) because consumer code branches on it. `browserPopupRedirectResolver` is accepted and ignored — the sandbox has its own first-class pluggable equivalent (`sandbox.setAuthFlowResolver`). `prodErrorMap` is accepted and DELIBERATELY not honored: installing it upstream strips error messages, and doing that in a sandbox whose purpose is to tell a developer what went wrong would be actively hostile.","status":"diverged-documented","evidence":["In an in-memory sandbox the persistence CHOICE has no observable consequence, so accepting the token and recording the mode is the honest behavior — the same inert-token pattern `pyric/firestore` uses for its cache-factory tokens. `unit:types.test.ts` + `unit:sandbox-email-link.test.ts` cover the exports. Oracle caveat recorded on auth#172: the `persistenceTypes` block of `auth-mechanical-surface-constants` reports `NONE` for every token including `browserLocalPersistence` — a Node-build stub artifact, not the browser contract, so the `.type` values here follow the documented `Persistence.type` union instead.","packages/pyric/test/auth/types.test.ts","packages/pyric/test/auth/sandbox-email-link.test.ts"],"assurance":"qualified"}]},{"feature":"int","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"int is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#180","kind":"registry-row","surface":"firestore-rules","behavior":"`request.time` Timestamp accessors (year/month/day/hours/minutes/seconds/nanos/dayOfWeek/dayOfYear/toMillis/date/time), `math.floor/round/sqrt/pow/isNaN`, `int()/float()/string()` casts, `request.method`, and `>=` / `*` operators in rules","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 3 cases (request.time pinned via requestTime for determinism). `oracle:rules-firestore-time-math-and-casts` — replayed by `unit:rules/oracle-conformance.test.ts`.","observation:rules-firestore-time-math-and-casts","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"IntegerSchema","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"IntegerSchema is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:IntegerSchema","kind":"runtime-export","surface":"ai","behavior":"IntegerSchema is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:IntegerSchema","kind":"type-export","surface":"ai","behavior":"IntegerSchema is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"intersection","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"intersection is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#174","kind":"registry-row","surface":"firestore-rules","behavior":"`Set.difference()`/`union()`/`intersection()` (Item 5.1) in rules","status":"conforms","evidence":["`oracle:rules-firestore-set-algebra-difference-union-intersection` — production Firestore Rules Test API verdicts for corpus scenario \"set-algebra-difference-union-intersection\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`; all cases match production.","observation:rules-firestore-set-algebra-difference-union-intersection","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"isSignInWithEmailLink","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"isSignInWithEmailLink is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:isSignInWithEmailLink","kind":"runtime-export","surface":"auth","behavior":"isSignInWithEmailLink is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#151","kind":"registry-row","surface":"auth","behavior":"Pure predicate over the link string — no network. `true` only for a link whose mode is `signIn` AND which carries an `oobCode`; `false` for a password-reset link, for `mode=signIn` with no code, for garbage, and for the empty string. Never throws.","status":"conforms","evidence":["ORACLE-BACKED, project-independent (no server involved): `auth-issigninwithemaillink-predicate` captured all five cases against prod. Replayed in `unit:oracle-conformance.test.ts`.","observation:auth-issigninwithemaillink-predicate","packages/pyric/test/auth/oracle-conformance.test.ts","packages/pyric/test/auth/sandbox-email-link.test.ts"],"assurance":"eligible"}]},{"feature":"isSupported","surface":"messaging","importPaths":["pyric/messaging","pyric/messaging/sw"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"isSupported is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-sw:runtime:isSupported","kind":"runtime-export","surface":"messaging-sw","behavior":"isSupported is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"messaging:runtime:isSupported","kind":"runtime-export","surface":"messaging","behavior":"isSupported is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"messaging#16","kind":"registry-row","surface":"messaging","behavior":"Resolves whether every API required by FCM exists within the service-worker context (bound to `isSwSupported`).","status":"conforms","evidence":["Upstream typings (`@firebase/messaging` 0.12.26 `sw/index-public`); no observation yet.","packages/pyric/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"messaging#17","kind":"registry-row","surface":"messaging","behavior":"The sw entry exports `onBackgroundMessage`, `getMessaging`, `experimentalSetDeliveryMetricsExportedToBigQueryEnabled`, and `isSupported`, but NOT `getToken` / `deleteToken` / `onMessage`; the client entry exports the latter but NOT `onBackgroundMessage` / the metrics toggle. The two modules register under different component names (`messaging` vs `messaging-sw`) and re-export identical `Messaging` / `GetTokenOptions` / `MessagePayload` / `NotificationPayload` / `FcmOptions` type declarations.","status":"conforms","evidence":["Upstream typings (`@firebase/messaging` 0.12.26 `index.d.ts` / `index.sw.d.ts`) plus Window and real module-ServiceWorker boundary replay `messaging-app-boundary.pw.ts`.","packages/pyric/test/messaging/oracle-conformance.test.ts","packages/cli/test/e2e/messaging-app-boundary.pw.ts"],"assurance":"eligible"},{"id":"messaging#5","kind":"registry-row","surface":"messaging","behavior":"Resolves whether every API required by FCM exists in the current browser window context (bound to `isWindowSupported`).","status":"conforms","evidence":["Upstream typings/JSDoc (`@firebase/messaging` 0.12.26); no observation yet.","packages/pyric/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"IteratedDataSnapshot","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"IteratedDataSnapshot is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"database:type:IteratedDataSnapshot","kind":"type-export","surface":"database","behavior":"IteratedDataSnapshot is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"keys","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"keys is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#178","kind":"registry-row","surface":"firestore-rules","behavior":"Required-fields validation idiom in rules — `request.resource.data.keys().hasAll()/hasOnly()` and the `diff().addedKeys()/removedKeys()/changedKeys()/affectedKeys()/unchangedKeys()` MapDiff family gating field-level mutations","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 7 cases (exact required-field set on create, field-scoped update via MapDiff). `oracle:rules-firestore-required-fields-and-mapdiff` — replayed by `unit:rules/oracle-conformance.test.ts`.","observation:rules-firestore-required-fields-and-mapdiff","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"Language","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"Language is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:Language","kind":"runtime-export","surface":"ai","behavior":"Language is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:Language","kind":"type-export","surface":"ai","behavior":"Language is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"LanguageModelCreateCoreOptions","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"LanguageModelCreateCoreOptions is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:LanguageModelCreateCoreOptions","kind":"type-export","surface":"ai","behavior":"LanguageModelCreateCoreOptions is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"LanguageModelCreateOptions","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"LanguageModelCreateOptions is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:LanguageModelCreateOptions","kind":"type-export","surface":"ai","behavior":"LanguageModelCreateOptions is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"LanguageModelExpected","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"LanguageModelExpected is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:LanguageModelExpected","kind":"type-export","surface":"ai","behavior":"LanguageModelExpected is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"LanguageModelMessage","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"LanguageModelMessage is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:LanguageModelMessage","kind":"type-export","surface":"ai","behavior":"LanguageModelMessage is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"LanguageModelMessageContent","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"LanguageModelMessageContent is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:LanguageModelMessageContent","kind":"type-export","surface":"ai","behavior":"LanguageModelMessageContent is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"LanguageModelMessageContentValue","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"LanguageModelMessageContentValue is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:LanguageModelMessageContentValue","kind":"type-export","surface":"ai","behavior":"LanguageModelMessageContentValue is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"LanguageModelMessageRole","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"LanguageModelMessageRole is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:LanguageModelMessageRole","kind":"type-export","surface":"ai","behavior":"LanguageModelMessageRole is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"LanguageModelMessageType","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"LanguageModelMessageType is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:LanguageModelMessageType","kind":"type-export","surface":"ai","behavior":"LanguageModelMessageType is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"LanguageModelPromptOptions","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"LanguageModelPromptOptions is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:LanguageModelPromptOptions","kind":"type-export","surface":"ai","behavior":"LanguageModelPromptOptions is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"LatLng","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"LatLng is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:LatLng","kind":"type-export","surface":"ai","behavior":"LatLng is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"latlng","surface":"firestore-rules","importPaths":["pyric/rules"],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"latlng is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#181","kind":"registry-row","surface":"firestore-rules","behavior":"`latlng.value().latitude()/longitude()/distance()` and `duration.value()/time()/abs()` in rules","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 2 cases (coordinate + duration bounds). `oracle:rules-firestore-duration-and-latlng` — replayed by `unit:rules/oracle-conformance.test.ts`.","observation:rules-firestore-duration-and-latlng","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"latlng.distance","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"latlng.distance is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.latlng.distance","kind":"rules-construct","surface":"firestore-rules","behavior":"latlng.distance is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.LatLng#function_distance_"],"assurance":"eligible"}]},{"feature":"latlng.latitude","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"latlng.latitude is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.latlng.latitude","kind":"rules-construct","surface":"firestore-rules","behavior":"latlng.latitude is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.LatLng#function_latitude_"],"assurance":"eligible"}]},{"feature":"latlng.longitude","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"latlng.longitude is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.latlng.longitude","kind":"rules-construct","surface":"firestore-rules","behavior":"latlng.longitude is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.LatLng#function_longitude_"],"assurance":"eligible"}]},{"feature":"latlng.value","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"latlng.value is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.function.latlng.value","kind":"rules-construct","surface":"firestore-rules","behavior":"latlng.value is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.latlng#function_value_"],"assurance":"eligible"}]},{"feature":"let","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"let is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#182","kind":"registry-row","surface":"firestore-rules","behavior":"User-defined `function`/`let`, granular `allow get/list/update/write` verbs, the ternary operator, and a recursive `{document=**}` match in rules","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 7 cases (role-gated docs + public recursive subtree). `oracle:rules-firestore-functions-verbs-and-recursive` — replayed by `unit:rules/oracle-conformance.test.ts`.","observation:rules-firestore-functions-verbs-and-recursive","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"let","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"let is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#104","kind":"registry-row","surface":"storage-rules","behavior":"User-defined `function` definitions — `let` bindings, functions calling functions, and match-block-scoped helper functions (lexical scoping)","status":"conforms","evidence":["STALE ROW, corrected 2026-07-10: production capture proves the evaluator supports user-defined functions with `let` bindings, nested function calls, and block-scoped helpers. `oracle:rules-storage-functions-let-scope` matches production verdict-for-verdict on all 5 cases. Same-name shadowing and undefined-function calls are compile-time rejections in production and are covered by evaluator unit tests instead (they cannot be captured as a clean production verdict).","observation:rules-storage-functions-let-scope","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"lexicalScope","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"lexicalScope is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#104","kind":"registry-row","surface":"storage-rules","behavior":"User-defined `function` definitions — `let` bindings, functions calling functions, and match-block-scoped helper functions (lexical scoping)","status":"conforms","evidence":["STALE ROW, corrected 2026-07-10: production capture proves the evaluator supports user-defined functions with `let` bindings, nested function calls, and block-scoped helpers. `oracle:rules-storage-functions-let-scope` matches production verdict-for-verdict on all 5 cases. Same-name shadowing and undefined-function calls are compile-time rejections in production and are covered by evaluator unit tests instead (they cannot be captured as a clean production verdict).","observation:rules-storage-functions-let-scope","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"LightSettings","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"LightSettings is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#29","kind":"registry-row","surface":"messaging-admin","behavior":"Android LED light settings — all three fields required.","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `messaging-api`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"limit","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"limit is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:limit","kind":"runtime-export","surface":"firestore","behavior":"limit is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#54","kind":"registry-row","surface":"firestore","behavior":"`query(coll, where(…), orderBy(…), limit(…))` composes constraints in order","status":"conforms","evidence":["`unit:sandbox-target.test.ts`, `playground:firestore-query`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#60","kind":"registry-row","surface":"firestore","behavior":"`limit(n)` — caps result count","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#62","kind":"registry-row","surface":"firestore","behavior":"Composite filters AND with other constraints — `query(coll, or(...), orderBy(...), limit(...))`","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#63","kind":"registry-row","surface":"firestore","behavior":"Passing `orderBy` / `limit` into `or()` / `and()` → `TypeError`","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"limitToFirst","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"limitToFirst is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"database:runtime:limitToFirst","kind":"runtime-export","surface":"database","behavior":"limitToFirst is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#142","kind":"registry-row","surface":"rtdb-modular","behavior":"`query(ref, orderByChild('field'), limitToFirst(N))` returns a `Query` whose `get()` resolves a snapshot containing N children ordered by `field`","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-query-orderbychild-limit.json` — seeded 4 children with positions `[3,1,4,2]`, observed `orderedKeys: [{key:'a',pos:1}, {key:'b',pos:2}]` (first 2 in ascending order). Requires `.indexOn` declared in rules.","observation:rtdb-modular-orderbychild-window","observation:rtdb-modular-query-orderbychild-limit"],"assurance":"eligible"},{"id":"rtdb-modular#150","kind":"registry-row","surface":"rtdb-modular","behavior":"`limitToFirst(N)` caps the result count from the start of the ordered range","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-query-orderbychild-limit.json` plus `packages/conformance/observations/rtdb-modular/rtdb-modular-limittofirst-vs-limittolast.json` (firstPositions `[1,2]`).","observation:rtdb-modular-limittofirst-vs-limittolast","observation:rtdb-modular-orderbyvalue-numeric","observation:rtdb-modular-query-orderbychild-limit"],"assurance":"eligible"},{"id":"rtdb-modular#M51","kind":"registry-row","surface":"rtdb-modular","behavior":"`orderByValue()` orders primitive children by their value; `limitToFirst(N)` returns the N smallest, ascending","status":"conforms","evidence":["Sandbox aligned: `unit:modular/queries.test.ts` (\"returns the limitToFirst(N) smallest values, ascending\"). Oracle observation `packages/conformance/observations/rtdb-modular/rtdb-modular-orderbyvalue-numeric.json` shows prod threw `Index not defined` against blockingfun — the sandbox does NOT enforce `.indexOn` (rules-engine integration for query indexes is deferred); the semantic claim (ordering by value) is locked here.","observation:rtdb-modular-orderbyvalue-numeric","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M54","kind":"registry-row","surface":"rtdb-modular","behavior":"`limitToFirst(N)` keeps the lowest-ranked N children (post-ordering, pre-filter)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/queries.test.ts` (\"limitToFirst takes the lowest-ranked window\"); matches oracle observation `packages/conformance/observations/rtdb-modular/rtdb-modular-limittofirst-vs-limittolast.json` (firstPositions `[1,2]`).","observation:rtdb-modular-limittofirst-vs-limittolast","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M56","kind":"registry-row","surface":"rtdb-modular","behavior":"`limitToFirst(N)` larger than the result returns the full window (no padding, no throw)","status":"conforms","evidence":["`unit:modular/queries.test.ts` (\"limitToFirst(N) larger than the result returns the full window\")","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M69","kind":"registry-row","surface":"rtdb-modular","behavior":"Conflicting query constraints throw synchronously at `query(...)` construction (NOT silent last-win): multiple `orderBy*`, a second `limitToFirst`/`limitToLast`, a second start (`startAt`/`startAfter`/`equalTo`) or end (`endAt`/`endBefore`/`equalTo`) (DB-B5)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/constraint-conflicts.test.ts` (5 cases); upstream `api/Reference_impl.ts:160-165,1824-1841,1888-1905,1945-1951,2193-2206`","packages/pyric/test/database/modular/constraint-conflicts.test.ts"],"assurance":"eligible"}]},{"feature":"limitToLast","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"limitToLast is available, has diverged fidelity, and is qualified for assurance.","caveats":["`limitToLast(n)` — trailing n in ordered result (requires `orderBy`). Sandbox: the no-orderBy precondition throws a `FirestoreError` with `.code === 'invalid-argument'` (FS-B16; pre-fix plain `Error`s). Prod: the same precondition throws `.code === 'unimplemented'`","divergence, oracle-locked by `packages/conformance/observations/firestore/firestore-limittolast-preconditions.json`: prod's no-orderBy `limitToLast` throws code `unimplemented`, the sandbox throws `invalid-argument`. Trailing-window semantics with `orderBy` conform (observed `[\"b\"]` matches). Both sides pinned in `oracle-conformance.test.ts`. Cursor composition + descending: `unit:upstream-query-probes.test.ts`. Cursor/empty-snapshot precondition codes remain per `unit:sandbox-target.test.ts` + `unit:admin-compat/cursors.test.ts` (verified failing pre-fix)"],"claims":[{"id":"firestore:runtime:limitToLast","kind":"runtime-export","surface":"firestore","behavior":"limitToLast is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#61","kind":"registry-row","surface":"firestore","behavior":"`limitToLast(n)` — trailing n in ordered result (requires `orderBy`). Sandbox: the no-orderBy precondition throws a `FirestoreError` with `.code === 'invalid-argument'` (FS-B16; pre-fix plain `Error`s). Prod: the same precondition throws `.code === 'unimplemented'`","status":"diverged-documented","evidence":["divergence, oracle-locked by `packages/conformance/observations/firestore/firestore-limittolast-preconditions.json`: prod's no-orderBy `limitToLast` throws code `unimplemented`, the sandbox throws `invalid-argument`. Trailing-window semantics with `orderBy` conform (observed `[\"b\"]` matches). Both sides pinned in `oracle-conformance.test.ts`. Cursor composition + descending: `unit:upstream-query-probes.test.ts`. Cursor/empty-snapshot precondition codes remain per `unit:sandbox-target.test.ts` + `unit:admin-compat/cursors.test.ts` (verified failing pre-fix)","observation:firestore-limittolast-preconditions","packages/pyric/test/firestore/sandbox-target.test.ts","packages/pyric/test/sandbox/firestore/admin-compat/cursors.test.ts","packages/pyric/test/firestore/oracle-conformance.test.ts","packages/pyric/test/firestore/upstream-query-probes.test.ts"],"assurance":"qualified"}]},{"feature":"limitToLast","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"limitToLast is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"database:runtime:limitToLast","kind":"runtime-export","surface":"database","behavior":"limitToLast is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#151","kind":"registry-row","surface":"rtdb-modular","behavior":"`limitToLast(N)` caps from the end","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-limittofirst-vs-limittolast.json` — observed `lastKeys: ['d','e'], lastPositions: [4,5]` for `limitToLast(2)` on a 5-child collection ordered by `pos`.","observation:rtdb-modular-limittofirst-vs-limittolast"],"assurance":"eligible"},{"id":"rtdb-modular#M55","kind":"registry-row","surface":"rtdb-modular","behavior":"`limitToLast(N)` keeps the highest-ranked N children","status":"conforms","evidence":["Sandbox aligned: `unit:modular/queries.test.ts` (\"limitToLast takes the highest-ranked window\"); matches oracle observation `packages/conformance/observations/rtdb-modular/rtdb-modular-limittofirst-vs-limittolast.json` (lastPositions `[4,5]`).","observation:rtdb-modular-limittofirst-vs-limittolast","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M69","kind":"registry-row","surface":"rtdb-modular","behavior":"Conflicting query constraints throw synchronously at `query(...)` construction (NOT silent last-win): multiple `orderBy*`, a second `limitToFirst`/`limitToLast`, a second start (`startAt`/`startAfter`/`equalTo`) or end (`endAt`/`endBefore`/`equalTo`) (DB-B5)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/constraint-conflicts.test.ts` (5 cases); upstream `api/Reference_impl.ts:160-165,1824-1841,1888-1905,1945-1951,2193-2206`","packages/pyric/test/database/modular/constraint-conflicts.test.ts"],"assurance":"eligible"}]},{"feature":"linkWithCredential","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"linkWithCredential is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:linkWithCredential","kind":"runtime-export","surface":"auth","behavior":"linkWithCredential is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#160","kind":"registry-row","surface":"auth","behavior":"The ANONYMOUS UPGRADE. Linking an email credential onto an anonymous account upgrades it IN PLACE: the uid is PRESERVED, `isAnonymous` flips to `false`, the email is set, and `providerData` gains the provider. Preserving the uid is what keeps the data the user created while anonymous theirs. Returns a `UserCredential` with `operationType: 'link'` and `getAdditionalUserInfo().isNewUser === false` (a link never creates an identity). The linked credential then works as a first-class `signInWithEmailAndPassword`.","status":"conforms","evidence":["UNIT-BACKED, not oracle-backed — stated plainly. The probe (`auth-link-email-credential-to-anonymous`) ran against the real project and returned `linkCode: auth/operation-not-allowed`: the oracle project has the Email/Password provider DISABLED, so no email credential can be minted there and the flow cannot be reached. The capture is committed showing exactly that rather than being dropped. Behavior proven in `unit:sandbox-linking-reauth.test.ts`, including the uid-preservation invariant.","observation:auth-link-email-credential-to-anonymous","packages/pyric/test/auth/sandbox-linking-reauth.test.ts"],"assurance":"eligible"},{"id":"auth#161","kind":"registry-row","surface":"auth","behavior":"`auth/provider-already-linked` when the account already carries the provider (one identity per provider). `auth/email-already-in-use` when the email credential belongs to a DIFFERENT account — an address can back only one identity, so the link cannot be granted without stealing it.","status":"conforms","evidence":["UNIT-BACKED. The probe (`auth-link-conflicts`) ran and every arm returned `auth/operation-not-allowed` (same disabled Email/Password provider on the oracle project), so the conflict codes could not be observed against prod. They are matched instead to the oracle-CAPTURED `AuthErrorCodes` map (`PROVIDER_ALREADY_LINKED = auth/provider-already-linked`, `CREDENTIAL_ALREADY_IN_USE = auth/credential-already-in-use` — auth#172) and proven in `unit:sandbox-linking-reauth.test.ts`. NOTE: for an EMAIL credential the sandbox emits `auth/email-already-in-use`, the code prod uses for an address collision; `credential-already-in-use` remains the OAuth-credential case.","observation:auth-link-conflicts","packages/pyric/test/auth/sandbox-linking-reauth.test.ts"],"assurance":"eligible"}]},{"feature":"linkWithPhoneNumber","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"linkWithPhoneNumber is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["MFA / phone / reCAPTCHA is deferred, not out of scope — reCAPTCHA/SMS are external infrastructure Pyric can mock with the OAuth resolver pattern, and TOTP is pure algorithm work."],"claims":[{"id":"auth:runtime:linkWithPhoneNumber","kind":"runtime-export","surface":"auth","behavior":"MFA / phone / reCAPTCHA is deferred, not out of scope — reCAPTCHA/SMS are external infrastructure Pyric can mock with the OAuth resolver pattern, and TOTP is pure algorithm work.","status":"deferred","evidence":["registry:auth#180"],"assurance":"not-applicable"}]},{"feature":"linkWithPopup","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"linkWithPopup is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:linkWithPopup","kind":"runtime-export","surface":"auth","behavior":"linkWithPopup is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#164","kind":"registry-row","surface":"auth","behavior":"Route through the SAME `AuthFlowResolver` seam as `signInWithPopup`, with `authType: 'link'` on the request so a host UI can present 'link your Google account' rather than 'sign in'. The resolved credential names the provider to attach; the sandbox performs the attach and the uid is preserved. A disabled provider throws `auth/operation-not-allowed` AHEAD of the resolver check — a code deliberately distinct from `auth/argument-error`, which keeps meaning 'enabled, but no resolver/mock wired'.","status":"conforms","evidence":["`unit:sandbox-linking-reauth.test.ts` — asserts the resolver sees `authType: 'link'`, the uid is preserved, and the two error codes stay distinct. The OAuth arm cannot be oracle-probed at all (it needs a real IdP popup and a human), which is precisely why it goes through the resolver seam.","packages/pyric/test/auth/sandbox-linking-reauth.test.ts"],"assurance":"eligible"}]},{"feature":"linkWithRedirect","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"linkWithRedirect is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:linkWithRedirect","kind":"runtime-export","surface":"auth","behavior":"linkWithRedirect is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#164","kind":"registry-row","surface":"auth","behavior":"Route through the SAME `AuthFlowResolver` seam as `signInWithPopup`, with `authType: 'link'` on the request so a host UI can present 'link your Google account' rather than 'sign in'. The resolved credential names the provider to attach; the sandbox performs the attach and the uid is preserved. A disabled provider throws `auth/operation-not-allowed` AHEAD of the resolver check — a code deliberately distinct from `auth/argument-error`, which keeps meaning 'enabled, but no resolver/mock wired'.","status":"conforms","evidence":["`unit:sandbox-linking-reauth.test.ts` — asserts the resolver sees `authType: 'link'`, the uid is preserved, and the two error codes stay distinct. The OAuth arm cannot be oracle-probed at all (it needs a real IdP popup and a human), which is precisely why it goes through the resolver seam.","packages/pyric/test/auth/sandbox-linking-reauth.test.ts"],"assurance":"eligible"}]},{"feature":"List","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"List is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#179","kind":"registry-row","surface":"firestore-rules","behavior":"`String.split()/lower()/upper()/trim()/replace()/size()`, `List.hasAll()/hasAny()/hasOnly()/join()`, and `Map.values()` in rules","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 4 cases (CSV-split membership, slug/title/code normalization). `oracle:rules-firestore-list-and-string-methods` — replayed by `unit:rules/oracle-conformance.test.ts`.","observation:rules-firestore-list-and-string-methods","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"list","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"list is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Paginated listing is deferred — listAll covers the v1 scope; pagination needs a stable pageToken shape, which is unbuilt design work rather than a sandbox limitation.","Exported by `firebase/storage`; accepts `{ maxResults, pageToken }`, returns a `ListResult` with `nextPageToken` set when more pages remain","No paginated `list` implementation or behavioral probe exists; availability is classified by the owning surface contract. `ListResult.nextPageToken` remains optional for forward-compatible consumer code."],"claims":[{"id":"storage:runtime:list","kind":"runtime-export","surface":"storage","behavior":"Paginated listing is deferred — listAll covers the v1 scope; pagination needs a stable pageToken shape, which is unbuilt design work rather than a sandbox limitation.","status":"deferred","evidence":["registry:storage#78"],"assurance":"not-applicable"},{"id":"storage#78","kind":"registry-row","surface":"storage","behavior":"Exported by `firebase/storage`; accepts `{ maxResults, pageToken }`, returns a `ListResult` with `nextPageToken` set when more pages remain","status":"unsupported","evidence":["No paginated `list` implementation or behavioral probe exists; availability is classified by the owning surface contract. `ListResult.nextPageToken` remains optional for forward-compatible consumer code."],"assurance":"ineligible"}]},{"feature":"list.concat","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"list.concat is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.list.concat","kind":"rules-construct","surface":"firestore-rules","behavior":"list.concat is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.List#function_concat_"],"assurance":"eligible"}]},{"feature":"list.hasAll","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"list.hasAll is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.list.hasAll","kind":"rules-construct","surface":"firestore-rules","behavior":"list.hasAll is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.List#function_hasAll_"],"assurance":"eligible"}]},{"feature":"list.hasAny","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"list.hasAny is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.list.hasAny","kind":"rules-construct","surface":"firestore-rules","behavior":"list.hasAny is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.List#function_hasAny_"],"assurance":"eligible"}]},{"feature":"list.hasOnly","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"list.hasOnly is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.list.hasOnly","kind":"rules-construct","surface":"firestore-rules","behavior":"list.hasOnly is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.List#function_hasOnly_"],"assurance":"eligible"}]},{"feature":"list.join","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"list.join is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.list.join","kind":"rules-construct","surface":"firestore-rules","behavior":"list.join is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.List#function_join_"],"assurance":"eligible"}]},{"feature":"list.removeAll","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"list.removeAll is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.list.removeAll","kind":"rules-construct","surface":"firestore-rules","behavior":"list.removeAll is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.List#function_removeAll_"],"assurance":"eligible"}]},{"feature":"list.size","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"list.size is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.list.size","kind":"rules-construct","surface":"firestore-rules","behavior":"list.size is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.List#function_size_"],"assurance":"eligible"}]},{"feature":"list.toSet","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"list.toSet is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.list.toSet","kind":"rules-construct","surface":"firestore-rules","behavior":"list.toSet is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.List#function_toSet_"],"assurance":"eligible"}]},{"feature":"listAll","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"listAll is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage:runtime:listAll","kind":"runtime-export","surface":"storage","behavior":"listAll is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"storage#68","kind":"registry-row","surface":"storage","behavior":"Returns `ListResult` with `items` (direct child files) + `prefixes` (sub-folder refs) + `nextPageToken: undefined`","status":"conforms","evidence":["`unit:list.test.ts`","packages/pyric/test/storage/list.test.ts"],"assurance":"eligible"},{"id":"storage#69","kind":"registry-row","surface":"storage","behavior":"Empty bucket → both arrays empty, `nextPageToken: undefined`","status":"conforms","evidence":["`unit:list.test.ts` (\"returns empty arrays on an empty bucket\")","packages/pyric/test/storage/list.test.ts"],"assurance":"eligible"},{"id":"storage#70","kind":"registry-row","surface":"storage","behavior":"Direct children only — does NOT recurse into grandchildren as items","status":"conforms","evidence":["`unit:list.test.ts` (\"does not recurse into grandchildren as items\")","packages/pyric/test/storage/list.test.ts"],"assurance":"eligible"},{"id":"storage#71","kind":"registry-row","surface":"storage","behavior":"Sub-folders surface as `prefixes` and are deduplicated (many files under one folder → ONE prefix entry)","status":"conforms","evidence":["`unit:list.test.ts` (\"promotes sub-folders into prefixes (deduplicated)\")","packages/pyric/test/storage/list.test.ts"],"assurance":"eligible"},{"id":"storage#72","kind":"registry-row","surface":"storage","behavior":"`items` sorted by path (IDB key order, lexicographic)","status":"conforms","evidence":["`unit:list.test.ts` (\"lists direct children of a folder\")","packages/pyric/test/storage/list.test.ts"],"assurance":"eligible"},{"id":"storage#73","kind":"registry-row","surface":"storage","behavior":"`prefixes` sorted lexicographically by `fullPath` (for determinism)","status":"conforms","evidence":["`unit:list.test.ts` (root-scan example asserts `configs` < `sessions`)","packages/pyric/test/storage/list.test.ts"],"assurance":"eligible"},{"id":"storage#74","kind":"registry-row","surface":"storage","behavior":"The scanned ref itself is NEVER included in `items` (even when an object exists at the exact prefix path)","status":"conforms","evidence":["`unit:list.test.ts` (\"does not include the scanned ref itself\")","packages/pyric/test/storage/list.test.ts"],"assurance":"eligible"},{"id":"storage#75","kind":"registry-row","surface":"storage","behavior":"`listAll(ref(storage))` (root) scans the entire bucket","status":"conforms","evidence":["`unit:list.test.ts` (\"listAll on the root scans the entire bucket\")","packages/pyric/test/storage/list.test.ts"],"assurance":"eligible"},{"id":"storage#76","kind":"registry-row","surface":"storage","behavior":"Items expose the full `StorageReference` shape (storage, bucket, name, parent)","status":"conforms","evidence":["`unit:list.test.ts` (\"items expose the StorageReference shape\")","packages/pyric/test/storage/list.test.ts"],"assurance":"eligible"},{"id":"storage#77","kind":"registry-row","surface":"storage","behavior":"Prod: items + prefixes shape matches sandbox after `N` uploads under a directory","status":"conforms","evidence":["oracle: `packages/conformance/observations/storage/storage-listall-shape.json` (against blockingfun, fb-js-sdk 12.13.0: 3 direct children + 1 grandchild → `items` has all 3 direct children sorted, `prefixes` has the single sub-folder, `itemCount: 3`, `prefixCount: 1`, `threeDirectChildren: true`, `oneSubPrefix: true`)","observation:storage-listall-shape"],"assurance":"eligible"},{"id":"storage#77a","kind":"registry-row","surface":"storage","behavior":"`listAll` enforces rules: `read` permission on the scanned prefix path governs list (Firebase: `read` covers download AND list), denied prefix → `storage/unauthorized`","status":"conforms","evidence":["ST-B2 fixed: `list.ts` now calls `enforceRules` with `method: 'read'` on the listed prefix (was a silent bypass — a denied tree was still fully enumerable). With no rules configured the check is a no-op. Probe: `unit:list-rules.test.ts` (\"denies an anonymous listAll of a tree the rules protect\" / \"allows an authed listAll\"). Note: a `read` rule scoped to `match /sessions/{id}` does NOT grant list on `/sessions` — the folder needs its own read rule, matching prod; the session-archive demo ruleset adds `match /sessions { allow read }`.","packages/pyric/test/storage/list-rules.test.ts"],"assurance":"eligible"}]},{"feature":"ListenOptions","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"ListenOptions is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"database:type:ListenOptions","kind":"type-export","surface":"database","behavior":"ListenOptions is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ListenSource","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"ListenSource is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:ListenSource","kind":"type-export","surface":"firestore","behavior":"ListenSource is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ListOptions","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"ListOptions is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"storage:type:ListOptions","kind":"type-export","surface":"storage","behavior":"ListOptions is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ListResult","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"ListResult is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"storage:type:ListResult","kind":"type-export","surface":"storage","behavior":"ListResult is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"LiveGenerationConfig","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"LiveGenerationConfig is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:LiveGenerationConfig","kind":"type-export","surface":"ai","behavior":"LiveGenerationConfig is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"LiveGenerativeModel","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"LiveGenerativeModel is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Live API is deferred, not out of scope — it is a bidirectional websocket protocol the sandbox can model with a scripted session engine, the same seam pattern the REST plane already uses; the work has not happened yet.","Public type export is not mirrored."],"claims":[{"id":"ai:runtime:LiveGenerativeModel","kind":"runtime-export","surface":"ai","behavior":"Live API is deferred, not out of scope — it is a bidirectional websocket protocol the sandbox can model with a scripted session engine, the same seam pattern the REST plane already uses; the work has not happened yet.","status":"deferred","evidence":["upstream:firebase/ai"],"assurance":"not-applicable"},{"id":"ai:type:LiveGenerativeModel","kind":"type-export","surface":"ai","behavior":"LiveGenerativeModel is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"LiveModelParams","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"LiveModelParams is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:LiveModelParams","kind":"type-export","surface":"ai","behavior":"LiveModelParams is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"LiveResponseType","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"LiveResponseType is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Live API is deferred, not out of scope — it is a bidirectional websocket protocol the sandbox can model with a scripted session engine, the same seam pattern the REST plane already uses; the work has not happened yet.","Public type export is not mirrored."],"claims":[{"id":"ai:runtime:LiveResponseType","kind":"runtime-export","surface":"ai","behavior":"Live API is deferred, not out of scope — it is a bidirectional websocket protocol the sandbox can model with a scripted session engine, the same seam pattern the REST plane already uses; the work has not happened yet.","status":"deferred","evidence":["upstream:firebase/ai"],"assurance":"not-applicable"},{"id":"ai:type:LiveResponseType","kind":"type-export","surface":"ai","behavior":"LiveResponseType is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"LiveServerContent","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"LiveServerContent is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:LiveServerContent","kind":"type-export","surface":"ai","behavior":"LiveServerContent is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"LiveServerGoingAwayNotice","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"LiveServerGoingAwayNotice is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:LiveServerGoingAwayNotice","kind":"type-export","surface":"ai","behavior":"LiveServerGoingAwayNotice is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"LiveServerToolCall","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"LiveServerToolCall is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:LiveServerToolCall","kind":"type-export","surface":"ai","behavior":"LiveServerToolCall is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"LiveServerToolCallCancellation","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"LiveServerToolCallCancellation is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:LiveServerToolCallCancellation","kind":"type-export","surface":"ai","behavior":"LiveServerToolCallCancellation is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"LiveSession","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"LiveSession is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Live API is deferred, not out of scope — it is a bidirectional websocket protocol the sandbox can model with a scripted session engine, the same seam pattern the REST plane already uses; the work has not happened yet.","Public type export is not mirrored."],"claims":[{"id":"ai:runtime:LiveSession","kind":"runtime-export","surface":"ai","behavior":"Live API is deferred, not out of scope — it is a bidirectional websocket protocol the sandbox can model with a scripted session engine, the same seam pattern the REST plane already uses; the work has not happened yet.","status":"deferred","evidence":["upstream:firebase/ai"],"assurance":"not-applicable"},{"id":"ai:type:LiveSession","kind":"type-export","surface":"ai","behavior":"LiveSession is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"LiveSessionResumptionUpdate","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"LiveSessionResumptionUpdate is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:LiveSessionResumptionUpdate","kind":"type-export","surface":"ai","behavior":"LiveSessionResumptionUpdate is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"loadBundle","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"loadBundle is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Bundle-loading depends on a protobuf packaging format not modeled in the sandbox yet — a data/parsing problem, not external infrastructure, so it is buildable rather than genuinely un-modelable."],"claims":[{"id":"firestore:runtime:loadBundle","kind":"runtime-export","surface":"firestore","behavior":"Bundle-loading depends on a protobuf packaging format not modeled in the sandbox yet — a data/parsing problem, not external infrastructure, so it is buildable rather than genuinely un-modelable.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"}]},{"feature":"LoadBundleTask","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"LoadBundleTask is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Bundle-loading depends on a protobuf packaging format not modeled in the sandbox yet — a data/parsing problem, not external infrastructure, so it is buildable rather than genuinely un-modelable.","Public type export is not mirrored."],"claims":[{"id":"firestore:runtime:LoadBundleTask","kind":"runtime-export","surface":"firestore","behavior":"Bundle-loading depends on a protobuf packaging format not modeled in the sandbox yet — a data/parsing problem, not external infrastructure, so it is buildable rather than genuinely un-modelable.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"},{"id":"firestore:type:LoadBundleTask","kind":"type-export","surface":"firestore","behavior":"LoadBundleTask is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"LoadBundleTaskProgress","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"LoadBundleTaskProgress is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:LoadBundleTaskProgress","kind":"type-export","surface":"firestore","behavior":"LoadBundleTaskProgress is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"LogLevel","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"LogLevel is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"firestore:type:LogLevel","kind":"type-export","surface":"firestore","behavior":"LogLevel is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"map.diff","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"map.diff is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.map.diff","kind":"rules-construct","surface":"firestore-rules","behavior":"map.diff is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.Map#function_diff_"],"assurance":"eligible"}]},{"feature":"Map.get","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"Map.get is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#169","kind":"registry-row","surface":"firestore-rules","behavior":"`Map.get(key, default)`, including list-form nested-path traversal (Item 3), in rules","status":"conforms","evidence":["`oracle:rules-firestore-map-get-string-and-list-form` — production Firestore Rules Test API verdicts for corpus scenario \"map-get-string-and-list-form\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`; all cases match production.","observation:rules-firestore-map-get-string-and-list-form","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"map.get","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"map.get is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.map.get","kind":"rules-construct","surface":"firestore-rules","behavior":"map.get is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.Map#function_get_"],"assurance":"eligible"}]},{"feature":"map.hasAll","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"diverged","assurance":"ineligible","summary":"map.hasAll is available, has diverged fidelity, and is ineligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.map.hasAll","kind":"rules-construct","surface":"firestore-rules","behavior":"map.hasAll is enumerated in the firestore rules-language inventory","status":"rejected","evidence":["https://firebase.google.com/docs/reference/rules/rules.Map#function_hasAll_","Error: firestore.rules line [5], column [22]. Function not found error: Name: [hasAll]."],"assurance":"ineligible"}]},{"feature":"map.hasAny","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"diverged","assurance":"ineligible","summary":"map.hasAny is available, has diverged fidelity, and is ineligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.map.hasAny","kind":"rules-construct","surface":"firestore-rules","behavior":"map.hasAny is enumerated in the firestore rules-language inventory","status":"rejected","evidence":["https://firebase.google.com/docs/reference/rules/rules.Map#function_hasAny_","Error: firestore.rules line [5], column [22]. Function not found error: Name: [hasAny]."],"assurance":"ineligible"}]},{"feature":"map.hasOnly","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"diverged","assurance":"ineligible","summary":"map.hasOnly is available, has diverged fidelity, and is ineligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.map.hasOnly","kind":"rules-construct","surface":"firestore-rules","behavior":"map.hasOnly is enumerated in the firestore rules-language inventory","status":"rejected","evidence":["https://firebase.google.com/docs/reference/rules/rules.Map#function_hasOnly_","Error: firestore.rules line [5], column [22]. Function not found error: Name: [hasOnly]."],"assurance":"ineligible"}]},{"feature":"map.keys","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"map.keys is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.map.keys","kind":"rules-construct","surface":"firestore-rules","behavior":"map.keys is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.Map#function_keys_"],"assurance":"eligible"}]},{"feature":"map.size","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"map.size is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.map.size","kind":"rules-construct","surface":"firestore-rules","behavior":"map.size is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.Map#function_size_"],"assurance":"eligible"}]},{"feature":"Map.values","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"Map.values is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#179","kind":"registry-row","surface":"firestore-rules","behavior":"`String.split()/lower()/upper()/trim()/replace()/size()`, `List.hasAll()/hasAny()/hasOnly()/join()`, and `Map.values()` in rules","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 4 cases (CSV-split membership, slug/title/code normalization). `oracle:rules-firestore-list-and-string-methods` — replayed by `unit:rules/oracle-conformance.test.ts`.","observation:rules-firestore-list-and-string-methods","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"map.values","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"map.values is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.map.values","kind":"rules-construct","surface":"firestore-rules","behavior":"map.values is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.Map#function_values_"],"assurance":"eligible"}]},{"feature":"mapdiff.addedKeys","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"mapdiff.addedKeys is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.mapdiff.addedKeys","kind":"rules-construct","surface":"firestore-rules","behavior":"mapdiff.addedKeys is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.MapDiff#function_addedKeys_"],"assurance":"eligible"}]},{"feature":"mapdiff.affectedKeys","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"mapdiff.affectedKeys is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.mapdiff.affectedKeys","kind":"rules-construct","surface":"firestore-rules","behavior":"mapdiff.affectedKeys is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.MapDiff#function_affectedKeys_"],"assurance":"eligible"}]},{"feature":"mapdiff.changedKeys","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"mapdiff.changedKeys is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.mapdiff.changedKeys","kind":"rules-construct","surface":"firestore-rules","behavior":"mapdiff.changedKeys is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.MapDiff#function_changedKeys_"],"assurance":"eligible"}]},{"feature":"mapdiff.removedKeys","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"mapdiff.removedKeys is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.mapdiff.removedKeys","kind":"rules-construct","surface":"firestore-rules","behavior":"mapdiff.removedKeys is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.MapDiff#function_removedKeys_"],"assurance":"eligible"}]},{"feature":"mapdiff.unchangedKeys","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"mapdiff.unchangedKeys is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.mapdiff.unchangedKeys","kind":"rules-construct","surface":"firestore-rules","behavior":"mapdiff.unchangedKeys is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.MapDiff#function_unchangedKeys_"],"assurance":"eligible"}]},{"feature":"mapMembership","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"mapMembership is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#172","kind":"registry-row","surface":"firestore-rules","behavior":"Own-keys-only map membership and constructor-access denial (RULES-B7) in rules — `'toString' in map` is `false`, `.constructor` access errors (no JS prototype-chain leakage)","status":"conforms","evidence":["`oracle:rules-firestore-prototype-chain-keys` — production Firestore Rules Test API verdicts for corpus scenario \"prototype-chain-keys\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`; all cases match production.","observation:rules-firestore-prototype-chain-keys","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"matches","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"matches is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#170","kind":"registry-row","surface":"firestore-rules","behavior":"`matches()` as an anchored full-string RE2 match (RULES-B4) in rules — a pattern matching only a substring is `false`","status":"conforms","evidence":["`oracle:rules-firestore-matches-full-string-regex` — production Firestore Rules Test API verdicts for corpus scenario \"matches-full-string-regex\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`; all cases match production.","observation:rules-firestore-matches-full-string-regex","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"firestore-rules#175","kind":"registry-row","surface":"firestore-rules","behavior":"String-literal escape handling feeding `matches()` (Class B) in rules — `\\\\.` is unescaped before RE2 compilation, not forwarded raw to a JS `RegExp`","status":"conforms","evidence":["`oracle:rules-firestore-string-literals-and-regex` — production Firestore Rules Test API verdicts for corpus scenario \"string-literals-and-regex\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`; all cases match production.","observation:rules-firestore-string-literals-and-regex","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"matches","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"matches is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"rtdb-rules#11","kind":"registry-row","surface":"rtdb-rules","behavior":"String methods on a snapshot value — `beginsWith`, `contains`, `endsWith`, `matches` with a regex literal, `.length`, `toLowerCase`, `toUpperCase`, and replace-ALL `replace`","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves `String.replace` substitutes EVERY occurrence of the substring, not only the first — production ALLOWS the write whose rule is `newData.val().replace('_', '-') === 'a-b-c'` for the value `a_b_c`, which holds only under replace-all. The simulator delegated to JavaScript's `String.prototype.replace`, which given a string pattern substitutes only the first occurrence, and DENIED that write; the substitution now replaces every occurrence and the two-underscore case guards the regression. The same capture proves `toUpperCase` is a valid production rule method that the simulator's validator previously rejected outright as unknown. `oracle:rules-rtdb-r11-string-validation` matches production verdict-for-verdict on all 18 cases.","observation:rules-rtdb-r11-string-validation","packages/pyric/test/rules/rtdb/rules-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"matches","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"matches is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#113","kind":"registry-row","surface":"storage-rules","behavior":"`string.matches(regex)` with whole-string anchoring (a partial match denies)","status":"conforms","evidence":["NEW ROW, 2026-07-10: production capture proves `matches()` is whole-string anchored, matching a RE2 pattern only when it covers the entire string. `oracle:rules-storage-matches-regex` matches production verdict-for-verdict on all 3 cases. RE2-inexpressible patterns are rejected at ruleset compile time by production and are covered by evaluator unit tests instead.","observation:rules-storage-matches-regex","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"math","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"math is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#160","kind":"registry-row","surface":"firestore-rules","behavior":"CEL builtins `math.*`/`timestamp.*`/`duration.*` (FM3) — arithmetic, date, and duration comparisons in rules","status":"conforms","evidence":["`oracle:rules-firestore-builtins-time-and-math` — production Firestore Rules Test API verdicts for corpus scenario \"builtins-time-and-math\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`; all cases match production.","observation:rules-firestore-builtins-time-and-math","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"firestore-rules#180","kind":"registry-row","surface":"firestore-rules","behavior":"`request.time` Timestamp accessors (year/month/day/hours/minutes/seconds/nanos/dayOfWeek/dayOfYear/toMillis/date/time), `math.floor/round/sqrt/pow/isNaN`, `int()/float()/string()` casts, `request.method`, and `>=` / `*` operators in rules","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 3 cases (request.time pinned via requestTime for determinism). `oracle:rules-firestore-time-math-and-casts` — replayed by `unit:rules/oracle-conformance.test.ts`.","observation:rules-firestore-time-math-and-casts","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"math.abs","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"math.abs is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.function.math.abs","kind":"rules-construct","surface":"firestore-rules","behavior":"math.abs is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.math#function_abs_"],"assurance":"eligible"}]},{"feature":"math.ceil","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"math.ceil is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.function.math.ceil","kind":"rules-construct","surface":"firestore-rules","behavior":"math.ceil is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.math#function_ceil_"],"assurance":"eligible"}]},{"feature":"math.floor","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"math.floor is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.function.math.floor","kind":"rules-construct","surface":"firestore-rules","behavior":"math.floor is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.math#function_floor_"],"assurance":"eligible"}]},{"feature":"math.isInfinite","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"diverged","assurance":"ineligible","summary":"math.isInfinite is available, has diverged fidelity, and is ineligible for assurance.","caveats":[],"claims":[{"id":"firestore.function.math.isInfinite","kind":"rules-construct","surface":"firestore-rules","behavior":"math.isInfinite is enumerated in the firestore rules-language inventory","status":"rejected","evidence":["https://firebase.google.com/docs/reference/rules/rules.math#function_isInfinite_","Error: firestore.rules line [5], column [22]. Function not found error: Name: [math.isInfinite]."],"assurance":"ineligible"}]},{"feature":"math.isNaN","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"math.isNaN is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.function.math.isNaN","kind":"rules-construct","surface":"firestore-rules","behavior":"math.isNaN is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.math#function_isNaN_"],"assurance":"eligible"}]},{"feature":"math.pow","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"math.pow is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.function.math.pow","kind":"rules-construct","surface":"firestore-rules","behavior":"math.pow is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.math#function_pow_"],"assurance":"eligible"}]},{"feature":"math.round","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"math.round is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.function.math.round","kind":"rules-construct","surface":"firestore-rules","behavior":"math.round is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.math#function_round_"],"assurance":"eligible"}]},{"feature":"math.sqrt","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"math.sqrt is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.function.math.sqrt","kind":"rules-construct","surface":"firestore-rules","behavior":"math.sqrt is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.math#function_sqrt_"],"assurance":"eligible"}]},{"feature":"MemoryCacheSettings","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"MemoryCacheSettings is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:MemoryCacheSettings","kind":"type-export","surface":"firestore","behavior":"MemoryCacheSettings is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"memoryEagerGarbageCollector","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"memoryEagerGarbageCollector is available, has diverged fidelity, and is qualified for assurance.","caveats":["Config token accepted, inert — each returns a small tagged object so identity/usage doesn't crash. Persistence is the sandbox default; there is no cache tier left to configure","`unit:firestore/tier1-cache-init-align.test.ts`"],"claims":[{"id":"firestore:runtime:memoryEagerGarbageCollector","kind":"runtime-export","surface":"firestore","behavior":"memoryEagerGarbageCollector is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#146","kind":"registry-row","surface":"firestore","behavior":"Config token accepted, inert — each returns a small tagged object so identity/usage doesn't crash. Persistence is the sandbox default; there is no cache tier left to configure","status":"diverged-documented","evidence":["`unit:firestore/tier1-cache-init-align.test.ts`","packages/pyric/test/firestore/tier1-cache-init-align.test.ts"],"assurance":"qualified"}]},{"feature":"MemoryEagerGarbageCollector","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"MemoryEagerGarbageCollector is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:MemoryEagerGarbageCollector","kind":"type-export","surface":"firestore","behavior":"MemoryEagerGarbageCollector is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"MemoryGarbageCollector","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"MemoryGarbageCollector is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"firestore:type:MemoryGarbageCollector","kind":"type-export","surface":"firestore","behavior":"MemoryGarbageCollector is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"memoryLocalCache","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"memoryLocalCache is available, has diverged fidelity, and is qualified for assurance.","caveats":["Config token accepted, inert — each returns a small tagged object so identity/usage doesn't crash. Persistence is the sandbox default; there is no cache tier left to configure","`unit:firestore/tier1-cache-init-align.test.ts`"],"claims":[{"id":"firestore:runtime:memoryLocalCache","kind":"runtime-export","surface":"firestore","behavior":"memoryLocalCache is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#146","kind":"registry-row","surface":"firestore","behavior":"Config token accepted, inert — each returns a small tagged object so identity/usage doesn't crash. Persistence is the sandbox default; there is no cache tier left to configure","status":"diverged-documented","evidence":["`unit:firestore/tier1-cache-init-align.test.ts`","packages/pyric/test/firestore/tier1-cache-init-align.test.ts"],"assurance":"qualified"}]},{"feature":"MemoryLocalCache","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"MemoryLocalCache is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:MemoryLocalCache","kind":"type-export","surface":"firestore","behavior":"MemoryLocalCache is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"memoryLruGarbageCollector","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"memoryLruGarbageCollector is available, has diverged fidelity, and is qualified for assurance.","caveats":["Config token accepted, inert — each returns a small tagged object so identity/usage doesn't crash. Persistence is the sandbox default; there is no cache tier left to configure","`unit:firestore/tier1-cache-init-align.test.ts`"],"claims":[{"id":"firestore:runtime:memoryLruGarbageCollector","kind":"runtime-export","surface":"firestore","behavior":"memoryLruGarbageCollector is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#146","kind":"registry-row","surface":"firestore","behavior":"Config token accepted, inert — each returns a small tagged object so identity/usage doesn't crash. Persistence is the sandbox default; there is no cache tier left to configure","status":"diverged-documented","evidence":["`unit:firestore/tier1-cache-init-align.test.ts`","packages/pyric/test/firestore/tier1-cache-init-align.test.ts"],"assurance":"qualified"}]},{"feature":"MemoryLruGarbageCollector","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"MemoryLruGarbageCollector is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:MemoryLruGarbageCollector","kind":"type-export","surface":"firestore","behavior":"MemoryLruGarbageCollector is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"Message","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"Message is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#10","kind":"registry-row","surface":"messaging-admin","behavior":"A send payload carrying exactly one of token, topic, or condition.","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `messaging-api`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"MessagePayload","surface":"messaging","importPaths":["pyric/messaging","pyric/messaging/sw"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"MessagePayload is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-sw:type:MessagePayload","kind":"type-export","surface":"messaging-sw","behavior":"MessagePayload is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"messaging:type:MessagePayload","kind":"type-export","surface":"messaging","behavior":"MessagePayload is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"messaging#10","kind":"registry-row","surface":"messaging","behavior":"WebpushFcmOptions-style options carried on a client `MessagePayload` (`link`, `analyticsLabel`).","status":"conforms","evidence":["Upstream typings (`@firebase/messaging` 0.12.26 `public-types`); no observation yet.","packages/pyric/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"messaging#9","kind":"registry-row","surface":"messaging","behavior":"Display-notification block inside a `MessagePayload`. Production foreground deliveries carry a `notification` object whose keys include `title` and `body`.","status":"conforms","evidence":["oracle: `messaging-web-onmessage-foreground.json` (notificationKeys body, title). Replayed by the conformance suite.","observation:messaging-web-onmessage-foreground","packages/pyric/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"Messaging","surface":"messaging","importPaths":["pyric/messaging","pyric/messaging/sw"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"Messaging is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-sw:type:Messaging","kind":"type-export","surface":"messaging-sw","behavior":"Messaging is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"messaging:type:Messaging","kind":"type-export","surface":"messaging","behavior":"Messaging is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"messaging#1","kind":"registry-row","surface":"messaging","behavior":"Returns the FCM `Messaging` instance associated with the given (or default) `FirebaseApp`. Bound to the client component registered under the name `messaging`.","status":"conforms","evidence":["Upstream typings/JSDoc (firebase 12.13.0, `@firebase/messaging` 0.12.26); in-process mirror suite plus canonical-import SharedWorker replay `messaging-app-boundary.pw.ts`.","packages/pyric/test/messaging/oracle-conformance.test.ts","packages/cli/test/e2e/messaging-app-boundary.pw.ts"],"assurance":"eligible"},{"id":"messaging#13","kind":"registry-row","surface":"messaging","behavior":"Returns the FCM instance within a service-worker context (bound to `getMessagingInSw`); registers under the component name `messaging-sw`.","status":"conforms","evidence":["Upstream typings (`@firebase/messaging` 0.12.26 `sw/index-public`) plus real module-ServiceWorker served-entry replay `messaging-app-boundary.pw.ts`.","packages/pyric/test/messaging/oracle-conformance.test.ts","packages/cli/test/e2e/messaging-app-boundary.pw.ts"],"assurance":"eligible"},{"id":"messaging#17","kind":"registry-row","surface":"messaging","behavior":"The sw entry exports `onBackgroundMessage`, `getMessaging`, `experimentalSetDeliveryMetricsExportedToBigQueryEnabled`, and `isSupported`, but NOT `getToken` / `deleteToken` / `onMessage`; the client entry exports the latter but NOT `onBackgroundMessage` / the metrics toggle. The two modules register under different component names (`messaging` vs `messaging-sw`) and re-export identical `Messaging` / `GetTokenOptions` / `MessagePayload` / `NotificationPayload` / `FcmOptions` type declarations.","status":"conforms","evidence":["Upstream typings (`@firebase/messaging` 0.12.26 `index.d.ts` / `index.sw.d.ts`) plus Window and real module-ServiceWorker boundary replay `messaging-app-boundary.pw.ts`.","packages/pyric/test/messaging/oracle-conformance.test.ts","packages/cli/test/e2e/messaging-app-boundary.pw.ts"],"assurance":"eligible"},{"id":"messaging#6","kind":"registry-row","surface":"messaging","behavior":"Public interface of the FCM client SDK; exposes the bound `FirebaseApp` as `app`.","status":"conforms","evidence":["Upstream typings (`@firebase/messaging` 0.12.26 `public-types`); no observation yet.","packages/pyric/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"Messaging","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"Messaging is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#1","kind":"registry-row","surface":"messaging-admin","behavior":"Returns the `Messaging` service for the default or given admin `App`.","status":"conforms","evidence":["Upstream typings/JSDoc (firebase-admin 13.10.0 `lib/messaging/index`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"messaging-admin#3","kind":"registry-row","surface":"messaging-admin","behavior":"The admin `App` this `Messaging` instance is bound to.","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `messaging`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"messaging-admin#4","kind":"registry-row","surface":"messaging-admin","behavior":"Sends one message via FCM v1 and resolves with the resource name `projects/<projectId>/messages/<numeric id>`. `dryRun=true` returns the SAME shape (fake id), so callers cannot distinguish validation from acceptance by shape. Topic, condition, token, notification-only, data-only, and webpush-config sends are all accepted. Malformed sends fail server-side validation with HTTP 4xx `google.rpc` error envelopes carrying both a `google.rpc.BadRequest` (fieldViolations) and a `google.firebase.fcm.v1.FcmError` (errorCode); detail ordering is not contractual. The documented data-payload cap is 4096 bytes.","status":"conforms","evidence":["oracle: 10 send-plane observations — accept paths `messaging-send-topic-accepted`, `messaging-send-condition-accepted`, `messaging-send-notification-only-vs-data-only-accepted`, `messaging-send-webpush-config-accepted`; error envelopes `messaging-send-no-target-error-envelope`, `messaging-send-invalid-token-error-envelope`, `messaging-send-invalid-condition-error-envelope`, `messaging-send-invalid-topic-name-error-envelope`, `messaging-send-oversized-payload-error-envelope`, `messaging-send-webpush-invalid-ttl-error-envelope`. Replayed by the conformance suite.","observation:messaging-send-topic-accepted","observation:messaging-send-condition-accepted","observation:messaging-send-notification-only-vs-data-only-accepted","observation:messaging-send-webpush-config-accepted","observation:messaging-send-no-target-error-envelope","observation:messaging-send-invalid-token-error-envelope","observation:messaging-send-invalid-condition-error-envelope","observation:messaging-send-invalid-topic-name-error-envelope","observation:messaging-send-oversized-payload-error-envelope","observation:messaging-send-webpush-invalid-ttl-error-envelope","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"messaging-admin#5","kind":"registry-row","surface":"messaging-admin","behavior":"Sends an array of up to 500 messages, one RPC per message; resolves a `BatchResponse` whose `responses` are ordered to match the input. Total failure is signalled by a throw or an all-failure `BatchResponse`.","status":"conforms","evidence":["Upstream typings/JSDoc (firebase-admin 13.10.0 `messaging`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"messaging-admin#7","kind":"registry-row","surface":"messaging-admin","behavior":"Subscribes one or many registration tokens to a topic; resolves a `MessagingTopicManagementResponse`.","status":"conforms","evidence":["Upstream typings/JSDoc (firebase-admin 13.10.0 `messaging`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"messaging-admin#8","kind":"registry-row","surface":"messaging-admin","behavior":"Unsubscribes one or many registration tokens from a topic; resolves a `MessagingTopicManagementResponse`.","status":"conforms","evidence":["Upstream typings/JSDoc (firebase-admin 13.10.0 `messaging`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"messaging","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"messaging is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#2","kind":"registry-row","surface":"messaging-admin","behavior":"Namespaced / legacy accessor equivalent of `getMessaging`, exposed by the compat entry alongside the `namespace messaging` type aliases.","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `messaging-namespace`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"MessagingClientErrorCode","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"MessagingClientErrorCode is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#39","kind":"registry-row","surface":"messaging-admin","behavior":"Exported static `{ code, message }` members (`INVALID_ARGUMENT`, `INVALID_RECIPIENT`, `INVALID_PAYLOAD`, … `UNKNOWN_ERROR`). The wire-level `INVALID_ARGUMENT` FcmError returned by malformed sends maps to `MessagingClientErrorCode.INVALID_ARGUMENT`.","status":"conforms","evidence":["oracle: `messaging-send-no-target-error-envelope.json` + `messaging-send-invalid-token-error-envelope.json` (both carry the INVALID_ARGUMENT FcmError). Replayed by the conformance suite.","observation:messaging-send-no-target-error-envelope","observation:messaging-send-invalid-token-error-envelope","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"MessagingOptions","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"MessagingOptions is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#34","kind":"registry-row","surface":"messaging-admin","behavior":"Legacy send options; documented defaults are dryRun false, ttl 2419200s (4 weeks), priority high for notifications / normal for data.","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `messaging-api`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"MessagingPayload","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"MessagingPayload is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#33","kind":"registry-row","surface":"messaging-admin","behavior":"Legacy combined payload — one or both of `data` / `notification` required.","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `messaging-api`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"MessagingTopicManagementResponse","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"MessagingTopicManagementResponse is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#35","kind":"registry-row","surface":"messaging-admin","behavior":"Topic subscribe / unsubscribe result carrying per-index errors as `FirebaseArrayIndexError[]`.","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `messaging-api`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"missingFieldAccess","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"missingFieldAccess is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#176","kind":"registry-row","surface":"firestore-rules","behavior":"Missing-field access as a runtime error (RULES-B2) in rules — `typo == null` denies (missing access is not null); `!(key in map)` is the real absence check","status":"conforms","evidence":["`oracle:rules-firestore-undefined-field-access` — production Firestore Rules Test API verdicts for corpus scenario \"undefined-field-access\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`; all cases match production.","observation:rules-firestore-undefined-field-access","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"Modality","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"Modality is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:Modality","kind":"runtime-export","surface":"ai","behavior":"Modality is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:Modality","kind":"type-export","surface":"ai","behavior":"Modality is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ModalityTokenCount","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"ModalityTokenCount is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:ModalityTokenCount","kind":"type-export","surface":"ai","behavior":"ModalityTokenCount is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ModelParams","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"ModelParams is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:ModelParams","kind":"type-export","surface":"ai","behavior":"ModelParams is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"multiFactor","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"multiFactor is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["MFA / phone / reCAPTCHA is deferred, not out of scope — reCAPTCHA/SMS are external infrastructure Pyric can mock with the OAuth resolver pattern, and TOTP is pure algorithm work."],"claims":[{"id":"auth:runtime:multiFactor","kind":"runtime-export","surface":"auth","behavior":"MFA / phone / reCAPTCHA is deferred, not out of scope — reCAPTCHA/SMS are external infrastructure Pyric can mock with the OAuth resolver pattern, and TOTP is pure algorithm work.","status":"deferred","evidence":["registry:auth#180"],"assurance":"not-applicable"}]},{"feature":"MultiFactorAssertion","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"MultiFactorAssertion is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:MultiFactorAssertion","kind":"type-export","surface":"auth","behavior":"MultiFactorAssertion is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"MultiFactorError","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"MultiFactorError is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:MultiFactorError","kind":"type-export","surface":"auth","behavior":"MultiFactorError is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"MultiFactorInfo","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"MultiFactorInfo is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:MultiFactorInfo","kind":"type-export","surface":"auth","behavior":"MultiFactorInfo is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"MultiFactorResolver","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"MultiFactorResolver is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:MultiFactorResolver","kind":"type-export","surface":"auth","behavior":"MultiFactorResolver is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"MultiFactorSession","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"MultiFactorSession is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:MultiFactorSession","kind":"type-export","surface":"auth","behavior":"MultiFactorSession is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"MultiFactorUser","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"MultiFactorUser is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:MultiFactorUser","kind":"type-export","surface":"auth","behavior":"MultiFactorUser is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"namedQuery","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"namedQuery is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Bundle-loading depends on a protobuf packaging format not modeled in the sandbox yet — a data/parsing problem, not external infrastructure, so it is buildable rather than genuinely un-modelable."],"claims":[{"id":"firestore:runtime:namedQuery","kind":"runtime-export","surface":"firestore","behavior":"Bundle-loading depends on a protobuf packaging format not modeled in the sandbox yet — a data/parsing problem, not external infrastructure, so it is buildable rather than genuinely un-modelable.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"}]},{"feature":"NestedUpdateFields","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"NestedUpdateFields is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:NestedUpdateFields","kind":"type-export","surface":"firestore","behavior":"NestedUpdateFields is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"newData","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"newData is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.binding.newData","kind":"rules-construct","surface":"rtdb-rules","behavior":"newData is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/rules#newData"],"assurance":"qualified"}]},{"feature":"NextFn","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"NextFn is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:NextFn","kind":"type-export","surface":"auth","behavior":"NextFn is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"NextFn","surface":"messaging","importPaths":["pyric/messaging","pyric/messaging/sw"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"NextFn is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"messaging-sw:type:NextFn","kind":"type-export","surface":"messaging-sw","behavior":"NextFn is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"messaging:type:NextFn","kind":"type-export","surface":"messaging","behavior":"NextFn is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"NextOrObserver","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"NextOrObserver is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:NextOrObserver","kind":"type-export","surface":"auth","behavior":"NextOrObserver is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"Notification","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"Notification is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#16","kind":"registry-row","surface":"messaging-admin","behavior":"Top-level, platform-independent notification block. Production accepts a notification-only message (no data block).","status":"conforms","evidence":["oracle: `messaging-send-notification-only-vs-data-only-accepted.json`. Replayed by the conformance suite.","observation:messaging-send-notification-only-vs-data-only-accepted","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"messaging-admin#20","kind":"registry-row","surface":"messaging-admin","behavior":"Web Notification API-shaped options, including an open-ended index signature.","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `messaging-api`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"NotificationMessagePayload","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"NotificationMessagePayload is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#32","kind":"registry-row","surface":"messaging-admin","behavior":"Legacy notification payload with localization keys, a `clickAction`, and arbitrary string keys.","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `messaging-api`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"NotificationPayload","surface":"messaging","importPaths":["pyric/messaging","pyric/messaging/sw"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"NotificationPayload is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"messaging-sw:type:NotificationPayload","kind":"type-export","surface":"messaging-sw","behavior":"NotificationPayload is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"messaging:type:NotificationPayload","kind":"type-export","surface":"messaging","behavior":"NotificationPayload is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"now","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"now is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb-rules#12","kind":"registry-row","surface":"rtdb-rules","behavior":"`now` (the server evaluation clock) and `auth.token` claims, read both dotted (`auth.token.firebase.sign_in_provider`) and subscripted (`auth.token['firebase']['sign_in_provider']`)","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator resolves the server clock and the decoded ID-token claims as production does, through both access forms. The subscript's receiver is load-bearing: production's rules compiler ACCEPTS `auth.token[...]`, a map indexed by key, but REJECTS the same subscript applied to a snapshot value — `newData.val()['kind']` fails to compile with \"No such method/property\" — so `[]` is a map accessor, not a general indexing operator. `oracle:rules-rtdb-r12-server-time-and-token` matches production verdict-for-verdict on all 7 cases.","observation:rules-rtdb-r12-server-time-and-token","packages/pyric/test/rules/rtdb/rules-conformance.test.ts"],"assurance":"eligible"},{"id":"rtdb.binding.now","kind":"rules-construct","surface":"rtdb-rules","behavior":"now is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/rules#now"],"assurance":"qualified"}]},{"feature":"NumberSchema","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"NumberSchema is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:NumberSchema","kind":"runtime-export","surface":"ai","behavior":"NumberSchema is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:NumberSchema","kind":"type-export","surface":"ai","behavior":"NumberSchema is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"OAuthCredential","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"OAuthCredential is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:OAuthCredential","kind":"runtime-export","surface":"auth","behavior":"OAuthCredential is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth:type:OAuthCredential","kind":"type-export","surface":"auth","behavior":"OAuthCredential is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#180","kind":"registry-row","surface":"auth","behavior":"Real classes, not markers. `EmailAuthProvider.credential(email, password)` returns an `EmailAuthCredential` that CARRIES THE SECRET — which is what makes `linkWithCredential`, `reauthenticateWithCredential`, and `signInWithCredential` decidable in the sandbox with no resolver and no mock (the backend already stores and verifies passwords). `credentialWithLink` carries the link instead, and `signInMethod` discriminates (`'password'` vs `'emailLink'`). The backing secret is non-enumerable, so a spread or `Object.keys` walk does not pick it up; `toJSON()` DOES carry it, matching upstream (whose `fromJSON` needs it to round-trip). `OAuthCredential` carries the IdP tokens, which the sandbox cannot verify — those flows keep going through the resolver seam.","status":"conforms","evidence":["`unit:sandbox-linking-reauth.test.ts` — pins the secret-carrying behavior, the enumerable/toJSON split (so nobody 'hardens' it into a divergence later), and that a real email credential now signs in via `signInWithCredential` instead of throwing the sandbox-only `auth/no-mock-configured` it used to.","packages/pyric/test/auth/sandbox-linking-reauth.test.ts"],"assurance":"eligible"}]},{"feature":"OAuthCredentialOptions","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"OAuthCredentialOptions is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:OAuthCredentialOptions","kind":"type-export","surface":"auth","behavior":"OAuthCredentialOptions is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"OAuthProvider","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"OAuthProvider is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"auth:runtime:OAuthProvider","kind":"runtime-export","surface":"auth","behavior":"OAuthProvider is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth:type:OAuthProvider","kind":"type-export","surface":"auth","behavior":"OAuthProvider is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ObjectSchema","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"ObjectSchema is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:ObjectSchema","kind":"runtime-export","surface":"ai","behavior":"ObjectSchema is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:ObjectSchema","kind":"type-export","surface":"ai","behavior":"ObjectSchema is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ObjectSchemaRequest","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"ObjectSchemaRequest is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:ObjectSchemaRequest","kind":"type-export","surface":"ai","behavior":"ObjectSchemaRequest is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"Observer","surface":"messaging","importPaths":["pyric/messaging","pyric/messaging/sw"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"Observer is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"messaging-sw:type:Observer","kind":"type-export","surface":"messaging-sw","behavior":"Observer is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"messaging:type:Observer","kind":"type-export","surface":"messaging","behavior":"Observer is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"off","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"off is available, has unverified fidelity, and is qualified for assurance.","caveats":["When the same callback is registered more than once, each `off(ref, eventType, callback)` removes one registration without orphaning the others","Pyric behavior is locked by `packages/pyric/test/app/multi-app-listener-auth.test.ts`; a production duplicate-registration oracle capture is still needed"],"claims":[{"id":"database:runtime:off","kind":"runtime-export","surface":"database","behavior":"off is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#138","kind":"registry-row","surface":"rtdb-modular","behavior":"`off(ref)` removes ALL listeners at that ref (any event type, any callback)","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-off-stops-child-fires.json` — after `off(ref)` with no eventType, a subsequent write produced `postOffFires: 0` against an `onChildAdded` registration.","observation:rtdb-modular-off-stops-child-fires"],"assurance":"eligible"},{"id":"rtdb-modular#139","kind":"registry-row","surface":"rtdb-modular","behavior":"`off(ref, 'value')` removes only `value` listeners at that ref","status":"conforms","evidence":["Sandbox aligned (M48); oracle: `packages/conformance/observations/rtdb/rtdb-off-eventtype-precision.json` — registered TWO `value` listeners + one `child_added` at the same ref; after `off(ref, 'value')` (no callback), `valueListenersStopped: true` (neither value cb fired on subsequent writes) AND `childListenerStillFiringAfterOffValue: true` (the child listener kept firing). `offValueClearsAllValueListeners: true` confirms the no-callback variant removes ALL value listeners at the ref.","observation:rtdb-modular-off-stops-child-fires","observation:rtdb-off-eventtype-precision"],"assurance":"eligible"},{"id":"rtdb-modular#140","kind":"registry-row","surface":"rtdb-modular","behavior":"`off(ref, 'value', cb)` removes only the specific callback","status":"conforms","evidence":["Sandbox aligned (M48); adjacent to #141 — the upstream `off` with the cb argument removes only the matching callback. Same probe (`rtdb-onvalue-unsub-equivalence.json` Case 2) confirms `off(ref, 'value', cb)` stops only that callback."],"assurance":"eligible"},{"id":"rtdb-modular#141","kind":"registry-row","surface":"rtdb-modular","behavior":"The returned unsubscribe function from `onValue(ref, cb)` is equivalent to `off(ref, 'value', cb)`","status":"conforms","evidence":["Sandbox aligned (M48); oracle: `packages/conformance/observations/rtdb/rtdb-onvalue-unsub-equivalence.json` — `unsubReturnType: 'function'`, `unsubReturnedFnStopsListener: true` (the captured return value halted fires on write), `offRefValueCbStopsListener: true` (the same effect via `off(ref, 'value', cb)`), `bothFormsEquivalent: true`.","observation:rtdb-onvalue-unsub-equivalence"],"assurance":"eligible"},{"id":"rtdb-modular#183","kind":"registry-row","surface":"rtdb-modular","behavior":"When the same callback is registered more than once, each `off(ref, eventType, callback)` removes one registration without orphaning the others","status":"unverified","evidence":["Pyric behavior is locked by `packages/pyric/test/app/multi-app-listener-auth.test.ts`; a production duplicate-registration oracle capture is still needed"],"assurance":"qualified"},{"id":"rtdb-modular#M47","kind":"registry-row","surface":"rtdb-modular","behavior":"`off(ref)` (no event type) removes ALL listeners at that ref — value + every child event variety","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-child-events.test.ts` (\"off(ref) removes ALL listeners at the ref\" + \"off(ref) also removes value listeners at the same path\"); matches oracle observation `packages/conformance/observations/rtdb-modular/rtdb-modular-off-stops-child-fires.json` (`postOffFires: 0`).","observation:rtdb-modular-off-stops-child-fires","packages/pyric/test/database/modular/sandbox-child-events.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M48","kind":"registry-row","surface":"rtdb-modular","behavior":"`off(ref, eventType?, callback?)` variants: `off(ref, 'value')` / `off(ref, 'child_added')` / `off(ref, eventType, cb)` remove the targeted subset; returned-unsubscribe from `onChild*` is equivalent to `off(ref, eventType, cb)`","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-child-events.test.ts` (\"off(ref, \\\"child_added\\\") removes only that event variety\" + \"off(ref, \\\"value\\\") removes only value listeners\" + \"off(ref, eventType, cb) removes only the matching callback\" + \"returned-unsubscribe from onChildAdded is functionally equivalent to off()\").","packages/pyric/test/database/modular/sandbox-child-events.test.ts"],"assurance":"eligible"}]},{"feature":"onAuthStateChanged","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"onAuthStateChanged is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:onAuthStateChanged","kind":"runtime-export","surface":"auth","behavior":"onAuthStateChanged is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#29","kind":"registry-row","surface":"auth","behavior":"Fires immediately on subscribe with the current value (microtask-deferred)","status":"conforms","evidence":["`unit:sandbox-listeners.test.ts` + oracle: `packages/conformance/observations/auth/auth-row-29-onauthstatechanged-initial-fire-timing.json` (`firedSynchronously: 0, firedAfterMicrotask: 1` against blockingfun, fb-js-sdk 12.13.0 — initial fire does NOT arrive in the synchronous tick of `onAuthStateChanged(...)`; it lands after the first microtask flush)","observation:auth-row-29-onauthstatechanged-initial-fire-timing","packages/pyric/test/auth/sandbox-listeners.test.ts"],"assurance":"eligible"},{"id":"auth#30","kind":"registry-row","surface":"auth","behavior":"Fires on every subsequent identity change","status":"conforms","evidence":["`unit:sandbox-listeners.test.ts`, `playground:auth-anonymous` + oracle: `packages/conformance/observations/auth/auth-row-30-onauthstatechanged-fires-on-every-transition.json` (against blockingfun, fb-js-sdk 12.13.0: subscribe → `signIn` → `signOut` → `signIn` → `signOut`, each of the 4 transitions produced exactly 1 fire; `eachTransitionFiredExactlyOnce: true`)","observation:auth-row-30-onauthstatechanged-fires-on-every-transition","packages/pyric/test/auth/sandbox-listeners.test.ts"],"assurance":"eligible"},{"id":"auth#30a","kind":"registry-row","surface":"auth","behavior":"Dedups by uid: a same-uid update (profile-shape change, or a same-uid re-sign-in) does NOT re-fire `onAuthStateChanged` — only an actual uid change does. Mirrors upstream `notifyAuthListeners`'s `lastNotifiedUid` gate (`auth_impl.ts:718-723`). (`onIdTokenChanged` still fires on those same-uid updates — see row 38a.)","status":"conforms","evidence":["`unit:sandbox-uid-dedup.test.ts` (locks AUTH-B7 / B8)","packages/pyric/test/auth/sandbox-uid-dedup.test.ts"],"assurance":"eligible"},{"id":"auth#31","kind":"registry-row","surface":"auth","behavior":"**No duplicate fire** when subscribe is followed by a synchronous `setCurrentUser` — dedup ensures observer sees the new value once, not twice. Sandbox-only concern: prod has no synchronous state-change API, so the dedup window can't be exercised against the cloud SDK; subscribe-then-async-signIn naturally fires twice (initial + new value) because the microtask between them flushes the initial fire","status":"conforms","evidence":["`unit:sandbox-listeners.test.ts` (regression test from #399), `playground:auth-anonymous` + oracle baseline: `packages/conformance/observations/auth/auth-row-31-onauthstatechanged-no-dup-on-sync-transition.json` (against blockingfun, fb-js-sdk 12.13.0: subscribe + async `signInAnonymously` in the same tick produces `totalFires: 2` — `{uid: null, ts: 0}` then `{uid: <user>, ts: ~400ms}`. Confirms prod cannot exhibit the same-tick race; the dedup behavior remains a sandbox-only property)","observation:auth-row-31-onauthstatechanged-no-dup-on-sync-transition","packages/pyric/test/auth/sandbox-listeners.test.ts"],"assurance":"eligible"},{"id":"auth#32","kind":"registry-row","surface":"auth","behavior":"Returned `Unsubscribe` removes the observer; subsequent state changes do NOT fire it","status":"conforms","evidence":["`unit:sandbox-listeners.test.ts`, `playground:auth-listener-unsub` (bundled) + `playground:auth-row-32-unsubscribe-stops-fires` (one-claim) + oracle: `packages/conformance/observations/auth/auth-row-32-unsubscribe-stops-fires.json` (against blockingfun, fb-js-sdk 12.13.0: subscribe → 1 fire on `signInAnonymously` → call `unsub()` → `signOut` + `signInAnonymously` + `signOut` produce zero further fires; `postUnsubFires: 0, unsubscribeStoppedFires: true`)","observation:auth-row-32-unsubscribe-stops-fires","packages/pyric/test/auth/sandbox-listeners.test.ts"],"assurance":"eligible"},{"id":"auth#33","kind":"registry-row","surface":"auth","behavior":"Multiple subscribers all fire on each change","status":"conforms","evidence":["`unit:sandbox-listeners.test.ts` + oracle: `packages/conformance/observations/auth/auth-row-33-multiple-subscribers-all-fire.json` (against blockingfun, fb-js-sdk 12.13.0: two subscribers registered back-to-back each see 1 initial null fire, +1 on `signInAnonymously`, +1 on `signOut`; `bothFiredOnSignIn: true, bothFiredOnSignOut: true`)","observation:auth-row-33-multiple-subscribers-all-fire","packages/pyric/test/auth/sandbox-listeners.test.ts"],"assurance":"eligible"},{"id":"auth#33a","kind":"registry-row","surface":"auth","behavior":"Registry is array-backed (matches upstream `util/subscribe.ts`): the SAME observer fn registered N times produces N independent registrations that each fire, and one `Unsubscribe` removes exactly one registration. A resubscribe of a previously-unsubscribed fn fires its initial value again. (Per-registration initial-fire bookkeeping, not a shared per-observer dedup.)","status":"conforms","evidence":["`unit:sandbox-listener-registry.test.ts` (locks AUTH-B3 + AUTH-B4)","packages/pyric/test/auth/sandbox-listener-registry.test.ts"],"assurance":"eligible"},{"id":"auth#34","kind":"registry-row","surface":"auth","behavior":"Unsubscribing during emission does not skip remaining subscribers (snapshotted iteration)","status":"conforms","evidence":["`unit:sandbox-listeners.test.ts`","packages/pyric/test/auth/sandbox-listeners.test.ts"],"assurance":"eligible"},{"id":"auth#35","kind":"registry-row","surface":"auth","behavior":"A throwing observer doesn't block other observers from firing","status":"conforms","evidence":["`unit:sandbox-listeners.test.ts` + oracle: `packages/conformance/observations/auth/auth-row-35-throwing-observer-doesnt-block-others.json` (`secondObserverContinuedFiring: true` against blockingfun, fb-js-sdk 12.13.0 — observer #1 throws on every call, observer #2 still counts the initial fire AND the post-sign-in fire)","observation:auth-row-35-throwing-observer-doesnt-block-others","packages/pyric/test/auth/sandbox-listeners.test.ts"],"assurance":"eligible"},{"id":"auth#36","kind":"registry-row","surface":"auth","behavior":"Observer object form (`{next, error, complete}`) works alongside the function form","status":"conforms","evidence":["`unit:sandbox-listeners.test.ts` + oracle: `packages/conformance/observations/auth/auth-row-36-observer-object-form-works.json` (against blockingfun, fb-js-sdk 12.13.0: one observer as `NextFn`, another as `{next, error, complete}`. Both forms see 1 initial null fire, +1 on `signInAnonymously`, +1 on `signOut`; `bothFormsFiredOnSignIn: true, bothFormsFiredOnSignOut: true`)","observation:auth-row-36-observer-object-form-works","packages/pyric/test/auth/sandbox-listeners.test.ts"],"assurance":"eligible"},{"id":"auth#37","kind":"registry-row","surface":"auth","behavior":"Setting the same user twice does NOT double-fire (structural-equality no-op). Sandbox-internal `setCurrentUser` claim; the prod analog is `signInAnonymously` called twice in a row (per fix #399, the second call returns the same user).","status":"conforms","evidence":["`unit:sandbox-listeners.test.ts` + oracle: `packages/conformance/observations/auth/auth-row-37-same-user-no-double-fire.json` (against blockingfun, fb-js-sdk 12.13.0: first `signInAnonymously` fires the listener once; second call returns the same uid (`sameUserAcrossCalls: true`) and does NOT produce a fresh fire (`secondSignInProducedFire: false`). Prod also recognizes the same-user no-op)","observation:auth-row-37-same-user-no-double-fire","packages/pyric/test/auth/sandbox-listeners.test.ts"],"assurance":"eligible"}]},{"feature":"onBackgroundMessage","surface":"messaging","importPaths":["pyric/messaging/sw"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"onBackgroundMessage is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-sw:runtime:onBackgroundMessage","kind":"runtime-export","surface":"messaging-sw","behavior":"onBackgroundMessage is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"messaging#14","kind":"registry-row","surface":"messaging","behavior":"Called when a message arrives while the app has no visible window client. Production routes background deliveries here rather than to `onMessage`; the delivered payload carries `data` / `from` / `messageId` and, for notification messages, a `notification` block. A DATA-ONLY message still fires `onBackgroundMessage` with no `notification` key, and a registered handler suppresses the SDK auto-display.","status":"conforms","evidence":["oracle: `messaging-web-onbackgroundmessage.json` (no visible client → onBackgroundMessage) + `messaging-web-visibility-routing.json` + `messaging-web-data-only-background.json` (data-only fires, no notification key). Replayed by the conformance suite and by a real module Service Worker connected to the canonical SharedWorker broker in `messaging-app-boundary.pw.ts`.","observation:messaging-web-onbackgroundmessage","observation:messaging-web-visibility-routing","observation:messaging-web-data-only-background","packages/pyric/test/messaging/oracle-conformance.test.ts","packages/cli/test/e2e/messaging-app-boundary.pw.ts"],"assurance":"eligible"},{"id":"messaging#17","kind":"registry-row","surface":"messaging","behavior":"The sw entry exports `onBackgroundMessage`, `getMessaging`, `experimentalSetDeliveryMetricsExportedToBigQueryEnabled`, and `isSupported`, but NOT `getToken` / `deleteToken` / `onMessage`; the client entry exports the latter but NOT `onBackgroundMessage` / the metrics toggle. The two modules register under different component names (`messaging` vs `messaging-sw`) and re-export identical `Messaging` / `GetTokenOptions` / `MessagePayload` / `NotificationPayload` / `FcmOptions` type declarations.","status":"conforms","evidence":["Upstream typings (`@firebase/messaging` 0.12.26 `index.d.ts` / `index.sw.d.ts`) plus Window and real module-ServiceWorker boundary replay `messaging-app-boundary.pw.ts`.","packages/pyric/test/messaging/oracle-conformance.test.ts","packages/cli/test/e2e/messaging-app-boundary.pw.ts"],"assurance":"eligible"}]},{"feature":"onChildAdded","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"onChildAdded is available, has diverged fidelity, and is qualified for assurance.","caveats":["**Divergence (DB-B12, honest doc):** the onChild* callbacks do NOT receive the `previousChildName` second argument; `onValue`/`onChild*` do NOT accept a `cancelCallback`; `onChildAdded`/`Changed`/`Removed`/`Moved` accept only plain refs (not `Query`); `child_moved` never fires (ordered-query move detection unmodeled). These listener-surface holes are out of scope for the current phase — consumers needing them use `firebase/database` directly.","divergence documented; partial coverage: `{ onlyOnce }` IS implemented (M74)."],"claims":[{"id":"database:runtime:onChildAdded","kind":"runtime-export","surface":"database","behavior":"onChildAdded is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#133","kind":"registry-row","surface":"rtdb-modular","behavior":"`onChildAdded` replays the existing children on subscribe — one fire per existing child key, in `orderByKey` order by default (unlike `onValue` which fires once with the parent snapshot)","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-onchildadded-initial-replay.json` — seeded `{k1, k2, k3}`, observed 3 initial fires with `firedKeys: ['k1', 'k2', 'k3']` in insertion order against blockingfun.","observation:rtdb-modular-onchildadded-initial-replay"],"assurance":"eligible"},{"id":"rtdb-modular#134","kind":"registry-row","surface":"rtdb-modular","behavior":"After subscribe, adding a child via `push` or `set(child, …)` fires `onChildAdded` exactly once for that key","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-onchildadded-post-subscribe.json` — seeded `{k1,k2}`, observed `postSubscribeFires: 1, lastFire: {key:'k3', val:{v:3}}` after writing the new child.","observation:rtdb-modular-onchildadded-post-subscribe"],"assurance":"eligible"},{"id":"rtdb-modular#M31","kind":"registry-row","surface":"rtdb-modular","behavior":"`onChildAdded` / `onChildChanged` / `onChildRemoved` / `onChildMoved` — plain-ref subscription surface","status":"conforms","evidence":["Tier 2: sandbox aligned with oracle observations under `packages/conformance/observations/rtdb-modular/rtdb-modular-onchild*.json`. See M41–M48 for the per-event behavioral claims."],"assurance":"eligible"},{"id":"rtdb-modular#M41","kind":"registry-row","surface":"rtdb-modular","behavior":"`onChildAdded` replays each existing direct child of the parent ref on subscribe (one fire per existing key)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-child-events.test.ts` (\"replays existing direct children on subscribe — one fire per key\"); matches oracle observation `packages/conformance/observations/rtdb-modular/rtdb-modular-onchildadded-initial-replay.json` (seeded `{k1,k2,k3}`, observed `firedKeys: ['k1','k2','k3']`).","observation:rtdb-modular-onchildadded-initial-replay","packages/pyric/test/database/modular/sandbox-child-events.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M42","kind":"registry-row","surface":"rtdb-modular","behavior":"After subscribe, `onChildAdded` fires exactly once per new direct child write; snapshot carries `{key, val}` of the new child","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-child-events.test.ts` (\"fires exactly once per NEW direct child after subscribe\"); matches oracle observation `packages/conformance/observations/rtdb-modular/rtdb-modular-onchildadded-post-subscribe.json` (`postSubscribeFires: 1`, `lastFire: {key:'k3', val:{v:3}}`).","observation:rtdb-modular-onchildadded-post-subscribe","packages/pyric/test/database/modular/sandbox-child-events.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M75","kind":"registry-row","surface":"rtdb-modular","behavior":"**Divergence (DB-B12, honest doc):** the onChild* callbacks do NOT receive the `previousChildName` second argument; `onValue`/`onChild*` do NOT accept a `cancelCallback`; `onChildAdded`/`Changed`/`Removed`/`Moved` accept only plain refs (not `Query`); `child_moved` never fires (ordered-query move detection unmodeled). These listener-surface holes are out of scope for the current phase — consumers needing them use `firebase/database` directly.","status":"diverged-documented","evidence":["divergence documented; partial coverage: `{ onlyOnce }` IS implemented (M74)."],"assurance":"qualified"}]},{"feature":"onChildChanged","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"onChildChanged is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"database:runtime:onChildChanged","kind":"runtime-export","surface":"database","behavior":"onChildChanged is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#135","kind":"registry-row","surface":"rtdb-modular","behavior":"`onChildChanged` fires when an existing child's value changes; does NOT fire for added or removed children","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-onchildchanged-fires-on-update.json` — observed `firedOnInitial: 0, firedOnUpdate: 1, lastFire: {key:'k1', val:{v:2}}` (the NEW value, not the prior).","observation:rtdb-modular-onchildchanged-fires-on-update"],"assurance":"eligible"},{"id":"rtdb-modular#M31","kind":"registry-row","surface":"rtdb-modular","behavior":"`onChildAdded` / `onChildChanged` / `onChildRemoved` / `onChildMoved` — plain-ref subscription surface","status":"conforms","evidence":["Tier 2: sandbox aligned with oracle observations under `packages/conformance/observations/rtdb-modular/rtdb-modular-onchild*.json`. See M41–M48 for the per-event behavioral claims."],"assurance":"eligible"},{"id":"rtdb-modular#M43","kind":"registry-row","surface":"rtdb-modular","behavior":"`onChildChanged` has NO initial replay; fires once when an existing direct child's value transitions; snapshot carries the NEW value","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-child-events.test.ts` (\"does NOT fire on subscribe (no initial replay)\" + \"fires once when an existing child transitions to a new value; snapshot carries NEW val\"); matches oracle observation `packages/conformance/observations/rtdb-modular/rtdb-modular-onchildchanged-fires-on-update.json` (`firedOnInitial: 0, firedOnUpdate: 1, lastFire: {key:'k1', val:{v:2}}`).","observation:rtdb-modular-onchildchanged-fires-on-update","packages/pyric/test/database/modular/sandbox-child-events.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M44","kind":"registry-row","surface":"rtdb-modular","behavior":"`onChildChanged` does NOT fire for added or removed children — those go to the other event listeners","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-child-events.test.ts` (\"does NOT fire when a child is added\" + \"does NOT fire when a child is removed\").","packages/pyric/test/database/modular/sandbox-child-events.test.ts"],"assurance":"eligible"}]},{"feature":"onChildMoved","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"onChildMoved is available, has diverged fidelity, and is qualified for assurance.","caveats":["`onChildMoved` under an ordered query. Prod: fires when a child's `orderByChild`/`orderByValue` priority changes — emitted only on ordered queries. Sandbox: **never fires on reorder** — `onChildMoved` supports the plain-ref (no-fire) case only; the ordered-query overload is unimplemented","divergence, oracle-locked by `packages/conformance/observations/rtdb-modular/rtdb-modular-onchildmoved-with-orderby.json`: prod observed `firedOnMove: 1` under `query(ref, orderByChild('priority'))` after bumping a child's priority to a new sort position; the sandbox fires 0 on reorder. Partial alignment landed: all `onChild*` now ACCEPT a `Query` (previously threw a misleading `unrecognized reference` TypeError) with window-aware `child_added`/`child_changed`/`child_removed` diffs (`src/database/sandbox/backend.ts`); the two hold-lifting captures now exist: `rtdb-modular-onchildmoved-previouschildname-sequencing` pins prev-name sequencing (end/middle/front reorders yield prev k3/k2/null, no initial replay) and `rtdb-modular-childchanged-cofire-with-childmoved` pins co-fire semantics (a reorder fires BOTH `child_changed` and `child_moved`; a non-ordered-field change fires neither moved; prod fires `child_moved` on an ordered-field value change EVEN WHEN RANK IS UNCHANGED). Implementation of ordered `child_moved` is unblocked. Both sides pinned in `modular/oracle-conformance.test.ts` and `modular/sandbox-child-events.test.ts`. Sandbox Tier 2 locks the plain-ref no-fire case (M46)."],"claims":[{"id":"database:runtime:onChildMoved","kind":"runtime-export","surface":"database","behavior":"onChildMoved is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#137","kind":"registry-row","surface":"rtdb-modular","behavior":"`onChildMoved` under an ordered query. Prod: fires when a child's `orderByChild`/`orderByValue` priority changes — emitted only on ordered queries. Sandbox: **never fires on reorder** — `onChildMoved` supports the plain-ref (no-fire) case only; the ordered-query overload is unimplemented","status":"diverged-documented","evidence":["divergence, oracle-locked by `packages/conformance/observations/rtdb-modular/rtdb-modular-onchildmoved-with-orderby.json`: prod observed `firedOnMove: 1` under `query(ref, orderByChild('priority'))` after bumping a child's priority to a new sort position; the sandbox fires 0 on reorder. Partial alignment landed: all `onChild*` now ACCEPT a `Query` (previously threw a misleading `unrecognized reference` TypeError) with window-aware `child_added`/`child_changed`/`child_removed` diffs (`src/database/sandbox/backend.ts`); the two hold-lifting captures now exist: `rtdb-modular-onchildmoved-previouschildname-sequencing` pins prev-name sequencing (end/middle/front reorders yield prev k3/k2/null, no initial replay) and `rtdb-modular-childchanged-cofire-with-childmoved` pins co-fire semantics (a reorder fires BOTH `child_changed` and `child_moved`; a non-ordered-field change fires neither moved; prod fires `child_moved` on an ordered-field value change EVEN WHEN RANK IS UNCHANGED). Implementation of ordered `child_moved` is unblocked. Both sides pinned in `modular/oracle-conformance.test.ts` and `modular/sandbox-child-events.test.ts`. Sandbox Tier 2 locks the plain-ref no-fire case (M46).","observation:rtdb-modular-onchildmoved-with-orderby","observation:rtdb-modular-onchildmoved-previouschildname-sequencing","observation:rtdb-modular-childchanged-cofire-with-childmoved","packages/pyric/test/database/modular/oracle-conformance.test.ts"],"assurance":"qualified"},{"id":"rtdb-modular#M31","kind":"registry-row","surface":"rtdb-modular","behavior":"`onChildAdded` / `onChildChanged` / `onChildRemoved` / `onChildMoved` — plain-ref subscription surface","status":"conforms","evidence":["Tier 2: sandbox aligned with oracle observations under `packages/conformance/observations/rtdb-modular/rtdb-modular-onchild*.json`. See M41–M48 for the per-event behavioral claims."],"assurance":"eligible"},{"id":"rtdb-modular#M46","kind":"registry-row","surface":"rtdb-modular","behavior":"`onChildMoved` on a plain ref (no `query(_, orderBy*)`) NEVER fires — per RTDB docs, child_moved emits only under ordered queries","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-child-events.test.ts` (\"does NOT fire on a plain ref (no ordering)\"); matches the upstream contract observed under ordered-query in `packages/conformance/observations/rtdb-modular/rtdb-modular-onchildmoved-with-orderby.json` (where ordered-query did fire — Tier 3 will wire that path; Tier 2 locks the plain-ref no-fire case).","observation:rtdb-modular-onchildmoved-with-orderby","packages/pyric/test/database/modular/sandbox-child-events.test.ts"],"assurance":"eligible"}]},{"feature":"onChildRemoved","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"onChildRemoved is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"database:runtime:onChildRemoved","kind":"runtime-export","surface":"database","behavior":"onChildRemoved is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#136","kind":"registry-row","surface":"rtdb-modular","behavior":"`onChildRemoved` fires when a child is deleted (via `remove(child)` or `set(child, null)`); snapshot carries the PRIOR value","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-onchildremoved-fires-on-delete.json` — observed `firedOnDelete: 1, removedSnapCarriesPriorValue: true` (snapshot.val() was the pre-delete value).","observation:rtdb-modular-onchildremoved-fires-on-delete"],"assurance":"eligible"},{"id":"rtdb-modular#M31","kind":"registry-row","surface":"rtdb-modular","behavior":"`onChildAdded` / `onChildChanged` / `onChildRemoved` / `onChildMoved` — plain-ref subscription surface","status":"conforms","evidence":["Tier 2: sandbox aligned with oracle observations under `packages/conformance/observations/rtdb-modular/rtdb-modular-onchild*.json`. See M41–M48 for the per-event behavioral claims."],"assurance":"eligible"},{"id":"rtdb-modular#M45","kind":"registry-row","surface":"rtdb-modular","behavior":"`onChildRemoved` has NO initial replay; fires once when a direct child is deleted (via `remove(child)` or `set(child, null)`); snapshot carries the PRIOR (now-removed) value","status":"conforms","evidence":["`unit:upstream-rtdb-probes.test.ts` (parent wipe fan-out via remove(parent) / set(parent, scalar)) + `unit:modular/sandbox-child-events.test.ts` (single-child delete carries PRIOR val); matches oracle `rtdb-modular-onchildremoved-fires-on-delete.json`","observation:rtdb-modular-onchildremoved-fires-on-delete","packages/pyric/test/database/upstream-rtdb-probes.test.ts","packages/pyric/test/database/modular/sandbox-child-events.test.ts"],"assurance":"eligible"}]},{"feature":"OnDeviceParams","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"OnDeviceParams is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:OnDeviceParams","kind":"type-export","surface":"ai","behavior":"OnDeviceParams is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"OnDisconnect","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"OnDisconnect is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["onDisconnect requires a live connection lifecycle the in-memory sandbox has no equivalent for today — buildable as an honest no-op or inert token like the connection-management APIs, not genuinely un-modelable.","Public type export is not mirrored."],"claims":[{"id":"database:runtime:OnDisconnect","kind":"runtime-export","surface":"database","behavior":"onDisconnect requires a live connection lifecycle the in-memory sandbox has no equivalent for today — buildable as an honest no-op or inert token like the connection-management APIs, not genuinely un-modelable.","status":"deferred","evidence":["registry:rtdb-modular#163"],"assurance":"not-applicable"},{"id":"database:type:OnDisconnect","kind":"type-export","surface":"database","behavior":"OnDisconnect is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"onDisconnect","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"onDisconnect is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["onDisconnect requires a live connection lifecycle the in-memory sandbox has no equivalent for today — buildable as an honest no-op or inert token like the connection-management APIs, not genuinely un-modelable."],"claims":[{"id":"database:runtime:onDisconnect","kind":"runtime-export","surface":"database","behavior":"onDisconnect requires a live connection lifecycle the in-memory sandbox has no equivalent for today — buildable as an honest no-op or inert token like the connection-management APIs, not genuinely un-modelable.","status":"deferred","evidence":["registry:rtdb-modular#163"],"assurance":"not-applicable"}]},{"feature":"onIdTokenChanged","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"onIdTokenChanged is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:onIdTokenChanged","kind":"runtime-export","surface":"auth","behavior":"onIdTokenChanged is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#38","kind":"registry-row","surface":"auth","behavior":"Fires on user change (sandbox shares the auth-state path)","status":"conforms","evidence":["`unit:sandbox-listeners.test.ts` + oracle: `packages/conformance/observations/auth/auth-row-38-onidtokenchanged-fires-on-user-change.json` (against blockingfun, fb-js-sdk 12.13.0: subscribe → 1 initial fire (null) → `signInAnonymously` → +1 (user₁) → `signOut` → +1 (null) → `signInAnonymously` → +1 (user₂ with fresh uid). Every identity transition produces exactly one fire, matching `onAuthStateChanged`)","observation:auth-row-38-onidtokenchanged-fires-on-user-change","packages/pyric/test/auth/sandbox-listeners.test.ts"],"assurance":"eligible"},{"id":"auth#38a","kind":"registry-row","surface":"auth","behavior":"Fires on EVERY sign-in, including a same-uid re-sign-in (no `signOut` first) — which mints a fresh token, so a subsequent `getIdToken()` returns a new string. Mirrors upstream `notifyAuthListeners`, which calls `idTokenSubscription.next` on every identity update (`auth_impl.ts:716`). `onAuthStateChanged` stays silent on the same-uid case (row 30a).","status":"conforms","evidence":["`unit:sandbox-uid-dedup.test.ts` (locks AUTH-B8)","packages/pyric/test/auth/sandbox-uid-dedup.test.ts"],"assurance":"eligible"},{"id":"auth#39","kind":"registry-row","surface":"auth","behavior":"Fires on token refresh (`getIdToken(true)`)","status":"conforms","evidence":["`unit:sandbox-token-refresh.test.ts` — was ⚠ (documented divergence); aligned to prod in commit — sandbox now mints a fresh token on forceRefresh and fires `onIdTokenChanged` (NOT `onAuthStateChanged`, since identity is unchanged). Oracle: `packages/conformance/observations/auth/auth-onidtokenchanged-force-refresh.json` defines the target shape (`refreshFiredListener: true` against blockingfun; subscribe → null fire → `signInAnonymously` → +1 → `getIdToken(true)` → +1 for a total of 3 fires).","observation:auth-onidtokenchanged-force-refresh","packages/pyric/test/auth/sandbox-token-refresh.test.ts"],"assurance":"eligible"},{"id":"auth#40","kind":"registry-row","surface":"auth","behavior":"Initial-fire semantics match `onAuthStateChanged`","status":"conforms","evidence":["`unit:sandbox-listeners.test.ts` + oracle: `packages/conformance/observations/auth/auth-row-40-onidtokenchanged-matches-onauthstatechanged-initial-fire.json` (against blockingfun, fb-js-sdk 12.13.0: subscribing both listeners in the same tick yields `sync: {auth: 0, idToken: 0}` → `microtask: {auth: 1, idToken: 1}` → no further fires. Both listeners share the microtask-deferred initial-fire timing)","observation:auth-row-40-onidtokenchanged-matches-onauthstatechanged-initial-fire","packages/pyric/test/auth/sandbox-listeners.test.ts"],"assurance":"eligible"}]},{"feature":"onLog","surface":"app","importPaths":["pyric/app"],"evidenceSlug":"app-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"onLog is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"app:runtime:onLog","kind":"runtime-export","surface":"app","behavior":"onLog is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"app#13","kind":"registry-row","surface":"app","behavior":"`onLog(cb)` / `setLogLevel(level)` are a functioning app-owned diagnostic-logger seam: registering a handler returns undefined, raising the threshold takes effect, and a malformed `registerVersion` emits a `warn` entry (type `@firebase/app`) to the handler","status":"conforms","evidence":["oracle: `app-registry-onlog-setloglevel` (firebase 12.13.0) + replay: `oracle-conformance.test.ts`","observation:app-registry-onlog-setloglevel","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"onMessage","surface":"messaging","importPaths":["pyric/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"onMessage is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging:runtime:onMessage","kind":"runtime-export","surface":"messaging","behavior":"onMessage is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"messaging#11","kind":"registry-row","surface":"messaging","behavior":"The callback, observer, and teardown types consumed by `onMessage` / `onBackgroundMessage` are re-exported from `@firebase/util`.","status":"conforms","evidence":["Upstream typings (`@firebase/messaging` 0.12.26 re-exports); no observation yet.","packages/pyric/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"messaging#4","kind":"registry-row","surface":"messaging","behavior":"Dispatched with the push payload when a message arrives while a window client is visible; the returned function stops listening. Routing keys on page VISIBILITY, not focus: a `visibilityState: \"visible\"` page receives `onMessage` even when unfocused, and when no window client is visible the message routes to the service-worker `onBackgroundMessage` instead.","status":"conforms","evidence":["oracle: `messaging-web-onmessage-foreground.json` (focused page → onMessage) + `messaging-web-visibility-routing.json` (visible → onMessage, no visible client → onBackgroundMessage). Replayed by the conformance suite.","observation:messaging-web-onmessage-foreground","observation:messaging-web-visibility-routing","packages/pyric/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"messaging#8","kind":"registry-row","surface":"messaging","behavior":"Received message envelope delivered to `onMessage` / `onBackgroundMessage`. Production deliveries carry top-level keys `data`, `from`, `messageId`, and `notification`; `from` equals the project messaging sender id and `messageId` is present. (`from`, `collapseKey`, `messageId` are typed as required.)","status":"conforms","evidence":["oracle: `messaging-web-onmessage-foreground.json` + `messaging-web-onbackgroundmessage.json` (top-level keys data/from/messageId/notification; from = sender id; messageId present). Replayed by the conformance suite.","observation:messaging-web-onmessage-foreground","observation:messaging-web-onbackgroundmessage","packages/pyric/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"onSnapshot","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"onSnapshot is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:onSnapshot","kind":"runtime-export","surface":"firestore","behavior":"onSnapshot is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#80","kind":"registry-row","surface":"firestore","behavior":"`onSnapshot(docRef, cb)` fires the initial snapshot **asynchronously** — never synchronously during the registering call. Prod empirically lands after a `setTimeout(0)` macrotask (the fire travels the network listener channel); the sandbox defers through its delivery scheduler (microtask). The matrix contract is \"asynchronous, never during register\", not \"exactly the next microtask\"","status":"conforms","evidence":["Aligned via the listener delivery scheduler (`src/sandbox/firestore/local-environment.ts`): the initial fire is enqueued and delivered on a microtask, never during register — closing the divergence this row previously documented (the sandbox used to fire synchronously during registration; the sync-body tests were migrated to the flush/await idiom). Machine-checked against `packages/conformance/observations/firestore/firestore-row-80-onsnapshot-fires-initial.json` (`firstFireSyncDuringRegister: false`, fire count + contents) in `oracle-conformance.test.ts`; also `unit:sandbox-target.test.ts`, `playground:firestore-onsnapshot` (bundled) + `playground:firestore-row-80-onsnapshot-fires-initial` (one-claim).","observation:firestore-row-80-onsnapshot-fires-initial","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#81","kind":"registry-row","surface":"firestore","behavior":"`onSnapshot(query, cb)` fires on collection writes; `QuerySnapshot.docChanges()` reports `added` / `modified` / `removed` with `oldIndex` / `newIndex`","status":"conforms","evidence":["`unit:sandbox-target.test.ts`, oracle: `packages/conformance/observations/firestore/firestore-row-81-onsnapshot-query-fires-on-write.json` — listener on `query(coll)` saw 1 initial fire (empty, `size:0`), then one fire per write: `addDoc` → `size:1`, `setDoc(coll, 'known-id')` → `size:2`, `deleteDoc(addedRef)` → `size:1`. Total 4 fires, each reflecting the current collection state. Every collection-level write produces a distinct fire. (Note: this oracle used a *filterless* `query(coll)`, which masked FS-B2 — see row 81a.) Modular `docChanges` indexes: `unit:upstream-transform-txn-listener-probes.test.ts`","observation:firestore-row-81-onsnapshot-query-fires-on-write","packages/pyric/test/firestore/sandbox-target.test.ts","packages/pyric/test/firestore/upstream-transform-txn-listener-probes.test.ts"],"assurance":"eligible"},{"id":"firestore#81a","kind":"registry-row","surface":"firestore","behavior":"**Filtered listeners honor `where` / `orderBy` / `limit` (FS-B2)** — `onSnapshot(query(coll, where(…), orderBy(…), limit(…)), cb)` delivers the same membership as `getDocs(sameQuery)`: non-matching docs are excluded on the initial fire and on writes; ordering + limit are applied. Pre-FS-B2 the `SnapshotTarget` dropped all constraints and delivered the whole collection.","status":"conforms","evidence":["`unit:onsnapshot-query-constraints.test.ts` (filtered/ordered/limited listeners; verified failing pre-fix)","packages/pyric/test/firestore/onsnapshot-query-constraints.test.ts"],"assurance":"eligible"},{"id":"firestore#81b","kind":"registry-row","surface":"firestore","behavior":"**Listener `.data()` matches `getDoc` shape (FS-B10)** — the `onSnapshot` doc + query snapshot path runs the same read-path translation as `getDoc`/`getDocs`, so `snap.data().createdAt` is a compat `Timestamp` (`{seconds, nanoseconds}`), not the rules-internal wrapper (`{seconds, nanos}` + `typeName`, no `nanoseconds`). Pre-FS-B10 a listener leaked the internal shape while the single-doc read returned the compat shape.","status":"conforms","evidence":["`unit:simulator/listener-read-translation.test.ts` (doc + query listener Timestamp shape; verified failing pre-fix)","packages/pyric/test/sandbox/firestore/simulator/listener-read-translation.test.ts"],"assurance":"eligible"},{"id":"firestore#82","kind":"registry-row","surface":"firestore","behavior":"Initial fire for a missing doc has `exists() === false` and `data() === undefined`","status":"conforms","evidence":["`playground:firestore-onsnapshot` (bundled) + `playground:firestore-row-82-onsnapshot-missing-initial` (one-claim), oracle: `packages/conformance/observations/firestore/firestore-row-82-onsnapshot-missing-initial.json` — single initial fire with `snap.exists() === false`, `snap.data() === undefined`, `hasPendingWrites: false`, `fromCache: false`. The missing-doc fire is server-confirmed, not a cache speculation.","observation:firestore-row-82-onsnapshot-missing-initial"],"assurance":"eligible"},{"id":"firestore#83","kind":"registry-row","surface":"firestore","behavior":"Returned `Unsubscribe` stops further fires","status":"conforms","evidence":["`unit:sandbox-target.test.ts`, oracle: `packages/conformance/observations/firestore/firestore-row-83-unsubscribe-stops-fires.json` — pre-unsubscribe write fired the listener (initial fire + write fire = 2 fires); after `unsub()`, a subsequent `setDoc` produced 0 additional fires (`postUnsubFireCount: 0`). Unsubscribe is durable; no fires arrive on the released callback after a 1.5s settle window.","observation:firestore-row-83-unsubscribe-stops-fires","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#84","kind":"registry-row","surface":"firestore","behavior":"Observer object form `{next, error, complete}` works alongside the function form. **Partial observers are accepted — `{ error: fn }` with no `next` registers and routes denials to `error` (FS-B14, `isPartialObserver` semantics from upstream `api/observer.ts`); pre-fix it was misrouted as `SnapshotListenOptions` and threw \"missing next handler\".**","status":"conforms","evidence":["oracle: `packages/conformance/observations/firestore/firestore-row-84-observer-object-form.json` — registered two listeners on the same doc: one as a bare function `(snap) => …`, one as `{next, error, complete}`. Both fired once on initial (`{v:0}`) and again after a write (`{v:1}`), capturing identical data. `error` never fired (no rule denial), `complete` never fired on `unsub()` (Firebase treats unsubscribe as a teardown, not a \"complete\" signal — the observer's `complete` callback is reserved for terminal stream end, which `onSnapshot` does not produce). The two registration shapes are interchangeable for fire dispatch. `unit:onsnapshot-observer-discriminator.test.ts` (error-only observer; verified failing pre-fix)","observation:firestore-row-84-observer-object-form","packages/pyric/test/firestore/onsnapshot-observer-discriminator.test.ts"],"assurance":"eligible"},{"id":"firestore#85","kind":"registry-row","surface":"firestore","behavior":"`SnapshotListenOptions.includeMetadataChanges` — one write yields the pending-write local echo (`hasPendingWrites: true`) then, for metadata listeners, the settled ack fire: default listener 2 fires, metadata listener 3","status":"conforms","evidence":["Aligned via the listener delivery scheduler (`src/sandbox/firestore/local-environment.ts` + `snapshot-listeners.ts`): the write echo carries `hasPendingWrites: true` and `includeMetadataChanges` listeners receive the settled metadata-only ack, reproducing prod's recorded 2/3-fire sequences exactly. Machine-checked against `packages/conformance/observations/firestore/firestore-include-metadata-changes.json` in `oracle-conformance.test.ts` (fire counts and per-fire `hasPendingWrites` sequence asserted from the capture)","observation:firestore-include-metadata-changes"],"assurance":"eligible"},{"id":"firestore#86","kind":"registry-row","surface":"firestore","behavior":"Snapshot's `.ref` / `.docs[i].ref` are tagged so consumer code can pass them to follow-up ops","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#87","kind":"registry-row","surface":"firestore","behavior":"Sandbox-live: listener registered as alice keeps emitting alice's view after `setUser → bob` (identity frozen at subscribe)","status":"conforms","evidence":["`unit:sandbox-live-identity.test.ts` (\"listener registered as alice keeps emitting alice's view\")","packages/pyric/test/firestore/sandbox-live-identity.test.ts"],"assurance":"eligible"},{"id":"firestore#88","kind":"registry-row","surface":"firestore","behavior":"Sandbox-live: listener registered as anonymous keeps firing after sign-in (anonymous → signed-in identity persists per listener)","status":"conforms","evidence":["`unit:sandbox-live-identity.test.ts` (\"listener registered as anonymous on /public keeps firing after sign-in\")","packages/pyric/test/firestore/sandbox-live-identity.test.ts"],"assurance":"eligible"},{"id":"firestore#89","kind":"registry-row","surface":"firestore","behavior":"Snapshot's ref is usable in follow-up ops under the new user (the ref is live, the listener identity is frozen — distinct)","status":"conforms","evidence":["`unit:sandbox-live-identity.test.ts` (\"snapshot ref is usable in subsequent ops under the new user\"), oracle: `packages/conformance/observations/firestore/firestore-row-89-snapshot-ref-usable.json` — captured `snap.ref` from a docRef listener's first fire and `snap.docs[0].ref` from a query listener's first fire; both refs round-trip via `getDoc` (returning the same data) and `setDoc` (writes succeed and a follow-up `getDoc` confirms the new payload). `snap.ref.path` equals the original `doc(coll, id).path`. Both snap-ref shapes are first-class refs in prod, matching sandbox's tagged-ref guarantee.","observation:firestore-row-89-snapshot-ref-usable","packages/pyric/test/firestore/sandbox-live-identity.test.ts"],"assurance":"eligible"},{"id":"firestore#90","kind":"registry-row","surface":"firestore","behavior":"Preview tree mounts the user's component exactly once per session load — no observer subscriptions leak across parallel `AppPreview` instances. Root cause: `PlaygroundPage` rendered both `WorkspacePanel`'s and the mobile `AppPanel`'s `AppPreview` unconditionally (the latter `md:hidden` on desktop but still mounted), producing two live preview trees subscribing in parallel. Fixed by gating `AppPanel` on `useIsMobile() && mobileTab === 'app'`.","status":"conforms","evidence":["`playground:preview-single-mount`"],"assurance":"eligible"}]},{"feature":"onSnapshotResume","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"onSnapshotResume is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Snapshot JSON reconstruction and listener-resume helpers depend on serialized snapshot state that the sandbox has not modeled."],"claims":[{"id":"firestore:runtime:onSnapshotResume","kind":"runtime-export","surface":"firestore","behavior":"Snapshot JSON reconstruction and listener-resume helpers depend on serialized snapshot state that the sandbox has not modeled.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"}]},{"feature":"onSnapshotsInSync","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"onSnapshotsInSync is available, has diverged fidelity, and is qualified for assurance.","caveats":["Fires the callback once the current snapshot-delivery microtask queue settles — the closest honest approximation of \"every active listener has delivered its latest state\" available without a true cross-listener sync signal. Not scoped to real server round-trips like the real SDK's guarantee; scoped to local delivery only","`unit:firestore/tier1-cache-init-align.test.ts`"],"claims":[{"id":"firestore:runtime:onSnapshotsInSync","kind":"runtime-export","surface":"firestore","behavior":"onSnapshotsInSync is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#150","kind":"registry-row","surface":"firestore","behavior":"Fires the callback once the current snapshot-delivery microtask queue settles — the closest honest approximation of \"every active listener has delivered its latest state\" available without a true cross-listener sync signal. Not scoped to real server round-trips like the real SDK's guarantee; scoped to local delivery only","status":"diverged-documented","evidence":["`unit:firestore/tier1-cache-init-align.test.ts`","packages/pyric/test/firestore/tier1-cache-init-align.test.ts"],"assurance":"qualified"}]},{"feature":"onValue","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"onValue is available, has diverged fidelity, and is qualified for assurance.","caveats":["**Divergence (DB-B12, honest doc):** the onChild* callbacks do NOT receive the `previousChildName` second argument; `onValue`/`onChild*` do NOT accept a `cancelCallback`; `onChildAdded`/`Changed`/`Removed`/`Moved` accept only plain refs (not `Query`); `child_moved` never fires (ordered-query move detection unmodeled). These listener-surface holes are out of scope for the current phase — consumers needing them use `firebase/database` directly.","divergence documented; partial coverage: `{ onlyOnce }` IS implemented (M74).","The returned value from `onValue(ref, cb)` is the unsubscribe function (NOT an object); calling it removes the listener","upstream contract — locked indirectly by #131"],"claims":[{"id":"database:runtime:onValue","kind":"runtime-export","surface":"database","behavior":"onValue is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#128","kind":"registry-row","surface":"rtdb-modular","behavior":"Subscribing to a path with **existing data** fires the listener once with the current snapshot (the \"initial fire\")","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-onvalue-initial-with-data.json` — observed exactly 1 initial fire within ~46ms of subscribe, snapshot.val() === the seeded payload.","observation:rtdb-modular-onvalue-initial-with-data"],"assurance":"eligible"},{"id":"rtdb-modular#129","kind":"registry-row","surface":"rtdb-modular","behavior":"Subscribing to a **nonexistent path** still fires the listener once — with a `null`-val snapshot AND `exists() === false`. Matches Firestore's `onSnapshot`-on-missing-doc semantics: prod RTDB does NOT silently skip the initial fire for empty paths.","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-onvalue-initial-no-data.json` — observed 1 initial fire on a never-written path with `firstFire.val: null, firstFire.exists: false` (~55ms after subscribe).","observation:rtdb-modular-onvalue-initial-no-data"],"assurance":"eligible"},{"id":"rtdb-modular#130","kind":"registry-row","surface":"rtdb-modular","behavior":"Subsequent `set(ref, …)` fires the listener with the new value","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb/rtdb-onvalue-fires-on-set.json` — observed 1 fire per `set()` (1+1+1 = 3 total: initial-null, after-first-set, after-second-set).","observation:rtdb-onvalue-fires-on-set"],"assurance":"eligible"},{"id":"rtdb-modular#131","kind":"registry-row","surface":"rtdb-modular","behavior":"Unsubscribe — the returned unsubscribe function stops further fires; subsequent writes produce 0 additional fires after `unsub()`","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-onvalue-unsubscribe.json` — observed `preUnsubFires: 2, postUnsubFires: 2` (a write performed after `unsub()` produced 0 additional fires within a 500ms settle window).","observation:rtdb-modular-onvalue-unsubscribe"],"assurance":"eligible"},{"id":"rtdb-modular#132","kind":"registry-row","surface":"rtdb-modular","behavior":"The returned value from `onValue(ref, cb)` is the unsubscribe function (NOT an object); calling it removes the listener","status":"unverified","evidence":["upstream contract — locked indirectly by #131"],"assurance":"qualified"},{"id":"rtdb-modular#M26","kind":"registry-row","surface":"rtdb-modular","behavior":"`onValue(ref, cb)` fires immediately on subscribe with the current value at the path","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"fires on subscribe with the current value\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M27","kind":"registry-row","surface":"rtdb-modular","behavior":"`onValue` fires again after every write that CHANGES the value at the watched path; a write that leaves the watched subtree byte-identical (a no-change re-write, or an ancestor/descendant write that doesn't alter this path) is suppressed (DB-B8)","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"fires after every write that touches the watched path\") + `unit:modular/no-change-suppression.test.ts` (\"re-writing the same value does NOT re-fire\" + \"ancestor write leaving the subtree unchanged does NOT fire\")","packages/pyric/test/database/modular/no-change-suppression.test.ts","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M28","kind":"registry-row","surface":"rtdb-modular","behavior":"`onValue` fires after a descendant write (the listener sees subtree changes)","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"fires on a descendant write\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M29","kind":"registry-row","surface":"rtdb-modular","behavior":"`onValue` initial-fire for an absent path delivers `val=null, exists=false` (matches matrix expectation locked by oracle for sentinel/listener shape)","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"absent path: initial fire delivers val=null, exists=false\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M30","kind":"registry-row","surface":"rtdb-modular","behavior":"The `onValue` return value is an unsubscribe function; calling it stops further fires","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"fires after every write that touches the watched path\" — checks unsubscribed listener doesn't fire on subsequent write)","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M37d","kind":"registry-row","surface":"rtdb-modular","behavior":"`options.applyLocally` controls whether the in-flight optimistic value fans out to `onValue` listeners — default `true` (apply locally before commit); `false` suppresses intermediate fires so listeners see only the committed value","status":"conforms","evidence":["Sandbox aligned: `unit:modular/transaction.test.ts` (\"applyLocally: true (default) — listener sees initial + committed value\" + \"applyLocally: false — listener sees only the committed value\"); matches oracle observation `packages/conformance/observations/rtdb-modular/rtdb-modular-runtransaction-options-applylocally.json` (single-client harness: both branches produce 2 fires (initial + commit) — divergence vs prod's documented multi-client suppression would surface under contention, which the sandbox doesn't model)","observation:rtdb-modular-runtransaction-options-applylocally","packages/pyric/test/database/modular/transaction.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M37g","kind":"registry-row","surface":"rtdb-modular","behavior":"Committed transaction fans out to `onValue` listeners on the watched path with the new value (default applyLocally behavior)","status":"conforms","evidence":["`unit:modular/transaction.test.ts` (\"committed write fans out to onValue listeners\")","packages/pyric/test/database/modular/transaction.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M58","kind":"registry-row","surface":"rtdb-modular","behavior":"`onValue(query, cb)` only fires when the windowed result changes — writes OUTSIDE the window don't re-fire the listener; writes that displace a member DO","status":"conforms","evidence":["`unit:upstream-rtdb-probes.test.ts` (\"one update nulls, mutates, and displaces within a limitToFirst window\") + `unit:modular/queries.test.ts` (\"fires only when the windowed result changes\"); matches oracle `rtdb-modular-onvalue-with-query.json`","observation:rtdb-modular-onvalue-with-query","packages/pyric/test/database/upstream-rtdb-probes.test.ts","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M59","kind":"registry-row","surface":"rtdb-modular","behavior":"`onValue(query)` initial fire delivers an empty window (`numChildren() === 0`) when the path is absent","status":"conforms","evidence":["`unit:modular/queries.test.ts` (\"initial fire on an empty path delivers an empty window\")","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M74","kind":"registry-row","surface":"rtdb-modular","behavior":"`onValue(ref, cb, { onlyOnce: true })` fires once then auto-unsubscribes (DB-B12)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/onvalue-onlyonce.test.ts`; upstream `api/Reference_impl.ts:975-980`","packages/pyric/test/database/modular/onvalue-onlyonce.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M75","kind":"registry-row","surface":"rtdb-modular","behavior":"**Divergence (DB-B12, honest doc):** the onChild* callbacks do NOT receive the `previousChildName` second argument; `onValue`/`onChild*` do NOT accept a `cancelCallback`; `onChildAdded`/`Changed`/`Removed`/`Moved` accept only plain refs (not `Query`); `child_moved` never fires (ordered-query move detection unmodeled). These listener-surface holes are out of scope for the current phase — consumers needing them use `firebase/database` directly.","status":"diverged-documented","evidence":["divergence documented; partial coverage: `{ onlyOnce }` IS implemented (M74)."],"assurance":"qualified"}]},{"feature":"onValueCreated","surface":"functions-rtdb","importPaths":[],"evidenceSlug":"functions-rtdb-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"onValueCreated is available, has unverified fidelity, and is qualified for assurance.","caveats":["A handler that throws or returns a rejected Promise is reported by the managed runtime; with retry disabled, the Eventarc request can still be acknowledged with HTTP 200.","oracle: `functions-rtdb-onvaluecreated-failed-execution.json`; Pyric observes the rejected handler and marker, but has no Eventarc HTTP request seam with which to replay the captured 200 acknowledgement."],"claims":[{"id":"functions-rtdb#1","kind":"registry-row","surface":"functions-rtdb","behavior":"A write that changes an exact matched RTDB location from absent to present invokes the handler once with a create CloudEvent and a DataSnapshot containing the created value.","status":"conforms","evidence":["oracle: `functions-rtdb-onvaluecreated-exact-create.json` (firebase-functions 7.2.5); production exact-create behavior. Local replay: `packages/cli/test/functions-rtdb/oracle-conformance.test.ts` assertion set `functions-rtdb#1`.","observation:functions-rtdb-onvaluecreated-exact-create","packages/cli/test/functions-rtdb/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"functions-rtdb#11","kind":"registry-row","surface":"functions-rtdb","behavior":"A Promise returned by the handler keeps the execution open through delayed asynchronous work and its awaited Admin write.","status":"conforms","evidence":["oracle: `functions-rtdb-onvaluecreated-exact-create.json`; capture logged only after the delayed Admin write completed. Local replay: `packages/cli/test/functions-rtdb/oracle-conformance.test.ts` assertion set `functions-rtdb#11`.","observation:functions-rtdb-onvaluecreated-exact-create","packages/cli/test/functions-rtdb/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"functions-rtdb#12","kind":"registry-row","surface":"functions-rtdb","behavior":"A handler that throws or returns a rejected Promise is reported by the managed runtime; with retry disabled, the Eventarc request can still be acknowledged with HTTP 200.","status":"unverified","evidence":["oracle: `functions-rtdb-onvaluecreated-failed-execution.json`; Pyric observes the rejected handler and marker, but has no Eventarc HTTP request seam with which to replay the captured 200 acknowledgement.","observation:functions-rtdb-onvaluecreated-failed-execution"],"assurance":"qualified"},{"id":"functions-rtdb#13","kind":"registry-row","surface":"functions-rtdb","behavior":"Sequential creates are all delivered; their observed arrival order is evidence, not an ordering guarantee.","status":"conforms","evidence":["oracle: `functions-rtdb-onvaluecreated-wildcard-batches.json`; all three arrived in observed order 2, 1, 3. Local replay: `packages/cli/test/functions-rtdb/oracle-conformance.test.ts` assertion set `functions-rtdb#13`.","observation:functions-rtdb-onvaluecreated-wildcard-batches","packages/cli/test/functions-rtdb/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"functions-rtdb#2","kind":"registry-row","surface":"functions-rtdb","behavior":"After the initial create delivery, changing or deleting that same matched value does not invoke an onValueCreated handler.","status":"conforms","evidence":["oracle: `functions-rtdb-onvaluecreated-exact-create.json`; update/delete produced no additional delivery in the bounded production scenario. Local replay: `packages/cli/test/functions-rtdb/oracle-conformance.test.ts` assertion set `functions-rtdb#2`.","observation:functions-rtdb-onvaluecreated-exact-create","packages/cli/test/functions-rtdb/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"functions-rtdb#3","kind":"registry-row","surface":"functions-rtdb","behavior":"A value that already exists when the trigger is deployed does not produce a historical create delivery.","status":"conforms","evidence":["oracle: `functions-rtdb-onvaluecreated-startup-existing.json`; pre-seeded value, zero delivery in the observation window. Local replay: `packages/cli/test/functions-rtdb/oracle-conformance.test.ts` assertion set `functions-rtdb#3`.","observation:functions-rtdb-onvaluecreated-startup-existing","packages/cli/test/functions-rtdb/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"functions-rtdb#4","kind":"registry-row","surface":"functions-rtdb","behavior":"A named single-segment wildcard matches a created child and exposes the matched segment through event.params.","status":"conforms","evidence":["oracle: `functions-rtdb-onvaluecreated-wildcard-batches.json`; production populated caseId and itemId. Local replay: `packages/cli/test/functions-rtdb/oracle-conformance.test.ts` assertion set `functions-rtdb#4`.","observation:functions-rtdb-onvaluecreated-wildcard-batches","packages/cli/test/functions-rtdb/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"functions-rtdb#5","kind":"registry-row","surface":"functions-rtdb","behavior":"Creating an ancestor object invokes the wildcard handler once for each newly-present matching descendant.","status":"conforms","evidence":["oracle: `functions-rtdb-onvaluecreated-wildcard-batches.json`; one ancestor set delivered alpha and beta. Local replay: `packages/cli/test/functions-rtdb/oracle-conformance.test.ts` assertion set `functions-rtdb#5`.","observation:functions-rtdb-onvaluecreated-wildcard-batches","packages/cli/test/functions-rtdb/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"functions-rtdb#6","kind":"registry-row","surface":"functions-rtdb","behavior":"When an ancestor write creates an exact matched descendant, the event snapshot is projected to that descendant rather than the ancestor object.","status":"conforms","evidence":["oracle: `functions-rtdb-onvaluecreated-descendant-projection.json`; leaf snapshot excluded its sibling. Local replay: `packages/cli/test/functions-rtdb/oracle-conformance.test.ts` assertion set `functions-rtdb#6`.","observation:functions-rtdb-onvaluecreated-descendant-projection","packages/cli/test/functions-rtdb/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"functions-rtdb#7","kind":"registry-row","surface":"functions-rtdb","behavior":"One multi-location update that creates multiple wildcard-matched children produces one create delivery for each child.","status":"conforms","evidence":["oracle: `functions-rtdb-onvaluecreated-wildcard-batches.json`; one update delivered delta and gamma. Local replay: `packages/cli/test/functions-rtdb/oracle-conformance.test.ts` assertion set `functions-rtdb#7`.","observation:functions-rtdb-onvaluecreated-wildcard-batches","packages/cli/test/functions-rtdb/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"OperationType","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"OperationType is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:OperationType","kind":"runtime-export","surface":"auth","behavior":"OperationType is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#172","kind":"registry-row","surface":"auth","behavior":"The constant maps, value for value. `OperationType.SIGN_IN === 'signIn'`, `SignInMethod.EMAIL_LINK === 'emailLink'`, `ProviderId.GOOGLE === 'google.com'`, `ActionCodeOperation.PASSWORD_RESET === 'PASSWORD_RESET'`, and the 106-entry `AuthErrorCodes` map (`INVALID_OOB_CODE === 'auth/invalid-action-code'`, `PROVIDER_ALREADY_LINKED === 'auth/provider-already-linked'`, `NO_SUCH_PROVIDER === 'auth/no-such-provider'`, `USER_MISMATCH === 'auth/user-mismatch'`, …).","status":"conforms","evidence":["ORACLE-BACKED, snapshotted straight from the shipped SDK: `auth-mechanical-surface-constants` against firebase-js-sdk 12.13.0, replayed value-for-value in `unit:oracle-conformance.test.ts`. This matters more than it looks: consumer code COMPARES against these constants, so a mirror that got a string wrong would turn every such comparison into a silent `false` — a worse failure than the export simply being absent, because it typechecks and runs. NOTE: the capture's `persistenceTypes` block is deliberately NOT asserted — the harness runs under Node, where firebase/auth stubs the browser-only persistence tokens to `type: 'NONE'` (it reports 'NONE' even for `browserLocalPersistence`, which is unambiguously 'LOCAL'); asserting it would be asserting a harness artifact. See auth#178.","observation:auth-mechanical-surface-constants","packages/pyric/test/auth/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"operator.add","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.add is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.operator.add","kind":"rules-construct","surface":"firestore-rules","behavior":"operator.add is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.add","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"operator.add is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.operator.add","kind":"rules-construct","surface":"rtdb-rules","behavior":"operator.add is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/database/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"operator.add","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.add is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage.operator.add","kind":"rules-construct","surface":"storage-rules","behavior":"operator.add is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.and","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.and is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#163","kind":"registry-row","surface":"firestore-rules","behavior":"CEL tri-state error absorption in `||`/`&&` (RULES-B3) — `error || true` → ALLOW, `error && false` → DENY, commutative absorption (not JS left-to-right short-circuit)","status":"conforms","evidence":["`oracle:rules-firestore-error-absorption-and-or` — production Firestore Rules Test API verdicts for corpus scenario \"error-absorption-and-or\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`; all cases match production.","observation:rules-firestore-error-absorption-and-or","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"firestore.operator.and","kind":"rules-construct","surface":"firestore-rules","behavior":"operator.and is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.and","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"operator.and is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.operator.and","kind":"rules-construct","surface":"rtdb-rules","behavior":"operator.and is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/database/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"operator.and","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.and is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage.operator.and","kind":"rules-construct","surface":"storage-rules","behavior":"operator.and is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.div","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"operator.div is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["`int`/`float` division and type distinction (RULES-B5) in rules — truncating int÷int, float division stays float, div-by-zero denies, `is int`/`is float` distinct","`oracle:rules-firestore-int-float-and-division` — production Firestore Rules Test API verdicts for corpus scenario \"int-float-and-division\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator narrows a float-valued payload field toward int on the float-payload case, unlike production which preserves the float type — pinned KNOWN_DIVERGENCE"],"claims":[{"id":"firestore-rules#167","kind":"registry-row","surface":"firestore-rules","behavior":"`int`/`float` division and type distinction (RULES-B5) in rules — truncating int÷int, float division stays float, div-by-zero denies, `is int`/`is float` distinct","status":"diverged-documented","evidence":["`oracle:rules-firestore-int-float-and-division` — production Firestore Rules Test API verdicts for corpus scenario \"int-float-and-division\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator narrows a float-valued payload field toward int on the float-payload case, unlike production which preserves the float type — pinned KNOWN_DIVERGENCE","observation:rules-firestore-int-float-and-division","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"ineligible"},{"id":"firestore.operator.div","kind":"rules-construct","surface":"firestore-rules","behavior":"operator.div is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-conditions"],"assurance":"ineligible"}]},{"feature":"operator.div","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"operator.div is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.operator.div","kind":"rules-construct","surface":"rtdb-rules","behavior":"operator.div is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/database/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"operator.div","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.div is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#119","kind":"registry-row","surface":"storage-rules","behavior":"Ternary `?:` — branch selection, error-in-condition deny, and `error || true` absorption","status":"conforms","evidence":["NEW ROW, 2026-07-17: production capture proves the evaluator selects ternary branches by condition, denies when the CONDITION errors (even with identical `true` branches — production errors the whole conditional rather than falling through to a branch), and still absorbs the same error through `|| true`. `oracle:rules-storage-ternary-and-error-absorption` matches production verdict-for-verdict on all 5 cases. A division-by-zero in the condition previously yielded JS Infinity (no error) and false-ALLOWed the erroring-condition case; zero divisors now error-and-deny.","observation:rules-storage-ternary-and-error-absorption","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage-rules#123","kind":"registry-row","surface":"storage-rules","behavior":"Float literals, `%`, unary minus, float division, negative-dividend modulo (`-7 % 2 == -1`), and TRUNCATING int division (`10 / 4 == 2`, `-7 / 2 == -3`)","status":"conforms","evidence":["ROW CORRECTED, 2026-07-17 (same day): with the RULES-B5 float model adopted from the simulator, int ÷ int truncates toward zero, float division stays float (re-tagged), and int-op-float promotes to float. `oracle:rules-storage-float-modulo-unary-minus` now matches production verdict-for-verdict on all 6 cases with no knownGap abstentions. An int zero divisor errors-and-denies; a float zero divisor follows the simulator's CEL-pinned ±Infinity/NaN. The prior same-day row recorded the truncation divergence; that gap is closed.","observation:rules-storage-float-modulo-unary-minus","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.operator.div","kind":"rules-construct","surface":"storage-rules","behavior":"operator.div is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.eq","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.eq is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.operator.eq","kind":"rules-construct","surface":"firestore-rules","behavior":"operator.eq is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.eq","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.eq is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#122","kind":"registry-row","surface":"storage-rules","behavior":"List/map literals, range-slice access `[i:j]` on lists and strings (out-of-range bounds ERROR, no JS clamp), and structural `==` on lists","status":"conforms","evidence":["NEW ROW, 2026-07-17: production capture proves slices evaluate on `split()` lists and on strings, that an out-of-range slice END errors and denies (production does NOT clamp to length the way JS `.slice()` does — same semantics the Firestore capture pinned in rules-firestore-range-slice-list-and-string), and that a slice compares equal to a list literal structurally. `oracle:rules-storage-list-map-literals-and-slice` matches production verdict-for-verdict on all 6 cases. Pre-fix the evaluator clamped bounds JS-style and compared lists by reference identity; both fixed and pinned by `unit:rules.test.ts` JS-semantics guards.","observation:rules-storage-list-map-literals-and-slice","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.operator.eq","kind":"rules-construct","surface":"storage-rules","behavior":"operator.eq is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.gt","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.gt is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.operator.gt","kind":"rules-construct","surface":"firestore-rules","behavior":"operator.gt is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.gt","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"operator.gt is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.operator.gt","kind":"rules-construct","surface":"rtdb-rules","behavior":"operator.gt is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/database/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"operator.gt","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.gt is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage.operator.gt","kind":"rules-construct","surface":"storage-rules","behavior":"operator.gt is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.gte","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.gte is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.operator.gte","kind":"rules-construct","surface":"firestore-rules","behavior":"operator.gte is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.gte","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"operator.gte is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.operator.gte","kind":"rules-construct","surface":"rtdb-rules","behavior":"operator.gte is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/database/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"operator.gte","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.gte is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage.operator.gte","kind":"rules-construct","surface":"storage-rules","behavior":"operator.gte is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.in","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.in is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.operator.in","kind":"rules-construct","surface":"firestore-rules","behavior":"operator.in is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.in","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"operator.in is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"storage-rules#120","kind":"registry-row","surface":"storage-rules","behavior":"`in` on list literals (membership) and on maps (OWN-key membership) — prototype names (`toString`/`constructor`/`hasOwnProperty`) are never keys","status":"conforms","evidence":["NEW ROW, 2026-07-17: production capture proves `in` tests list membership and map OWN keys only — `'toString' in metadata` is false unless the map literally carries that key, for both custom-metadata maps and map literals. `oracle:rules-storage-in-membership-and-proto-keys` matches production verdict-for-verdict on all 8 cases. Pre-fix the evaluator used JS `in`, which walks the prototype chain and false-ALLOWed the proto-key cases (the same bug class the Firestore simulator fixed under RULES-B7); the own-key check now guards it, pinned by `unit:rules.test.ts` JS-semantics guards.","observation:rules-storage-in-membership-and-proto-keys","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.operator.in","kind":"rules-construct","surface":"storage-rules","behavior":"operator.in is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"operator.index","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.index is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.operator.index","kind":"rules-construct","surface":"firestore-rules","behavior":"operator.index is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.index","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"operator.index is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.operator.index","kind":"rules-construct","surface":"rtdb-rules","behavior":"operator.index is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/database/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"operator.index","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.index is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage.operator.index","kind":"rules-construct","surface":"storage-rules","behavior":"operator.index is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.is","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"operator.is is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["`int`/`float` division and type distinction (RULES-B5) in rules — truncating int÷int, float division stays float, div-by-zero denies, `is int`/`is float` distinct","`oracle:rules-firestore-int-float-and-division` — production Firestore Rules Test API verdicts for corpus scenario \"int-float-and-division\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator narrows a float-valued payload field toward int on the float-payload case, unlike production which preserves the float type — pinned KNOWN_DIVERGENCE"],"claims":[{"id":"firestore-rules#167","kind":"registry-row","surface":"firestore-rules","behavior":"`int`/`float` division and type distinction (RULES-B5) in rules — truncating int÷int, float division stays float, div-by-zero denies, `is int`/`is float` distinct","status":"diverged-documented","evidence":["`oracle:rules-firestore-int-float-and-division` — production Firestore Rules Test API verdicts for corpus scenario \"int-float-and-division\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator narrows a float-valued payload field toward int on the float-payload case, unlike production which preserves the float type — pinned KNOWN_DIVERGENCE","observation:rules-firestore-int-float-and-division","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"ineligible"},{"id":"firestore.operator.is","kind":"rules-construct","surface":"firestore-rules","behavior":"operator.is is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-conditions"],"assurance":"ineligible"}]},{"feature":"operator.is","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"operator.is is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"storage-rules#121","kind":"registry-row","surface":"storage-rules","behavior":"`is` type tests over the storage bindings (`size is int`, `contentType is string`, `metadata is map`, `split() is list`) and int/float LITERAL typing (`1.0 is float`, `1 is int`, cross checks false)","status":"conforms","evidence":["ROW CORRECTED, 2026-07-17 (same day): the evaluator now adopts the simulator's RULES-B5 float model — a `RulesFloat` wrapper tags float values (a numeric literal written with a decimal point converts to one) while a bare JS number means int — so `1.0 is float` / `!(1.0 is int)` type by literal form exactly as production does. `oracle:rules-storage-type-checks-is` now matches production verdict-for-verdict on all 3 cases with no knownGap abstentions. The prior same-day row recorded the value-typed divergence; that gap is closed.","observation:rules-storage-type-checks-is","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.operator.is","kind":"rules-construct","surface":"storage-rules","behavior":"operator.is is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"operator.looseEq","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"operator.looseEq is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.operator.looseEq","kind":"rules-construct","surface":"rtdb-rules","behavior":"operator.looseEq is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/database/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"operator.looseNeq","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"operator.looseNeq is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.operator.looseNeq","kind":"rules-construct","surface":"rtdb-rules","behavior":"operator.looseNeq is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/database/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"operator.lt","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.lt is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.operator.lt","kind":"rules-construct","surface":"firestore-rules","behavior":"operator.lt is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.lt","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"operator.lt is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.operator.lt","kind":"rules-construct","surface":"rtdb-rules","behavior":"operator.lt is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/database/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"operator.lt","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.lt is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage.operator.lt","kind":"rules-construct","surface":"storage-rules","behavior":"operator.lt is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.lte","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.lte is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.operator.lte","kind":"rules-construct","surface":"firestore-rules","behavior":"operator.lte is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.lte","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"operator.lte is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.operator.lte","kind":"rules-construct","surface":"rtdb-rules","behavior":"operator.lte is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/database/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"operator.lte","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.lte is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage.operator.lte","kind":"rules-construct","surface":"storage-rules","behavior":"operator.lte is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.member","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.member is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.operator.member","kind":"rules-construct","surface":"firestore-rules","behavior":"operator.member is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.member","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"operator.member is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.operator.member","kind":"rules-construct","surface":"rtdb-rules","behavior":"operator.member is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/database/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"operator.member","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.member is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage.operator.member","kind":"rules-construct","surface":"storage-rules","behavior":"operator.member is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.mod","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.mod is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.operator.mod","kind":"rules-construct","surface":"firestore-rules","behavior":"operator.mod is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.mod","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"operator.mod is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.operator.mod","kind":"rules-construct","surface":"rtdb-rules","behavior":"operator.mod is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/database/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"operator.mod","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"operator.mod is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"storage-rules#123","kind":"registry-row","surface":"storage-rules","behavior":"Float literals, `%`, unary minus, float division, negative-dividend modulo (`-7 % 2 == -1`), and TRUNCATING int division (`10 / 4 == 2`, `-7 / 2 == -3`)","status":"conforms","evidence":["ROW CORRECTED, 2026-07-17 (same day): with the RULES-B5 float model adopted from the simulator, int ÷ int truncates toward zero, float division stays float (re-tagged), and int-op-float promotes to float. `oracle:rules-storage-float-modulo-unary-minus` now matches production verdict-for-verdict on all 6 cases with no knownGap abstentions. An int zero divisor errors-and-denies; a float zero divisor follows the simulator's CEL-pinned ±Infinity/NaN. The prior same-day row recorded the truncation divergence; that gap is closed.","observation:rules-storage-float-modulo-unary-minus","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.operator.mod","kind":"rules-construct","surface":"storage-rules","behavior":"operator.mod is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"operator.mul","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.mul is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.operator.mul","kind":"rules-construct","surface":"firestore-rules","behavior":"operator.mul is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.mul","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"operator.mul is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.operator.mul","kind":"rules-construct","surface":"rtdb-rules","behavior":"operator.mul is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/database/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"operator.mul","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.mul is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#123","kind":"registry-row","surface":"storage-rules","behavior":"Float literals, `%`, unary minus, float division, negative-dividend modulo (`-7 % 2 == -1`), and TRUNCATING int division (`10 / 4 == 2`, `-7 / 2 == -3`)","status":"conforms","evidence":["ROW CORRECTED, 2026-07-17 (same day): with the RULES-B5 float model adopted from the simulator, int ÷ int truncates toward zero, float division stays float (re-tagged), and int-op-float promotes to float. `oracle:rules-storage-float-modulo-unary-minus` now matches production verdict-for-verdict on all 6 cases with no knownGap abstentions. An int zero divisor errors-and-denies; a float zero divisor follows the simulator's CEL-pinned ±Infinity/NaN. The prior same-day row recorded the truncation divergence; that gap is closed.","observation:rules-storage-float-modulo-unary-minus","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.operator.mul","kind":"rules-construct","surface":"storage-rules","behavior":"operator.mul is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.neg","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"operator.neg is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.operator.neg","kind":"rules-construct","surface":"rtdb-rules","behavior":"operator.neg is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/database/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"operator.neq","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.neq is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.operator.neq","kind":"rules-construct","surface":"firestore-rules","behavior":"operator.neq is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.neq","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.neq is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage.operator.neq","kind":"rules-construct","surface":"storage-rules","behavior":"operator.neq is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.not","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.not is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.operator.not","kind":"rules-construct","surface":"firestore-rules","behavior":"operator.not is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.not","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"operator.not is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.operator.not","kind":"rules-construct","surface":"rtdb-rules","behavior":"operator.not is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/database/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"operator.not","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.not is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage.operator.not","kind":"rules-construct","surface":"storage-rules","behavior":"operator.not is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.or","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.or is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#163","kind":"registry-row","surface":"firestore-rules","behavior":"CEL tri-state error absorption in `||`/`&&` (RULES-B3) — `error || true` → ALLOW, `error && false` → DENY, commutative absorption (not JS left-to-right short-circuit)","status":"conforms","evidence":["`oracle:rules-firestore-error-absorption-and-or` — production Firestore Rules Test API verdicts for corpus scenario \"error-absorption-and-or\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`; all cases match production.","observation:rules-firestore-error-absorption-and-or","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"firestore.operator.or","kind":"rules-construct","surface":"firestore-rules","behavior":"operator.or is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.or","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"operator.or is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.operator.or","kind":"rules-construct","surface":"rtdb-rules","behavior":"operator.or is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/database/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"operator.or","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.or is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#119","kind":"registry-row","surface":"storage-rules","behavior":"Ternary `?:` — branch selection, error-in-condition deny, and `error || true` absorption","status":"conforms","evidence":["NEW ROW, 2026-07-17: production capture proves the evaluator selects ternary branches by condition, denies when the CONDITION errors (even with identical `true` branches — production errors the whole conditional rather than falling through to a branch), and still absorbs the same error through `|| true`. `oracle:rules-storage-ternary-and-error-absorption` matches production verdict-for-verdict on all 5 cases. A division-by-zero in the condition previously yielded JS Infinity (no error) and false-ALLOWed the erroring-condition case; zero divisors now error-and-deny.","observation:rules-storage-ternary-and-error-absorption","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.operator.or","kind":"rules-construct","surface":"storage-rules","behavior":"operator.or is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.slice","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"operator.slice is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["Range-slice `[i:j]` syntax for `List` and `String` (Item 4) in rules","`oracle:rules-firestore-range-slice-list-and-string` — production Firestore Rules Test API verdicts for corpus scenario \"range-slice-list-and-string\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator clamps an out-of-bounds slice end to the collection length on both the list and string OOB-slice cases; production denies — pinned KNOWN_DIVERGENCE"],"claims":[{"id":"firestore-rules#173","kind":"registry-row","surface":"firestore-rules","behavior":"Range-slice `[i:j]` syntax for `List` and `String` (Item 4) in rules","status":"diverged-documented","evidence":["`oracle:rules-firestore-range-slice-list-and-string` — production Firestore Rules Test API verdicts for corpus scenario \"range-slice-list-and-string\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator clamps an out-of-bounds slice end to the collection length on both the list and string OOB-slice cases; production denies — pinned KNOWN_DIVERGENCE","observation:rules-firestore-range-slice-list-and-string","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"ineligible"},{"id":"firestore.operator.slice","kind":"rules-construct","surface":"firestore-rules","behavior":"operator.slice is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-conditions"],"assurance":"ineligible"}]},{"feature":"operator.slice","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"operator.slice is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"storage-rules#122","kind":"registry-row","surface":"storage-rules","behavior":"List/map literals, range-slice access `[i:j]` on lists and strings (out-of-range bounds ERROR, no JS clamp), and structural `==` on lists","status":"conforms","evidence":["NEW ROW, 2026-07-17: production capture proves slices evaluate on `split()` lists and on strings, that an out-of-range slice END errors and denies (production does NOT clamp to length the way JS `.slice()` does — same semantics the Firestore capture pinned in rules-firestore-range-slice-list-and-string), and that a slice compares equal to a list literal structurally. `oracle:rules-storage-list-map-literals-and-slice` matches production verdict-for-verdict on all 6 cases. Pre-fix the evaluator clamped bounds JS-style and compared lists by reference identity; both fixed and pinned by `unit:rules.test.ts` JS-semantics guards.","observation:rules-storage-list-map-literals-and-slice","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.operator.slice","kind":"rules-construct","surface":"storage-rules","behavior":"operator.slice is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"operator.strictEq","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"operator.strictEq is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.operator.strictEq","kind":"rules-construct","surface":"rtdb-rules","behavior":"operator.strictEq is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/database/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"operator.strictNeq","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"operator.strictNeq is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.operator.strictNeq","kind":"rules-construct","surface":"rtdb-rules","behavior":"operator.strictNeq is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/database/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"operator.sub","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.sub is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.operator.sub","kind":"rules-construct","surface":"firestore-rules","behavior":"operator.sub is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.sub","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"operator.sub is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.operator.sub","kind":"rules-construct","surface":"rtdb-rules","behavior":"operator.sub is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/database/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"operator.sub","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.sub is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage.operator.sub","kind":"rules-construct","surface":"storage-rules","behavior":"operator.sub is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.ternary","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.ternary is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.operator.ternary","kind":"rules-construct","surface":"firestore-rules","behavior":"operator.ternary is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.ternary","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"operator.ternary is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.operator.ternary","kind":"rules-construct","surface":"rtdb-rules","behavior":"operator.ternary is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/database/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"operator.ternary","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"operator.ternary is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"storage-rules#119","kind":"registry-row","surface":"storage-rules","behavior":"Ternary `?:` — branch selection, error-in-condition deny, and `error || true` absorption","status":"conforms","evidence":["NEW ROW, 2026-07-17: production capture proves the evaluator selects ternary branches by condition, denies when the CONDITION errors (even with identical `true` branches — production errors the whole conditional rather than falling through to a branch), and still absorbs the same error through `|| true`. `oracle:rules-storage-ternary-and-error-absorption` matches production verdict-for-verdict on all 5 cases. A division-by-zero in the condition previously yielded JS Infinity (no error) and false-ALLOWed the erroring-condition case; zero divisors now error-and-deny.","observation:rules-storage-ternary-and-error-absorption","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.operator.ternary","kind":"rules-construct","surface":"storage-rules","behavior":"operator.ternary is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"operator.unary-minus","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"operator.unary-minus is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.operator.unary-minus","kind":"rules-construct","surface":"firestore-rules","behavior":"operator.unary-minus is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"operator.unary-minus","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"operator.unary-minus is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"storage-rules#123","kind":"registry-row","surface":"storage-rules","behavior":"Float literals, `%`, unary minus, float division, negative-dividend modulo (`-7 % 2 == -1`), and TRUNCATING int division (`10 / 4 == 2`, `-7 / 2 == -3`)","status":"conforms","evidence":["ROW CORRECTED, 2026-07-17 (same day): with the RULES-B5 float model adopted from the simulator, int ÷ int truncates toward zero, float division stays float (re-tagged), and int-op-float promotes to float. `oracle:rules-storage-float-modulo-unary-minus` now matches production verdict-for-verdict on all 6 cases with no knownGap abstentions. An int zero divisor errors-and-denies; a float zero divisor follows the simulator's CEL-pinned ±Infinity/NaN. The prior same-day row recorded the truncation divergence; that gap is closed.","observation:rules-storage-float-modulo-unary-minus","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.operator.unary-minus","kind":"rules-construct","surface":"storage-rules","behavior":"operator.unary-minus is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"or","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"or is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:or","kind":"runtime-export","surface":"firestore","behavior":"or is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#56","kind":"registry-row","surface":"firestore","behavior":"`or(...)` composite — at least one sub-filter matches","status":"conforms","evidence":["`unit:sandbox-target.test.ts` (\"or() matches docs where any sub-filter matches\"), oracle: `packages/conformance/observations/firestore/firestore-or-composite.json` (4 seeded docs; `or(where('x','==',1), where('y','==',2))` returned the exact union `{match-both, match-x, match-y}` — no implicit index required against cloud Firestore)","observation:firestore-or-composite","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#58","kind":"registry-row","surface":"firestore","behavior":"Nested `or` / `and` — full composite tree","status":"conforms","evidence":["`unit:sandbox-target.test.ts` (\"nested or/and — the canonical composite pattern\"), oracle: `packages/conformance/observations/firestore/firestore-nested-or-and-composite.json` (6 seeded docs; `or(and(where('x','==',1), where('y','==',2)), where('z','==',3))` returned `{inner-and-match, outer-z-match, both-branches}` — exact boolean union as predicted)","observation:firestore-nested-or-and-composite","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#62","kind":"registry-row","surface":"firestore","behavior":"Composite filters AND with other constraints — `query(coll, or(...), orderBy(...), limit(...))`","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#63","kind":"registry-row","surface":"firestore","behavior":"Passing `orderBy` / `limit` into `or()` / `and()` → `TypeError`","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#64","kind":"registry-row","surface":"firestore","behavior":"Zero-arg `or()` / `and()` → `TypeError`","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"orderBy","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"orderBy is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:orderBy","kind":"runtime-export","surface":"firestore","behavior":"orderBy is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#54","kind":"registry-row","surface":"firestore","behavior":"`query(coll, where(…), orderBy(…), limit(…))` composes constraints in order","status":"conforms","evidence":["`unit:sandbox-target.test.ts`, `playground:firestore-query`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#59","kind":"registry-row","surface":"firestore","behavior":"`orderBy(field, 'asc'|'desc')` — direction parameter","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#59a","kind":"registry-row","surface":"firestore","behavior":"**Canonical type-order comparison (FS-B3)** — orderBy + range filters compare by Firestore's canonical type order (`null < bool < number < timestamp < string < bytes < ref < geopoint < array < map`), then within-type; numbers sort numerically (not lexicographically), NaN sorts as the smallest number, and range filters (`<`/`<=`/`>`/`>=`) only match same-type values. Pre-FS-B3 the comparator fell back to `String(a).localeCompare(String(b))`.","status":"conforms","evidence":["`unit:admin-compat/canonical-type-order.test.ts` (cross-type ranking, numeric sort, NaN, timestamps, arrays; verified failing pre-fix)","packages/pyric/test/sandbox/firestore/admin-compat/canonical-type-order.test.ts"],"assurance":"eligible"},{"id":"firestore#59b","kind":"registry-row","surface":"firestore","behavior":"**orderBy excludes missing-field docs (FS-B3)** — a doc lacking an orderBy field is omitted from the result (matches prod); pre-fix it was sorted in via `compareValues(undefined, …)`.","status":"conforms","evidence":["`unit:admin-compat/canonical-type-order.test.ts` (\"excludes the missing-field doc\")","packages/pyric/test/sandbox/firestore/admin-compat/canonical-type-order.test.ts"],"assurance":"eligible"},{"id":"firestore#59c","kind":"registry-row","surface":"firestore","behavior":"**Implicit orderBy + `__name__` tiebreak (FS-B8)** — the query's sort is normalized to: explicit orderBy clauses, then an implicit order on each inequality-filtered field, then a final document-key (`__name__`) clause. Equal-valued docs sort deterministically by key; a `where('x','>',v)` with no explicit orderBy returns docs ordered by `x`. Mirrors `clones/.../core/query.ts:queryNormalizedOrderBy`. Pre-FS-B8 equal-valued docs were nondeterministic and inequality results came back in insertion order.","status":"conforms","evidence":["`unit:admin-compat/implicit-order-name.test.ts` (key tiebreak, snapshot-cursor disambiguation, implicit inequality order; verified failing pre-fix)","packages/pyric/test/sandbox/firestore/admin-compat/implicit-order-name.test.ts"],"assurance":"eligible"},{"id":"firestore#62","kind":"registry-row","surface":"firestore","behavior":"Composite filters AND with other constraints — `query(coll, or(...), orderBy(...), limit(...))`","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#63","kind":"registry-row","surface":"firestore","behavior":"Passing `orderBy` / `limit` into `or()` / `and()` → `TypeError`","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#65","kind":"registry-row","surface":"firestore","behavior":"Chained queries re-tag for further constraints (`query(query(coll, where), orderBy)`)","status":"conforms","evidence":["`unit:sandbox-target.test.ts` (\"chained queries are taggable\")","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"orderByChild","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"orderByChild is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"database:runtime:orderByChild","kind":"runtime-export","surface":"database","behavior":"orderByChild is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#142","kind":"registry-row","surface":"rtdb-modular","behavior":"`query(ref, orderByChild('field'), limitToFirst(N))` returns a `Query` whose `get()` resolves a snapshot containing N children ordered by `field`","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-query-orderbychild-limit.json` — seeded 4 children with positions `[3,1,4,2]`, observed `orderedKeys: [{key:'a',pos:1}, {key:'b',pos:2}]` (first 2 in ascending order). Requires `.indexOn` declared in rules.","observation:rtdb-modular-orderbychild-window","observation:rtdb-modular-query-orderbychild-limit"],"assurance":"eligible"},{"id":"rtdb-modular#M49","kind":"registry-row","surface":"rtdb-modular","behavior":"`query(ref, orderByChild(p), startAt(v), endAt(w))` window is BOTH-INCLUSIVE — children whose ordered field === `v` or === `w` are included","status":"conforms","evidence":["`unit:upstream-rtdb-probes.test.ts` (deep orderByChild nested path) + `unit:modular/queries.test.ts` (\"returns children whose ordered child is within [startAt, endAt] inclusive\"); matches oracle `rtdb-modular-orderbychild-window.json`","observation:rtdb-modular-orderbychild-window","packages/pyric/test/database/upstream-rtdb-probes.test.ts","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M52","kind":"registry-row","surface":"rtdb-modular","behavior":"`orderByChild(p) + equalTo(v)` returns ALL children whose field at `p` === `v` — no uniqueness enforced","status":"conforms","evidence":["Sandbox aligned: `unit:modular/queries.test.ts` (\"returns ALL children whose ordered field === the supplied value\"); matches oracle observation `packages/conformance/observations/rtdb-modular/rtdb-modular-equalTo-filter.json` (both 'b'-grouped children returned).","observation:rtdb-modular-equalTo-filter","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M63","kind":"registry-row","surface":"rtdb-modular","behavior":"`orderByChild('p')` on children missing the field treats their value as `null` (sorts FIRST per RTDB's type ordering)","status":"conforms","evidence":["`unit:modular/queries.test.ts` (\"orderByChild on a missing child path treats those children as null\")","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"}]},{"feature":"OrderByDirection","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"OrderByDirection is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:OrderByDirection","kind":"type-export","surface":"firestore","behavior":"OrderByDirection is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"orderByKey","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"orderByKey is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"database:runtime:orderByKey","kind":"runtime-export","surface":"database","behavior":"orderByKey is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#143","kind":"registry-row","surface":"rtdb-modular","behavior":"`orderByKey()` orders by the auto-id / numeric key","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-orderbykey-window.json` — seeded `{a,b,c,d,e}` in shuffled insertion order, observed `matchedKeys: ['b','c','d']` for `orderByKey() + startAt('b') + endAt('d')` (in key order).","observation:rtdb-modular-orderbykey-window"],"assurance":"eligible"},{"id":"rtdb-modular#M50","kind":"registry-row","surface":"rtdb-modular","behavior":"`orderByKey()` orders children by RTDB `nameCompare` — integer-looking keys sort numerically FIRST (so `['1','2','10']`, not the lexicographic `['1','10','2']`), then non-integer keys lexicographically; `startAt`/`endAt` cursors + the optional `key` tie-breaker use the same order (DB-B4)","status":"conforms","evidence":["`unit:upstream-rtdb-probes.test.ts` (INT32 overflow/underflow cursors) + `unit:modular/queries.test.ts` + `unit:modular/name-compare.test.ts`; matches oracle `rtdb-modular-orderbykey-window.json` and upstream `core/util/util.ts:253-276`","packages/pyric/test/database/upstream-rtdb-probes.test.ts","packages/pyric/test/database/modular/name-compare.test.ts","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"}]},{"feature":"orderByPriority","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"orderByPriority is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Firebase's legacy priority ordering system is absent; the sandbox exposes orderByChild/Key/Value only today. Priority ordering is data-modelable as a sort key, so this is revisitable scope rather than a hard sandbox limitation."],"claims":[{"id":"database:runtime:orderByPriority","kind":"runtime-export","surface":"database","behavior":"Firebase's legacy priority ordering system is absent; the sandbox exposes orderByChild/Key/Value only today. Priority ordering is data-modelable as a sort key, so this is revisitable scope rather than a hard sandbox limitation.","status":"deferred","evidence":["upstream:firebase/database"],"assurance":"not-applicable"}]},{"feature":"orderByValue","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"orderByValue is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"database:runtime:orderByValue","kind":"runtime-export","surface":"database","behavior":"orderByValue is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#144","kind":"registry-row","surface":"rtdb-modular","behavior":"`orderByValue()` orders by the primitive value of each child (for collections of primitives)","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-orderbyvalue-numeric.json` — seeded `{alice:30, bob:10, carol:50, dave:20, eve:40}`, the prod call threw `Index not defined, add \".indexOn\": \".value\"` (so prod enforces an index requirement on `orderByValue()`); semantic ordering claim still holds, sandbox does not enforce indexes.","observation:rtdb-modular-orderbyvalue-numeric"],"assurance":"eligible"},{"id":"rtdb-modular#M51","kind":"registry-row","surface":"rtdb-modular","behavior":"`orderByValue()` orders primitive children by their value; `limitToFirst(N)` returns the N smallest, ascending","status":"conforms","evidence":["Sandbox aligned: `unit:modular/queries.test.ts` (\"returns the limitToFirst(N) smallest values, ascending\"). Oracle observation `packages/conformance/observations/rtdb-modular/rtdb-modular-orderbyvalue-numeric.json` shows prod threw `Index not defined` against blockingfun — the sandbox does NOT enforce `.indexOn` (rules-engine integration for query indexes is deferred); the semantic claim (ordering by value) is locked here.","observation:rtdb-modular-orderbyvalue-numeric","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"}]},{"feature":"Outcome","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"Outcome is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:Outcome","kind":"runtime-export","surface":"ai","behavior":"Outcome is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:Outcome","kind":"type-export","surface":"ai","behavior":"Outcome is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"parent","surface":"rtdb","importPaths":[],"evidenceSlug":"database-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"parent is available, has unverified fidelity, and is qualified for assurance.","caveats":["`ref(db, path)` returns a tagged `DatabaseReference` carrying `key`, `parent`, `root`, `toString()`","upstream `firebase/database` contract","`ref(db)` with no path returns the root ref (`key === null`, `parent === null`)","upstream contract","`ref.parent` is `null` at root, otherwise the parent ref"],"claims":[{"id":"rtdb-modular#100","kind":"registry-row","surface":"rtdb-modular","behavior":"`ref(db, path)` returns a tagged `DatabaseReference` carrying `key`, `parent`, `root`, `toString()`","status":"unverified","evidence":["upstream `firebase/database` contract"],"assurance":"qualified"},{"id":"rtdb-modular#101","kind":"registry-row","surface":"rtdb-modular","behavior":"`ref(db)` with no path returns the root ref (`key === null`, `parent === null`)","status":"unverified","evidence":["upstream contract"],"assurance":"qualified"},{"id":"rtdb-modular#103","kind":"registry-row","surface":"rtdb-modular","behavior":"`ref.parent` is `null` at root, otherwise the parent ref","status":"unverified","evidence":["upstream contract"],"assurance":"qualified"},{"id":"rtdb-modular#M41","kind":"registry-row","surface":"rtdb-modular","behavior":"`onChildAdded` replays each existing direct child of the parent ref on subscribe (one fire per existing key)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-child-events.test.ts` (\"replays existing direct children on subscribe — one fire per key\"); matches oracle observation `packages/conformance/observations/rtdb-modular/rtdb-modular-onchildadded-initial-replay.json` (seeded `{k1,k2,k3}`, observed `firedKeys: ['k1','k2','k3']`).","observation:rtdb-modular-onchildadded-initial-replay","packages/pyric/test/database/modular/sandbox-child-events.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M5","kind":"registry-row","surface":"rtdb-modular","behavior":"`child(ref, 'sub/path')` composes paths; result inherits the parent's target","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"child(ref, 'sub') composes paths\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M6","kind":"registry-row","surface":"rtdb-modular","behavior":"`ref.parent` returns the parent ref; `root.parent === null`","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"ref.parent returns the parent ref; root.parent is null\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"parseActionCodeURL","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"parseActionCodeURL is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:parseActionCodeURL","kind":"runtime-export","surface":"auth","behavior":"parseActionCodeURL is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#150","kind":"registry-row","surface":"auth","behavior":"Parses an out-of-band action link. The `mode` query param maps to a NORMALIZED operation (`mode=resetPassword` -> `PASSWORD_RESET`, `mode=signIn` -> `EMAIL_SIGNIN`), `oobCode` surfaces as `code`, `lang` as `languageCode`, and `continueUrl` comes out URL-DECODED. A link missing `mode`, missing `oobCode`, carrying an unknown mode, or that is not a URL at all parses to `null` — the parse NEVER throws. `parseActionCodeURL` and `ActionCodeURL.parseLink` agree.","status":"conforms","evidence":["ORACLE-BACKED and project-independent: this is a PURE client-side parse (no network, no project, no mailbox), so the sandbox owes prod an exact match and there is no room for a divergence. Oracle: `auth-actioncodeurl-parse` against firebase-js-sdk 12.13.0. Replayed in `unit:oracle-conformance.test.ts`.","observation:auth-actioncodeurl-parse","packages/pyric/test/auth/oracle-conformance.test.ts","packages/pyric/test/auth/sandbox-email-link.test.ts"],"assurance":"eligible"}]},{"feature":"ParsedToken","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"ParsedToken is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:ParsedToken","kind":"type-export","surface":"auth","behavior":"ParsedToken is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"parseLink","surface":"auth","importPaths":[],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"parseLink is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth#150","kind":"registry-row","surface":"auth","behavior":"Parses an out-of-band action link. The `mode` query param maps to a NORMALIZED operation (`mode=resetPassword` -> `PASSWORD_RESET`, `mode=signIn` -> `EMAIL_SIGNIN`), `oobCode` surfaces as `code`, `lang` as `languageCode`, and `continueUrl` comes out URL-DECODED. A link missing `mode`, missing `oobCode`, carrying an unknown mode, or that is not a URL at all parses to `null` — the parse NEVER throws. `parseActionCodeURL` and `ActionCodeURL.parseLink` agree.","status":"conforms","evidence":["ORACLE-BACKED and project-independent: this is a PURE client-side parse (no network, no project, no mailbox), so the sandbox owes prod an exact match and there is no room for a divergence. Oracle: `auth-actioncodeurl-parse` against firebase-js-sdk 12.13.0. Replayed in `unit:oracle-conformance.test.ts`.","observation:auth-actioncodeurl-parse","packages/pyric/test/auth/oracle-conformance.test.ts","packages/pyric/test/auth/sandbox-email-link.test.ts"],"assurance":"eligible"}]},{"feature":"parseStorageRules","surface":"storage-rules","importPaths":["pyric/storage"],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"parseStorageRules is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#94","kind":"registry-row","surface":"storage-rules","behavior":"`parseStorageRules(source)` returns an opaque handle","status":"conforms","evidence":["`unit:rules.test.ts` (\"parses the canonical session-archive ruleset\")","packages/pyric/test/storage/rules.test.ts"],"assurance":"eligible"},{"id":"storage-rules#95","kind":"registry-row","surface":"storage-rules","behavior":"`parseStorageRules` rejects non-`firebase.storage` service headers","status":"conforms","evidence":["`unit:rules.test.ts` (\"rejects unknown service header\")","packages/pyric/test/storage/rules.test.ts"],"assurance":"eligible"},{"id":"storage-rules#97","kind":"registry-row","surface":"storage-rules","behavior":"`parseStorageRules` rejects unterminated string literals with `SyntaxError`","status":"conforms","evidence":["`unit:rules.test.ts` (\"rejects unterminated strings\")","packages/pyric/test/storage/rules.test.ts"],"assurance":"eligible"}]},{"feature":"Part","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"Part is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:Part","kind":"type-export","surface":"ai","behavior":"Part is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"PartialWithFieldValue","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"PartialWithFieldValue is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:PartialWithFieldValue","kind":"type-export","surface":"firestore","behavior":"PartialWithFieldValue is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"PasswordPolicy","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"PasswordPolicy is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"auth:type:PasswordPolicy","kind":"type-export","surface":"auth","behavior":"PasswordPolicy is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"PasswordValidationStatus","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"PasswordValidationStatus is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"auth:type:PasswordValidationStatus","kind":"type-export","surface":"auth","behavior":"PasswordValidationStatus is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"path.bind","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"path.bind is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["`Path` wrapper, `path()` constructor, and `Path.bind()` (Item 5.4) in rules","`oracle:rules-firestore-path-constructor-and-bind` — production Firestore Rules Test API verdicts for corpus scenario \"path-constructor-and-bind\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator treats `path()` as idempotent on an already-Path argument where production denies — pinned KNOWN_DIVERGENCE"],"claims":[{"id":"firestore-rules#171","kind":"registry-row","surface":"firestore-rules","behavior":"`Path` wrapper, `path()` constructor, and `Path.bind()` (Item 5.4) in rules","status":"diverged-documented","evidence":["`oracle:rules-firestore-path-constructor-and-bind` — production Firestore Rules Test API verdicts for corpus scenario \"path-constructor-and-bind\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator treats `path()` as idempotent on an already-Path argument where production denies — pinned KNOWN_DIVERGENCE","observation:rules-firestore-path-constructor-and-bind","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"ineligible"},{"id":"firestore.method.path.bind","kind":"rules-construct","surface":"firestore-rules","behavior":"path.bind is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.Path#function_bind_"],"assurance":"ineligible"}]},{"feature":"pathParameters","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"pathParameters is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#103","kind":"registry-row","surface":"storage-rules","behavior":"Path-parameter binding (`{sessionId}`) accessible inside the `if` expression","status":"conforms","evidence":["`unit:rules.test.ts`","packages/pyric/test/storage/rules.test.ts"],"assurance":"eligible"}]},{"feature":"path-variable","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"path-variable is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.binding.path-variable","kind":"rules-construct","surface":"firestore-rules","behavior":"path-variable is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-structure#hierarchical_data"],"assurance":"eligible"}]},{"feature":"path-variable","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"path-variable is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.binding.path-variable","kind":"rules-construct","surface":"rtdb-rules","behavior":"path-variable is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/database/security/core-syntax#variables"],"assurance":"qualified"}]},{"feature":"path-variable","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"path-variable is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage.binding.path-variable","kind":"rules-construct","surface":"storage-rules","behavior":"path-variable is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"pathVariables","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"pathVariables is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"rtdb-rules#2","kind":"registry-row","surface":"rtdb-rules","behavior":"`$uid` path-variable ownership (`$uid === auth.uid`) — the owner path allows, a foreign uid and an anonymous request deny","status":"conforms","evidence":["`oracle:rules-rtdb-r2-own-uid` — production verdicts captured by deploy-observe-restore, replayed verdict-for-verdict against the in-process simulator; all 5 cases match production, so the simulator binds the path variable against `auth.uid` exactly as production does.","observation:rules-rtdb-r2-own-uid","packages/pyric/test/rules/rtdb/rules-conformance.test.ts"],"assurance":"eligible"},{"id":"rtdb-rules#7","kind":"registry-row","surface":"rtdb-rules","behavior":"Nested path variable in an expression (`$sessionId === auth.uid`) — the matching session allows, a mismatched session denies, and an unmatched anonymous op denies with no matching rule","status":"conforms","evidence":["`oracle:rules-rtdb-r7-pathvar-binding` — production verdicts captured by deploy-observe-restore, replayed verdict-for-verdict; all 4 cases match. The simulator binds the nested variable identically and returns NO_MATCHING_RULE (read as deny) where production denies for want of a rule.","observation:rules-rtdb-r7-pathvar-binding","packages/pyric/test/rules/rtdb/rules-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"Persistence","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"Persistence is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"auth:type:Persistence","kind":"type-export","surface":"auth","behavior":"Persistence is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"PersistenceSettings","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"PersistenceSettings is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"firestore:type:PersistenceSettings","kind":"type-export","surface":"firestore","behavior":"PersistenceSettings is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"PersistentCacheIndexManager","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"PersistentCacheIndexManager is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Index-tuning / GC-policy APIs have no real knob to turn in an in-memory sandbox today, but sibling cache-factory tokens are already honest inert tokens; these are buildable the same way and not genuinely out of scope.","Public type export is not mirrored."],"claims":[{"id":"firestore:runtime:PersistentCacheIndexManager","kind":"runtime-export","surface":"firestore","behavior":"Index-tuning / GC-policy APIs have no real knob to turn in an in-memory sandbox today, but sibling cache-factory tokens are already honest inert tokens; these are buildable the same way and not genuinely out of scope.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"},{"id":"firestore:type:PersistentCacheIndexManager","kind":"type-export","surface":"firestore","behavior":"PersistentCacheIndexManager is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"PersistentCacheSettings","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"PersistentCacheSettings is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:PersistentCacheSettings","kind":"type-export","surface":"firestore","behavior":"PersistentCacheSettings is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"persistentLocalCache","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"persistentLocalCache is available, has diverged fidelity, and is qualified for assurance.","caveats":["Config token accepted, inert — each returns a small tagged object so identity/usage doesn't crash. Persistence is the sandbox default; there is no cache tier left to configure","`unit:firestore/tier1-cache-init-align.test.ts`"],"claims":[{"id":"firestore:runtime:persistentLocalCache","kind":"runtime-export","surface":"firestore","behavior":"persistentLocalCache is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#146","kind":"registry-row","surface":"firestore","behavior":"Config token accepted, inert — each returns a small tagged object so identity/usage doesn't crash. Persistence is the sandbox default; there is no cache tier left to configure","status":"diverged-documented","evidence":["`unit:firestore/tier1-cache-init-align.test.ts`","packages/pyric/test/firestore/tier1-cache-init-align.test.ts"],"assurance":"qualified"}]},{"feature":"PersistentLocalCache","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"PersistentLocalCache is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:PersistentLocalCache","kind":"type-export","surface":"firestore","behavior":"PersistentLocalCache is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"persistentMultipleTabManager","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"persistentMultipleTabManager is available, has diverged fidelity, and is qualified for assurance.","caveats":["Config token accepted, inert — each returns a small tagged object so identity/usage doesn't crash. Persistence is the sandbox default; there is no cache tier left to configure","`unit:firestore/tier1-cache-init-align.test.ts`"],"claims":[{"id":"firestore:runtime:persistentMultipleTabManager","kind":"runtime-export","surface":"firestore","behavior":"persistentMultipleTabManager is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#146","kind":"registry-row","surface":"firestore","behavior":"Config token accepted, inert — each returns a small tagged object so identity/usage doesn't crash. Persistence is the sandbox default; there is no cache tier left to configure","status":"diverged-documented","evidence":["`unit:firestore/tier1-cache-init-align.test.ts`","packages/pyric/test/firestore/tier1-cache-init-align.test.ts"],"assurance":"qualified"}]},{"feature":"PersistentMultipleTabManager","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"PersistentMultipleTabManager is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:PersistentMultipleTabManager","kind":"type-export","surface":"firestore","behavior":"PersistentMultipleTabManager is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"persistentSingleTabManager","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"persistentSingleTabManager is available, has diverged fidelity, and is qualified for assurance.","caveats":["Config token accepted, inert — each returns a small tagged object so identity/usage doesn't crash. Persistence is the sandbox default; there is no cache tier left to configure","`unit:firestore/tier1-cache-init-align.test.ts`"],"claims":[{"id":"firestore:runtime:persistentSingleTabManager","kind":"runtime-export","surface":"firestore","behavior":"persistentSingleTabManager is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#146","kind":"registry-row","surface":"firestore","behavior":"Config token accepted, inert — each returns a small tagged object so identity/usage doesn't crash. Persistence is the sandbox default; there is no cache tier left to configure","status":"diverged-documented","evidence":["`unit:firestore/tier1-cache-init-align.test.ts`","packages/pyric/test/firestore/tier1-cache-init-align.test.ts"],"assurance":"qualified"}]},{"feature":"PersistentSingleTabManager","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"PersistentSingleTabManager is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:PersistentSingleTabManager","kind":"type-export","surface":"firestore","behavior":"PersistentSingleTabManager is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"PersistentSingleTabManagerSettings","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"PersistentSingleTabManagerSettings is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:PersistentSingleTabManagerSettings","kind":"type-export","surface":"firestore","behavior":"PersistentSingleTabManagerSettings is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"PersistentTabManager","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"PersistentTabManager is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"firestore:type:PersistentTabManager","kind":"type-export","surface":"firestore","behavior":"PersistentTabManager is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"PhoneAuthCredential","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"PhoneAuthCredential is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["MFA / phone / reCAPTCHA is deferred, not out of scope — reCAPTCHA/SMS are external infrastructure Pyric can mock with the OAuth resolver pattern, and TOTP is pure algorithm work.","Public type export is not mirrored."],"claims":[{"id":"auth:runtime:PhoneAuthCredential","kind":"runtime-export","surface":"auth","behavior":"MFA / phone / reCAPTCHA is deferred, not out of scope — reCAPTCHA/SMS are external infrastructure Pyric can mock with the OAuth resolver pattern, and TOTP is pure algorithm work.","status":"deferred","evidence":["registry:auth#180"],"assurance":"not-applicable"},{"id":"auth:type:PhoneAuthCredential","kind":"type-export","surface":"auth","behavior":"PhoneAuthCredential is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"PhoneAuthProvider","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"PhoneAuthProvider is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["MFA / phone / reCAPTCHA is deferred, not out of scope — reCAPTCHA/SMS are external infrastructure Pyric can mock with the OAuth resolver pattern, and TOTP is pure algorithm work.","Public type export is not mirrored."],"claims":[{"id":"auth:runtime:PhoneAuthProvider","kind":"runtime-export","surface":"auth","behavior":"MFA / phone / reCAPTCHA is deferred, not out of scope — reCAPTCHA/SMS are external infrastructure Pyric can mock with the OAuth resolver pattern, and TOTP is pure algorithm work.","status":"deferred","evidence":["registry:auth#180"],"assurance":"not-applicable"},{"id":"auth:type:PhoneAuthProvider","kind":"type-export","surface":"auth","behavior":"PhoneAuthProvider is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"PhoneInfoOptions","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"PhoneInfoOptions is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:PhoneInfoOptions","kind":"type-export","surface":"auth","behavior":"PhoneInfoOptions is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"PhoneMultiFactorAssertion","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"PhoneMultiFactorAssertion is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:PhoneMultiFactorAssertion","kind":"type-export","surface":"auth","behavior":"PhoneMultiFactorAssertion is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"PhoneMultiFactorEnrollInfoOptions","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"PhoneMultiFactorEnrollInfoOptions is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:PhoneMultiFactorEnrollInfoOptions","kind":"type-export","surface":"auth","behavior":"PhoneMultiFactorEnrollInfoOptions is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"PhoneMultiFactorGenerator","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"PhoneMultiFactorGenerator is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["MFA / phone / reCAPTCHA is deferred, not out of scope — reCAPTCHA/SMS are external infrastructure Pyric can mock with the OAuth resolver pattern, and TOTP is pure algorithm work.","Public type export is not mirrored."],"claims":[{"id":"auth:runtime:PhoneMultiFactorGenerator","kind":"runtime-export","surface":"auth","behavior":"MFA / phone / reCAPTCHA is deferred, not out of scope — reCAPTCHA/SMS are external infrastructure Pyric can mock with the OAuth resolver pattern, and TOTP is pure algorithm work.","status":"deferred","evidence":["registry:auth#180"],"assurance":"not-applicable"},{"id":"auth:type:PhoneMultiFactorGenerator","kind":"type-export","surface":"auth","behavior":"PhoneMultiFactorGenerator is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"PhoneMultiFactorInfo","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"PhoneMultiFactorInfo is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:PhoneMultiFactorInfo","kind":"type-export","surface":"auth","behavior":"PhoneMultiFactorInfo is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"PhoneMultiFactorSignInInfoOptions","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"PhoneMultiFactorSignInInfoOptions is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:PhoneMultiFactorSignInInfoOptions","kind":"type-export","surface":"auth","behavior":"PhoneMultiFactorSignInInfoOptions is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"PhoneSingleFactorInfoOptions","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"PhoneSingleFactorInfoOptions is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:PhoneSingleFactorInfoOptions","kind":"type-export","surface":"auth","behavior":"PhoneSingleFactorInfoOptions is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"policies","surface":"rtdb","importPaths":[],"evidenceSlug":"database-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"policies is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"rtdb#85","kind":"registry-row","surface":"rtdb","behavior":"`policies` exports composite predicates that compose atoms: `pathOwnerOnly`, `fieldOwnerOnly`, `ownerOrNew`, `hasRole`, `isMember`, `required`, `transition`","status":"conforms","evidence":["`unit:constraints/policies.test.ts`","packages/pyric/test/rules/rtdb/constraints/policies.test.ts"],"assurance":"eligible"}]},{"feature":"PopupRedirectResolver","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"PopupRedirectResolver is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:PopupRedirectResolver","kind":"type-export","surface":"auth","behavior":"PopupRedirectResolver is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"POSSIBLE_ROLES","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"POSSIBLE_ROLES is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"ai:runtime:POSSIBLE_ROLES","kind":"runtime-export","surface":"ai","behavior":"POSSIBLE_ROLES is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai#chat-role-vocabulary","kind":"registry-row","surface":"ai","behavior":"`POSSIBLE_ROLES` is exactly `[\"user\", \"model\", \"function\", \"system\"]`","status":"conforms","evidence":["`unit:chat-session.test.ts` test `ai#chat-role-vocabulary` (upstream constant; distinct from the production wire role vocabulary in ai-error-bad-role)","packages/pyric/test/ai/chat-session.test.ts"],"assurance":"eligible"}]},{"feature":"PrebuiltVoiceConfig","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"PrebuiltVoiceConfig is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:PrebuiltVoiceConfig","kind":"type-export","surface":"ai","behavior":"PrebuiltVoiceConfig is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"Primitive","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"Primitive is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:Primitive","kind":"type-export","surface":"firestore","behavior":"Primitive is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"prodErrorMap","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"prodErrorMap is available, has diverged fidelity, and is qualified for assurance.","caveats":["Inert configuration tokens, accepted so the idiomatic `initializeAuth(app, { persistence: indexedDBLocalPersistence })` and `setPersistence(auth, browserCookiePersistence)` compile, run, and behave identically. The `.type` discriminant matches upstream exactly (`NONE` / `SESSION` / `LOCAL` / `LOCAL` / `COOKIE`) because consumer code branches on it. `browserPopupRedirectResolver` is accepted and ignored — the sandbox has its own first-class pluggable equivalent (`sandbox.setAuthFlowResolver`). `prodErrorMap` is accepted and DELIBERATELY not honored: installing it upstream strips error messages, and doing that in a sandbox whose purpose is to tell a developer what went wrong would be actively hostile.","In an in-memory sandbox the persistence CHOICE has no observable consequence, so accepting the token and recording the mode is the honest behavior — the same inert-token pattern `pyric/firestore` uses for its cache-factory tokens. `unit:types.test.ts` + `unit:sandbox-email-link.test.ts` cover the exports. Oracle caveat recorded on auth#172: the `persistenceTypes` block of `auth-mechanical-surface-constants` reports `NONE` for every token including `browserLocalPersistence` — a Node-build stub artifact, not the browser contract, so the `.type` values here follow the documented `Persistence.type` union instead."],"claims":[{"id":"auth:runtime:prodErrorMap","kind":"runtime-export","surface":"auth","behavior":"prodErrorMap is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#178","kind":"registry-row","surface":"auth","behavior":"Inert configuration tokens, accepted so the idiomatic `initializeAuth(app, { persistence: indexedDBLocalPersistence })` and `setPersistence(auth, browserCookiePersistence)` compile, run, and behave identically. The `.type` discriminant matches upstream exactly (`NONE` / `SESSION` / `LOCAL` / `LOCAL` / `COOKIE`) because consumer code branches on it. `browserPopupRedirectResolver` is accepted and ignored — the sandbox has its own first-class pluggable equivalent (`sandbox.setAuthFlowResolver`). `prodErrorMap` is accepted and DELIBERATELY not honored: installing it upstream strips error messages, and doing that in a sandbox whose purpose is to tell a developer what went wrong would be actively hostile.","status":"diverged-documented","evidence":["In an in-memory sandbox the persistence CHOICE has no observable consequence, so accepting the token and recording the mode is the honest behavior — the same inert-token pattern `pyric/firestore` uses for its cache-factory tokens. `unit:types.test.ts` + `unit:sandbox-email-link.test.ts` cover the exports. Oracle caveat recorded on auth#172: the `persistenceTypes` block of `auth-mechanical-surface-constants` reports `NONE` for every token including `browserLocalPersistence` — a Node-build stub artifact, not the browser contract, so the `.type` values here follow the documented `Persistence.type` union instead.","packages/pyric/test/auth/types.test.ts","packages/pyric/test/auth/sandbox-email-link.test.ts"],"assurance":"qualified"}]},{"feature":"PromptFeedback","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"PromptFeedback is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:PromptFeedback","kind":"type-export","surface":"ai","behavior":"PromptFeedback is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"providerData","surface":"auth","importPaths":[],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"providerData is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth#182","kind":"registry-row","surface":"auth","behavior":"One entry PER LINKED PROVIDER, read from the identity's stored record. Previously the sandbox synthesized a single `{providerId: 'password'}` entry for EVERY non-anonymous user, so a Google popup sign-in reported its provider as `'password'` and a linked account could never show more than one. Consumer code branches on this array (that is what it is for — 'is this account linked to Google?'), so the synthesized version was actively misleading. Empty for anonymous users; after `unlink` of the last provider it is genuinely empty (it does not resurrect the removed provider).","status":"conforms","evidence":["Was a BUG until this climb, and worth naming as one: the array was fabricated, not read. Now fixed and locked. `unit:sandbox-linking-reauth.test.ts` now pins that a Google link surfaces `google.com` in `providerData`, that `unlink` shrinks it, and that unlinking the last provider leaves it empty rather than falling back to a synthesized `'password'` entry.","packages/pyric/test/auth/sandbox-linking-reauth.test.ts"],"assurance":"eligible"}]},{"feature":"ProviderId","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"ProviderId is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:ProviderId","kind":"runtime-export","surface":"auth","behavior":"ProviderId is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#172","kind":"registry-row","surface":"auth","behavior":"The constant maps, value for value. `OperationType.SIGN_IN === 'signIn'`, `SignInMethod.EMAIL_LINK === 'emailLink'`, `ProviderId.GOOGLE === 'google.com'`, `ActionCodeOperation.PASSWORD_RESET === 'PASSWORD_RESET'`, and the 106-entry `AuthErrorCodes` map (`INVALID_OOB_CODE === 'auth/invalid-action-code'`, `PROVIDER_ALREADY_LINKED === 'auth/provider-already-linked'`, `NO_SUCH_PROVIDER === 'auth/no-such-provider'`, `USER_MISMATCH === 'auth/user-mismatch'`, …).","status":"conforms","evidence":["ORACLE-BACKED, snapshotted straight from the shipped SDK: `auth-mechanical-surface-constants` against firebase-js-sdk 12.13.0, replayed value-for-value in `unit:oracle-conformance.test.ts`. This matters more than it looks: consumer code COMPARES against these constants, so a mirror that got a string wrong would turn every such comparison into a silent `false` — a worse failure than the export simply being absent, because it typechecks and runs. NOTE: the capture's `persistenceTypes` block is deliberately NOT asserted — the harness runs under Node, where firebase/auth stubs the browser-only persistence tokens to `type: 'NONE'` (it reports 'NONE' even for `browserLocalPersistence`, which is unambiguously 'LOCAL'); asserting it would be asserting a harness artifact. See auth#178.","observation:auth-mechanical-surface-constants","packages/pyric/test/auth/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"push","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"push is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"database:runtime:push","kind":"runtime-export","surface":"database","behavior":"push is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#124","kind":"registry-row","surface":"rtdb-modular","behavior":"`push(ref).key` is a 20-char string starting with `-`, available **synchronously** (client-side mint, no server round-trip required)","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb/rtdb-push-autoid-format.json`","observation:rtdb-push-autoid-format"],"assurance":"eligible"},{"id":"rtdb-modular#125","kind":"registry-row","surface":"rtdb-modular","behavior":"Sequential `push` calls produce monotonically-sortable keys (timestamp-prefixed for chronological ordering via `orderByKey`)","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb/rtdb-push-autoid-format.json`","observation:rtdb-push-autoid-format"],"assurance":"eligible"},{"id":"rtdb-modular#126","kind":"registry-row","surface":"rtdb-modular","behavior":"`push(ref, value)` writes the value AND returns the new child ref (both behaviors in one call); `push(ref)` mints the ref without writing","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-push-with-value.json` — `await push(parent, {hello:'world'})` returned a ref with a 20-char key; subsequent `get(r)` returned `{hello:'world'}`.","observation:rtdb-modular-push-with-value"],"assurance":"eligible"},{"id":"rtdb-modular#127","kind":"registry-row","surface":"rtdb-modular","behavior":"The returned ref `r = push(parent, value)` is usable in follow-up ops: `get(r)`, `set(r, …)`, `remove(r)`","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-push-with-value.json` — observed all 4 follow-up ops succeed through the returned ref (`refIsUsableForFollowupOps: true`).","observation:rtdb-modular-push-with-value"],"assurance":"eligible"},{"id":"rtdb-modular#M17","kind":"registry-row","surface":"rtdb-modular","behavior":"`push(ref)` mints a 20-char auto-id key starting with `-`, lexicographically sortable","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-target.test.ts` (\"mints 20-char keys starting with \\\"-\\\"\" + \"sequential push keys are lex-sortable\"); matches oracle observation `packages/conformance/observations/rtdb/rtdb-push-autoid-format.json`","observation:rtdb-push-autoid-format","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M18","kind":"registry-row","surface":"rtdb-modular","behavior":"`push(ref, value)` writes `value` at the new child path","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"push(ref, value) writes the value at the new child path\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M19","kind":"registry-row","surface":"rtdb-modular","behavior":"`pushKey()` mints a fresh push-shaped key without writing — used by callers building multi-path updates that need the key first","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"pushKey() mints a fresh key without writing\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M68","kind":"registry-row","surface":"rtdb-modular","behavior":"Write validation: an `undefined` payload, a non-finite number (`NaN`/`±Infinity`), or a key containing a forbidden char (`.`, `#`, `$`, `/`, `[`, `]`, control chars) is rejected with a plain `Error` (DB-B1)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/normalization.test.ts` (\"rejects an undefined payload\" + \"rejects an invalid key\" + \"rejects a non-finite number\"); upstream `core/util/validation.ts:45,58,112-199`","packages/pyric/test/database/modular/normalization.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M70","kind":"registry-row","surface":"rtdb-modular","behavior":"`push(ref, value?)` returns a `ThenableReference` (a `DatabaseReference` with `.then`/`.catch`). The key + ref are minted CLIENT-SIDE and available synchronously even when the optional value write is rules-denied; the write is deferred onto the promise, so a denial REJECTS the awaited push rather than throwing synchronously and discarding the key (DB-B7)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/push-thenable.test.ts` (4 cases); matches oracle `packages/conformance/observations/rtdb/rtdb-push-autoid-format.json` (\"available immediately even when the subsequent server write is denied by rules\") + upstream `api/Reference_impl.ts:599-630`","observation:rtdb-push-autoid-format","packages/pyric/test/database/modular/push-thenable.test.ts"],"assurance":"eligible"}]},{"feature":"pushKey","surface":"rtdb","importPaths":[],"evidenceSlug":"database-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"pushKey is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"rtdb-modular#M19","kind":"registry-row","surface":"rtdb-modular","behavior":"`pushKey()` mints a fresh push-shaped key without writing — used by callers building multi-path updates that need the key first","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"pushKey() mints a fresh key without writing\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"query","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"query is available, has diverged fidelity, and is qualified for assurance.","caveats":["Index validation against `firestore.indexes.json` — sandbox uses `LocalEnvironment`'s lint pass; prod has its own server-side validation","divergence: sandbox can mis-pass a query that prod would reject at the server with `failed-precondition` if no index exists"],"claims":[{"id":"firestore:runtime:query","kind":"runtime-export","surface":"firestore","behavior":"query is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#54","kind":"registry-row","surface":"firestore","behavior":"`query(coll, where(…), orderBy(…), limit(…))` composes constraints in order","status":"conforms","evidence":["`unit:sandbox-target.test.ts`, `playground:firestore-query`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#59c","kind":"registry-row","surface":"firestore","behavior":"**Implicit orderBy + `__name__` tiebreak (FS-B8)** — the query's sort is normalized to: explicit orderBy clauses, then an implicit order on each inequality-filtered field, then a final document-key (`__name__`) clause. Equal-valued docs sort deterministically by key; a `where('x','>',v)` with no explicit orderBy returns docs ordered by `x`. Mirrors `clones/.../core/query.ts:queryNormalizedOrderBy`. Pre-FS-B8 equal-valued docs were nondeterministic and inequality results came back in insertion order.","status":"conforms","evidence":["`unit:admin-compat/implicit-order-name.test.ts` (key tiebreak, snapshot-cursor disambiguation, implicit inequality order; verified failing pre-fix)","packages/pyric/test/sandbox/firestore/admin-compat/implicit-order-name.test.ts"],"assurance":"eligible"},{"id":"firestore#62","kind":"registry-row","surface":"firestore","behavior":"Composite filters AND with other constraints — `query(coll, or(...), orderBy(...), limit(...))`","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#65","kind":"registry-row","surface":"firestore","behavior":"Chained queries re-tag for further constraints (`query(query(coll, where), orderBy)`)","status":"conforms","evidence":["`unit:sandbox-target.test.ts` (\"chained queries are taggable\")","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#66","kind":"registry-row","surface":"firestore","behavior":"Index validation against `firestore.indexes.json` — sandbox uses `LocalEnvironment`'s lint pass; prod has its own server-side validation","status":"diverged-documented","evidence":["divergence: sandbox can mis-pass a query that prod would reject at the server with `failed-precondition` if no index exists"],"assurance":"qualified"}]},{"feature":"Query","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"Query is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors."],"claims":[{"id":"firestore:runtime:Query","kind":"runtime-export","surface":"firestore","behavior":"These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"},{"id":"firestore:type:Query","kind":"type-export","surface":"firestore","behavior":"Query is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"query","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"query is available, has diverged fidelity, and is qualified for assurance.","caveats":["**Divergence (DB-B12, honest doc):** the onChild* callbacks do NOT receive the `previousChildName` second argument; `onValue`/`onChild*` do NOT accept a `cancelCallback`; `onChildAdded`/`Changed`/`Removed`/`Moved` accept only plain refs (not `Query`); `child_moved` never fires (ordered-query move detection unmodeled). These listener-surface holes are out of scope for the current phase — consumers needing them use `firebase/database` directly.","divergence documented; partial coverage: `{ onlyOnce }` IS implemented (M74)."],"claims":[{"id":"database:runtime:query","kind":"runtime-export","surface":"database","behavior":"query is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#142","kind":"registry-row","surface":"rtdb-modular","behavior":"`query(ref, orderByChild('field'), limitToFirst(N))` returns a `Query` whose `get()` resolves a snapshot containing N children ordered by `field`","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-query-orderbychild-limit.json` — seeded 4 children with positions `[3,1,4,2]`, observed `orderedKeys: [{key:'a',pos:1}, {key:'b',pos:2}]` (first 2 in ascending order). Requires `.indexOn` declared in rules.","observation:rtdb-modular-orderbychild-window","observation:rtdb-modular-query-orderbychild-limit"],"assurance":"eligible"},{"id":"rtdb-modular#152","kind":"registry-row","surface":"rtdb-modular","behavior":"Listeners on a `Query` (`onValue(q, …)`) emit only the windowed snapshot — NOT the parent ref's full data","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-onvalue-with-query.json` — seeded 3 children, watched first 2 by `pos`; observed 3 fires total: (1) initial `[a,b]`, (2) OUTSIDE-window write to `c/extra` did NOT fire, (3) INSIDE-window mutation of `a` re-fired, (4) new child `z` displaced `b` and re-fired. Outside-window writes are silent.","observation:rtdb-modular-onvalue-with-query"],"assurance":"eligible"},{"id":"rtdb-modular#M36","kind":"registry-row","surface":"rtdb-modular","behavior":"`query(ref, ...constraints)` + ordering/range constraints","status":"conforms","evidence":["`unit:upstream-rtdb-probes.test.ts` (\"orderByChild('a/b') + limitToFirst orders by the nested path\") + `unit:modular/queries.test.ts` + oracle observations under `packages/conformance/observations/rtdb-modular/`; see M49–M64 for the per-claim breakdown.","packages/pyric/test/database/upstream-rtdb-probes.test.ts","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M46","kind":"registry-row","surface":"rtdb-modular","behavior":"`onChildMoved` on a plain ref (no `query(_, orderBy*)`) NEVER fires — per RTDB docs, child_moved emits only under ordered queries","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-child-events.test.ts` (\"does NOT fire on a plain ref (no ordering)\"); matches the upstream contract observed under ordered-query in `packages/conformance/observations/rtdb-modular/rtdb-modular-onchildmoved-with-orderby.json` (where ordered-query did fire — Tier 3 will wire that path; Tier 2 locks the plain-ref no-fire case).","observation:rtdb-modular-onchildmoved-with-orderby","packages/pyric/test/database/modular/sandbox-child-events.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M49","kind":"registry-row","surface":"rtdb-modular","behavior":"`query(ref, orderByChild(p), startAt(v), endAt(w))` window is BOTH-INCLUSIVE — children whose ordered field === `v` or === `w` are included","status":"conforms","evidence":["`unit:upstream-rtdb-probes.test.ts` (deep orderByChild nested path) + `unit:modular/queries.test.ts` (\"returns children whose ordered child is within [startAt, endAt] inclusive\"); matches oracle `rtdb-modular-orderbychild-window.json`","observation:rtdb-modular-orderbychild-window","packages/pyric/test/database/upstream-rtdb-probes.test.ts","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M58","kind":"registry-row","surface":"rtdb-modular","behavior":"`onValue(query, cb)` only fires when the windowed result changes — writes OUTSIDE the window don't re-fire the listener; writes that displace a member DO","status":"conforms","evidence":["`unit:upstream-rtdb-probes.test.ts` (\"one update nulls, mutates, and displaces within a limitToFirst window\") + `unit:modular/queries.test.ts` (\"fires only when the windowed result changes\"); matches oracle `rtdb-modular-onvalue-with-query.json`","observation:rtdb-modular-onvalue-with-query","packages/pyric/test/database/upstream-rtdb-probes.test.ts","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M59","kind":"registry-row","surface":"rtdb-modular","behavior":"`onValue(query)` initial fire delivers an empty window (`numChildren() === 0`) when the path is absent","status":"conforms","evidence":["`unit:modular/queries.test.ts` (\"initial fire on an empty path delivers an empty window\")","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M60","kind":"registry-row","surface":"rtdb-modular","behavior":"`query(query(ref, c1), c2)` composes constraints — chaining folds both into one spec","status":"conforms","evidence":["`unit:modular/queries.test.ts` (\"query(query(ref, c1), c2) composes constraints\")","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M61","kind":"registry-row","surface":"rtdb-modular","behavior":"Snapshot from a query exposes children via `snap.forEach` in the executor-computed order — NOT necessarily the order `Object.entries(val)` would yield","status":"conforms","evidence":["`unit:modular/queries.test.ts` (\"forEach visits children in ascending order of the child key\")","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M64","kind":"registry-row","surface":"rtdb-modular","behavior":"`query` on a path holding a primitive (or absent path) returns an empty snapshot — no rows to iterate","status":"conforms","evidence":["`unit:modular/queries.test.ts` (\"query on a path with primitive value returns no rows\")","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M69","kind":"registry-row","surface":"rtdb-modular","behavior":"Conflicting query constraints throw synchronously at `query(...)` construction (NOT silent last-win): multiple `orderBy*`, a second `limitToFirst`/`limitToLast`, a second start (`startAt`/`startAfter`/`equalTo`) or end (`endAt`/`endBefore`/`equalTo`) (DB-B5)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/constraint-conflicts.test.ts` (5 cases); upstream `api/Reference_impl.ts:160-165,1824-1841,1888-1905,1945-1951,2193-2206`","packages/pyric/test/database/modular/constraint-conflicts.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M72","kind":"registry-row","surface":"rtdb-modular","behavior":"Object-valued children are ORDER-EQUAL — the sort/range tie is broken by key (`nameCompare`), NOT by an invented `JSON.stringify` ordering; a query re-write that only reorders object keys is \"no change\" and doesn't re-fire (DB-B11)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/object-order-equality.test.ts`; upstream `core/snap/ChildrenNode.ts:386-400`","packages/pyric/test/database/modular/object-order-equality.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M75","kind":"registry-row","surface":"rtdb-modular","behavior":"**Divergence (DB-B12, honest doc):** the onChild* callbacks do NOT receive the `previousChildName` second argument; `onValue`/`onChild*` do NOT accept a `cancelCallback`; `onChildAdded`/`Changed`/`Removed`/`Moved` accept only plain refs (not `Query`); `child_moved` never fires (ordered-query move detection unmodeled). These listener-surface holes are out of scope for the current phase — consumers needing them use `firebase/database` directly.","status":"diverged-documented","evidence":["divergence documented; partial coverage: `{ onlyOnce }` IS implemented (M74)."],"assurance":"qualified"}]},{"feature":"Query","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"Query is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"database:type:Query","kind":"type-export","surface":"database","behavior":"Query is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"QueryCompositeFilterConstraint","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"QueryCompositeFilterConstraint is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","Public type export is not mirrored."],"claims":[{"id":"firestore:runtime:QueryCompositeFilterConstraint","kind":"runtime-export","surface":"firestore","behavior":"These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"},{"id":"firestore:type:QueryCompositeFilterConstraint","kind":"type-export","surface":"firestore","behavior":"QueryCompositeFilterConstraint is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"QueryConstraint","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"QueryConstraint is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors."],"claims":[{"id":"firestore:runtime:QueryConstraint","kind":"runtime-export","surface":"firestore","behavior":"These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"},{"id":"firestore:type:QueryConstraint","kind":"type-export","surface":"firestore","behavior":"QueryConstraint is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"QueryConstraint","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"QueryConstraint is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["These Firebase classes are mirrored structurally in Pyric's type surface but are not exported as runtime constructor values; runtime identity remains unbuilt."],"claims":[{"id":"database:runtime:QueryConstraint","kind":"runtime-export","surface":"database","behavior":"These Firebase classes are mirrored structurally in Pyric's type surface but are not exported as runtime constructor values; runtime identity remains unbuilt.","status":"deferred","evidence":["upstream:firebase/database"],"assurance":"not-applicable"},{"id":"database:type:QueryConstraint","kind":"type-export","surface":"database","behavior":"QueryConstraint is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"QueryConstraintType","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"QueryConstraintType is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:QueryConstraintType","kind":"type-export","surface":"firestore","behavior":"QueryConstraintType is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"QueryConstraintType","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"QueryConstraintType is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"database:type:QueryConstraintType","kind":"type-export","surface":"database","behavior":"QueryConstraintType is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"QueryDocumentSnapshot","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"QueryDocumentSnapshot is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors."],"claims":[{"id":"firestore:runtime:QueryDocumentSnapshot","kind":"runtime-export","surface":"firestore","behavior":"These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"},{"id":"firestore:type:QueryDocumentSnapshot","kind":"type-export","surface":"firestore","behavior":"QueryDocumentSnapshot is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"QueryEndAtConstraint","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"QueryEndAtConstraint is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","Public type export is not mirrored."],"claims":[{"id":"firestore:runtime:QueryEndAtConstraint","kind":"runtime-export","surface":"firestore","behavior":"These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"},{"id":"firestore:type:QueryEndAtConstraint","kind":"type-export","surface":"firestore","behavior":"QueryEndAtConstraint is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"queryEqual","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"queryEqual is available, has diverged fidelity, and is qualified for assurance.","caveats":["`queryEqual(a, b)` is identity-only in the sandbox mirror; production's untouched Firebase SDK uses structural equality","divergence: sandbox does identity-only; prod does deep structural. Oracle-locked: `packages/conformance/observations/firestore/firestore-queryequal-structural.json` — two independently-built queries with the same `where('x','==',1)` constraint compare equal in prod (`sameQueryBuiltTwice: true`), confirming structural semantics. Common use case (caching the same returned query) works on both."],"claims":[{"id":"firestore:runtime:queryEqual","kind":"runtime-export","surface":"firestore","behavior":"queryEqual is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#116","kind":"registry-row","surface":"firestore","behavior":"`queryEqual(a, b)` is identity-only in the sandbox mirror; production's untouched Firebase SDK uses structural equality","status":"diverged-documented","evidence":["divergence: sandbox does identity-only; prod does deep structural. Oracle-locked: `packages/conformance/observations/firestore/firestore-queryequal-structural.json` — two independently-built queries with the same `where('x','==',1)` constraint compare equal in prod (`sameQueryBuiltTwice: true`), confirming structural semantics. Common use case (caching the same returned query) works on both.","observation:firestore-queryequal-structural"],"assurance":"qualified"}]},{"feature":"QueryFieldFilterConstraint","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"QueryFieldFilterConstraint is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","Public type export is not mirrored."],"claims":[{"id":"firestore:runtime:QueryFieldFilterConstraint","kind":"runtime-export","surface":"firestore","behavior":"These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"},{"id":"firestore:type:QueryFieldFilterConstraint","kind":"type-export","surface":"firestore","behavior":"QueryFieldFilterConstraint is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"QueryFilterConstraint","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"QueryFilterConstraint is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:QueryFilterConstraint","kind":"type-export","surface":"firestore","behavior":"QueryFilterConstraint is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"QueryLimitConstraint","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"QueryLimitConstraint is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","Public type export is not mirrored."],"claims":[{"id":"firestore:runtime:QueryLimitConstraint","kind":"runtime-export","surface":"firestore","behavior":"These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"},{"id":"firestore:type:QueryLimitConstraint","kind":"type-export","surface":"firestore","behavior":"QueryLimitConstraint is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"QueryNonFilterConstraint","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"QueryNonFilterConstraint is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:QueryNonFilterConstraint","kind":"type-export","surface":"firestore","behavior":"QueryNonFilterConstraint is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"QueryOrderByConstraint","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"QueryOrderByConstraint is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","Public type export is not mirrored."],"claims":[{"id":"firestore:runtime:QueryOrderByConstraint","kind":"runtime-export","surface":"firestore","behavior":"These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"},{"id":"firestore:type:QueryOrderByConstraint","kind":"type-export","surface":"firestore","behavior":"QueryOrderByConstraint is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"QuerySnapshot","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"QuerySnapshot is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors."],"claims":[{"id":"firestore:runtime:QuerySnapshot","kind":"runtime-export","surface":"firestore","behavior":"These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"},{"id":"firestore:type:QuerySnapshot","kind":"type-export","surface":"firestore","behavior":"QuerySnapshot is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"querySnapshotFromJSON","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"querySnapshotFromJSON is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Snapshot JSON reconstruction and listener-resume helpers depend on serialized snapshot state that the sandbox has not modeled."],"claims":[{"id":"firestore:runtime:querySnapshotFromJSON","kind":"runtime-export","surface":"firestore","behavior":"Snapshot JSON reconstruction and listener-resume helpers depend on serialized snapshot state that the sandbox has not modeled.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"}]},{"feature":"QueryStartAtConstraint","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"QueryStartAtConstraint is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","Public type export is not mirrored."],"claims":[{"id":"firestore:runtime:QueryStartAtConstraint","kind":"runtime-export","surface":"firestore","behavior":"These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"},{"id":"firestore:type:QueryStartAtConstraint","kind":"type-export","surface":"firestore","behavior":"QueryStartAtConstraint is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ReactNativeAsyncStorage","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"ReactNativeAsyncStorage is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:ReactNativeAsyncStorage","kind":"type-export","surface":"auth","behavior":"ReactNativeAsyncStorage is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"reauthenticateWithCredential","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"reauthenticateWithCredential is available, has diverged fidelity, and is qualified for assurance.","caveats":["In production the POINT of re-authentication is the `auth/requires-recent-login` gate: `updateEmail` / `updatePassword` / `deleteUser` refuse to run on a session whose sign-in is older than a few minutes, and re-auth is how you clear it. The sandbox does NOT enforce that gate — those three mutations already run on a session of any age (a pre-existing documented divergence), so there is no gate here for re-auth to clear. What re-auth DOES do here is real but narrower: it genuinely re-verifies the credential, mints a fresh token, and returns `operationType: 'reauthenticate'`. Code that calls it runs unchanged against prod, where it also clears the gate.","Declared divergence, not a bug: inventing a recent-login gate would break every existing sandbox flow (which never re-authenticates) while proving nothing. `unit:sandbox-linking-reauth.test.ts` pins the behavior that IS provided (real credential re-verification + a fresh token)."],"claims":[{"id":"auth:runtime:reauthenticateWithCredential","kind":"runtime-export","surface":"auth","behavior":"reauthenticateWithCredential is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#170","kind":"registry-row","surface":"auth","behavior":"Really re-verifies: an email credential is checked against the stored password exactly as `signInWithEmailAndPassword` checks it. A wrong password throws `auth/wrong-password`. A credential belonging to a DIFFERENT account throws `auth/user-mismatch` — checked BEFORE the password compare, so it cannot leak whether the other account's password was right. On success a fresh ID token is minted (a new `authTime`), and the returned `UserCredential` carries `operationType: 'reauthenticate'`.","status":"conforms","evidence":["UNIT-BACKED, and the reason it is not oracle-backed is recorded rather than glossed: the probe (`auth-reauthenticate-with-credential`) ran against the real project and could not even create the two accounts it needs — `setupCode: auth/operation-not-allowed`, because the oracle project has the Email/Password provider DISABLED. The capture is committed showing that. `auth/user-mismatch` is matched to the oracle-captured `AuthErrorCodes` map (auth#172). Behavior proven in `unit:sandbox-linking-reauth.test.ts`.","observation:auth-reauthenticate-with-credential","packages/pyric/test/auth/sandbox-linking-reauth.test.ts"],"assurance":"eligible"},{"id":"auth#176","kind":"registry-row","surface":"auth","behavior":"In production the POINT of re-authentication is the `auth/requires-recent-login` gate: `updateEmail` / `updatePassword` / `deleteUser` refuse to run on a session whose sign-in is older than a few minutes, and re-auth is how you clear it. The sandbox does NOT enforce that gate — those three mutations already run on a session of any age (a pre-existing documented divergence), so there is no gate here for re-auth to clear. What re-auth DOES do here is real but narrower: it genuinely re-verifies the credential, mints a fresh token, and returns `operationType: 'reauthenticate'`. Code that calls it runs unchanged against prod, where it also clears the gate.","status":"diverged-documented","evidence":["Declared divergence, not a bug: inventing a recent-login gate would break every existing sandbox flow (which never re-authenticates) while proving nothing. `unit:sandbox-linking-reauth.test.ts` pins the behavior that IS provided (real credential re-verification + a fresh token).","packages/pyric/test/auth/sandbox-linking-reauth.test.ts"],"assurance":"qualified"}]},{"feature":"reauthenticateWithPhoneNumber","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"reauthenticateWithPhoneNumber is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["MFA / phone / reCAPTCHA is deferred, not out of scope — reCAPTCHA/SMS are external infrastructure Pyric can mock with the OAuth resolver pattern, and TOTP is pure algorithm work."],"claims":[{"id":"auth:runtime:reauthenticateWithPhoneNumber","kind":"runtime-export","surface":"auth","behavior":"MFA / phone / reCAPTCHA is deferred, not out of scope — reCAPTCHA/SMS are external infrastructure Pyric can mock with the OAuth resolver pattern, and TOTP is pure algorithm work.","status":"deferred","evidence":["registry:auth#180"],"assurance":"not-applicable"}]},{"feature":"reauthenticateWithPopup","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"reauthenticateWithPopup is available, has diverged fidelity, and is qualified for assurance.","caveats":["In production the POINT of re-authentication is the `auth/requires-recent-login` gate: `updateEmail` / `updatePassword` / `deleteUser` refuse to run on a session whose sign-in is older than a few minutes, and re-auth is how you clear it. The sandbox does NOT enforce that gate — those three mutations already run on a session of any age (a pre-existing documented divergence), so there is no gate here for re-auth to clear. What re-auth DOES do here is real but narrower: it genuinely re-verifies the credential, mints a fresh token, and returns `operationType: 'reauthenticate'`. Code that calls it runs unchanged against prod, where it also clears the gate.","Declared divergence, not a bug: inventing a recent-login gate would break every existing sandbox flow (which never re-authenticates) while proving nothing. `unit:sandbox-linking-reauth.test.ts` pins the behavior that IS provided (real credential re-verification + a fresh token)."],"claims":[{"id":"auth:runtime:reauthenticateWithPopup","kind":"runtime-export","surface":"auth","behavior":"reauthenticateWithPopup is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#176","kind":"registry-row","surface":"auth","behavior":"In production the POINT of re-authentication is the `auth/requires-recent-login` gate: `updateEmail` / `updatePassword` / `deleteUser` refuse to run on a session whose sign-in is older than a few minutes, and re-auth is how you clear it. The sandbox does NOT enforce that gate — those three mutations already run on a session of any age (a pre-existing documented divergence), so there is no gate here for re-auth to clear. What re-auth DOES do here is real but narrower: it genuinely re-verifies the credential, mints a fresh token, and returns `operationType: 'reauthenticate'`. Code that calls it runs unchanged against prod, where it also clears the gate.","status":"diverged-documented","evidence":["Declared divergence, not a bug: inventing a recent-login gate would break every existing sandbox flow (which never re-authenticates) while proving nothing. `unit:sandbox-linking-reauth.test.ts` pins the behavior that IS provided (real credential re-verification + a fresh token).","packages/pyric/test/auth/sandbox-linking-reauth.test.ts"],"assurance":"qualified"},{"id":"auth#177","kind":"registry-row","surface":"auth","behavior":"Route through the shared resolver seam with `authType: 'reauth'`. The identity the resolver produces MUST be the user being re-authenticated — a resolver that hands back a different uid throws `auth/user-mismatch`. That check is the entire security content of the flow; without it 're-authentication' would accept anyone.","status":"conforms","evidence":["`unit:sandbox-linking-reauth.test.ts` — asserts the resolver sees `authType: 'reauth'` and that an impostor identity is rejected with `auth/user-mismatch`.","packages/pyric/test/auth/sandbox-linking-reauth.test.ts"],"assurance":"eligible"}]},{"feature":"reauthenticateWithRedirect","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"reauthenticateWithRedirect is available, has diverged fidelity, and is qualified for assurance.","caveats":["In production the POINT of re-authentication is the `auth/requires-recent-login` gate: `updateEmail` / `updatePassword` / `deleteUser` refuse to run on a session whose sign-in is older than a few minutes, and re-auth is how you clear it. The sandbox does NOT enforce that gate — those three mutations already run on a session of any age (a pre-existing documented divergence), so there is no gate here for re-auth to clear. What re-auth DOES do here is real but narrower: it genuinely re-verifies the credential, mints a fresh token, and returns `operationType: 'reauthenticate'`. Code that calls it runs unchanged against prod, where it also clears the gate.","Declared divergence, not a bug: inventing a recent-login gate would break every existing sandbox flow (which never re-authenticates) while proving nothing. `unit:sandbox-linking-reauth.test.ts` pins the behavior that IS provided (real credential re-verification + a fresh token)."],"claims":[{"id":"auth:runtime:reauthenticateWithRedirect","kind":"runtime-export","surface":"auth","behavior":"reauthenticateWithRedirect is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#176","kind":"registry-row","surface":"auth","behavior":"In production the POINT of re-authentication is the `auth/requires-recent-login` gate: `updateEmail` / `updatePassword` / `deleteUser` refuse to run on a session whose sign-in is older than a few minutes, and re-auth is how you clear it. The sandbox does NOT enforce that gate — those three mutations already run on a session of any age (a pre-existing documented divergence), so there is no gate here for re-auth to clear. What re-auth DOES do here is real but narrower: it genuinely re-verifies the credential, mints a fresh token, and returns `operationType: 'reauthenticate'`. Code that calls it runs unchanged against prod, where it also clears the gate.","status":"diverged-documented","evidence":["Declared divergence, not a bug: inventing a recent-login gate would break every existing sandbox flow (which never re-authenticates) while proving nothing. `unit:sandbox-linking-reauth.test.ts` pins the behavior that IS provided (real credential re-verification + a fresh token).","packages/pyric/test/auth/sandbox-linking-reauth.test.ts"],"assurance":"qualified"},{"id":"auth#177","kind":"registry-row","surface":"auth","behavior":"Route through the shared resolver seam with `authType: 'reauth'`. The identity the resolver produces MUST be the user being re-authenticated — a resolver that hands back a different uid throws `auth/user-mismatch`. That check is the entire security content of the flow; without it 're-authentication' would accept anyone.","status":"conforms","evidence":["`unit:sandbox-linking-reauth.test.ts` — asserts the resolver sees `authType: 'reauth'` and that an impostor identity is rejected with `auth/user-mismatch`.","packages/pyric/test/auth/sandbox-linking-reauth.test.ts"],"assurance":"eligible"}]},{"feature":"RecaptchaParameters","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"RecaptchaParameters is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:RecaptchaParameters","kind":"type-export","surface":"auth","behavior":"RecaptchaParameters is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"RecaptchaVerifier","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"RecaptchaVerifier is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["MFA / phone / reCAPTCHA is deferred, not out of scope — reCAPTCHA/SMS are external infrastructure Pyric can mock with the OAuth resolver pattern, and TOTP is pure algorithm work.","Public type export is not mirrored."],"claims":[{"id":"auth:runtime:RecaptchaVerifier","kind":"runtime-export","surface":"auth","behavior":"MFA / phone / reCAPTCHA is deferred, not out of scope — reCAPTCHA/SMS are external infrastructure Pyric can mock with the OAuth resolver pattern, and TOTP is pure algorithm work.","status":"deferred","evidence":["registry:auth#180"],"assurance":"not-applicable"},{"id":"auth:type:RecaptchaVerifier","kind":"type-export","surface":"auth","behavior":"RecaptchaVerifier is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"recursiveMatch","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"recursiveMatch is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#182","kind":"registry-row","surface":"firestore-rules","behavior":"User-defined `function`/`let`, granular `allow get/list/update/write` verbs, the ternary operator, and a recursive `{document=**}` match in rules","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 7 cases (role-gated docs + public recursive subtree). `oracle:rules-firestore-functions-verbs-and-recursive` — replayed by `unit:rules/oracle-conformance.test.ts`.","observation:rules-firestore-functions-verbs-and-recursive","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"recursiveWildcard","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"recursiveWildcard is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#102","kind":"registry-row","surface":"storage-rules","behavior":"Multi-segment wildcard `{allPaths=**}` matches zero-or-more remaining segments","status":"conforms","evidence":["`unit:rules.test.ts` (parser + evaluator both honor the `**` form)","packages/pyric/test/storage/rules.test.ts"],"assurance":"eligible"}]},{"feature":"ref","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"ref is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["`ref(db, path)` returns a tagged `DatabaseReference` carrying `key`, `parent`, `root`, `toString()`","upstream `firebase/database` contract","`ref(db)` with no path returns the root ref (`key === null`, `parent === null`)","upstream contract","`child(ref, 'a/b')` joins a relative path, including embedded slashes","`ref.parent` is `null` at root, otherwise the parent ref","`ref.key` is the final path segment, `null` for root","Unknown ref (not produced by this package) → `TypeError` in shim ops","Phase 3"],"claims":[{"id":"database:runtime:ref","kind":"runtime-export","surface":"database","behavior":"ref is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#100","kind":"registry-row","surface":"rtdb-modular","behavior":"`ref(db, path)` returns a tagged `DatabaseReference` carrying `key`, `parent`, `root`, `toString()`","status":"unverified","evidence":["upstream `firebase/database` contract"],"assurance":"qualified"},{"id":"rtdb-modular#101","kind":"registry-row","surface":"rtdb-modular","behavior":"`ref(db)` with no path returns the root ref (`key === null`, `parent === null`)","status":"unverified","evidence":["upstream contract"],"assurance":"qualified"},{"id":"rtdb-modular#102","kind":"registry-row","surface":"rtdb-modular","behavior":"`child(ref, 'a/b')` joins a relative path, including embedded slashes","status":"unverified","evidence":["upstream contract"],"assurance":"qualified"},{"id":"rtdb-modular#103","kind":"registry-row","surface":"rtdb-modular","behavior":"`ref.parent` is `null` at root, otherwise the parent ref","status":"unverified","evidence":["upstream contract"],"assurance":"qualified"},{"id":"rtdb-modular#104","kind":"registry-row","surface":"rtdb-modular","behavior":"`ref.key` is the final path segment, `null` for root","status":"unverified","evidence":["upstream contract"],"assurance":"qualified"},{"id":"rtdb-modular#105","kind":"registry-row","surface":"rtdb-modular","behavior":"Unknown ref (not produced by this package) → `TypeError` in shim ops","status":"unsupported","evidence":["Phase 3"],"assurance":"ineligible"},{"id":"rtdb-modular#M10","kind":"registry-row","surface":"rtdb-modular","behavior":"`set(ref, value)` replaces the value at the path","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-target.test.ts` (\"round-trips a primitive value\" + \"round-trips nested objects\"); matches oracle observation `packages/conformance/observations/rtdb/rtdb-set-then-get-roundtrip.json` (prod observation blocked on rules; sandbox locks the contract directly)","observation:rtdb-set-then-get-roundtrip","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M11","kind":"registry-row","surface":"rtdb-modular","behavior":"`set(ref, null)` deletes the subtree at the path","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-target.test.ts` (\"set(ref, null) deletes the path\"); matches oracle observation `packages/conformance/observations/rtdb/rtdb-remove-vs-set-null.json`","observation:rtdb-remove-vs-set-null","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M12","kind":"registry-row","surface":"rtdb-modular","behavior":"`remove(ref)` is equivalent to `set(ref, null)` (same end state)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-target.test.ts` (\"remove and set(null) produce identical end-state\"); matches oracle observation `packages/conformance/observations/rtdb/rtdb-remove-vs-set-null.json`","observation:rtdb-remove-vs-set-null","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M13","kind":"registry-row","surface":"rtdb-modular","behavior":"`update(ref, patch)` shallow-merges top-level keys at the ref's path","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"shallow-merges top-level keys\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M17","kind":"registry-row","surface":"rtdb-modular","behavior":"`push(ref)` mints a 20-char auto-id key starting with `-`, lexicographically sortable","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-target.test.ts` (\"mints 20-char keys starting with \\\"-\\\"\" + \"sequential push keys are lex-sortable\"); matches oracle observation `packages/conformance/observations/rtdb/rtdb-push-autoid-format.json`","observation:rtdb-push-autoid-format","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M18","kind":"registry-row","surface":"rtdb-modular","behavior":"`push(ref, value)` writes `value` at the new child path","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"push(ref, value) writes the value at the new child path\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M26","kind":"registry-row","surface":"rtdb-modular","behavior":"`onValue(ref, cb)` fires immediately on subscribe with the current value at the path","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"fires on subscribe with the current value\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M31","kind":"registry-row","surface":"rtdb-modular","behavior":"`onChildAdded` / `onChildChanged` / `onChildRemoved` / `onChildMoved` — plain-ref subscription surface","status":"conforms","evidence":["Tier 2: sandbox aligned with oracle observations under `packages/conformance/observations/rtdb-modular/rtdb-modular-onchild*.json`. See M41–M48 for the per-event behavioral claims."],"assurance":"eligible"},{"id":"rtdb-modular#M36","kind":"registry-row","surface":"rtdb-modular","behavior":"`query(ref, ...constraints)` + ordering/range constraints","status":"conforms","evidence":["`unit:upstream-rtdb-probes.test.ts` (\"orderByChild('a/b') + limitToFirst orders by the nested path\") + `unit:modular/queries.test.ts` + oracle observations under `packages/conformance/observations/rtdb-modular/`; see M49–M64 for the per-claim breakdown.","packages/pyric/test/database/upstream-rtdb-probes.test.ts","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M37","kind":"registry-row","surface":"rtdb-modular","behavior":"`runTransaction(ref, fn, options?)` resolves to `{ committed: boolean, snapshot: DataSnapshot }` for the happy path — the update fn return value is written, committed is `true`, and `snapshot.val()` reflects the committed value","status":"conforms","evidence":["Sandbox aligned: `unit:modular/transaction.test.ts` (\"resolves to { committed: boolean, snapshot } with the committed value\"); matches oracle observations `packages/conformance/observations/rtdb-modular/rtdb-modular-runtransaction-success.json` + `rtdb-modular-runtransaction-returns-committed-snapshot.json` (against blockingfun, fb-js-sdk 12.13.0)","observation:rtdb-modular-runtransaction-success","observation:rtdb-modular-runtransaction-warm-client-speculation","packages/pyric/test/database/modular/transaction.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M37b","kind":"registry-row","surface":"rtdb-modular","behavior":"The update fn receives the CURRENT value at the ref's path; for an absent path the argument is `null` (NOT `undefined`)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/transaction.test.ts` (\"update fn receives null for an absent path\" + \"update fn receives the existing value for a seeded path\"); matches oracle observation `packages/conformance/observations/rtdb-modular/rtdb-modular-runtransaction-current-value-arg.json` (prod observation showed `missingArgs[0].isNull === true`) — note divergence: prod ALSO speculatively calls the fn with `null` for a seeded path before the server-snap arrives, the sandbox skips that speculative call (single invocation with the real current value)","observation:rtdb-modular-runtransaction-current-value-arg","packages/pyric/test/database/modular/transaction.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M4","kind":"registry-row","surface":"rtdb-modular","behavior":"`ref(db, path?)` returns a path-tagged `DatabaseReference`; default is root","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"ref(db) returns a root ref\" + \"ref(db, ...) returns a path ref\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M40","kind":"registry-row","surface":"rtdb-modular","behavior":"Sandbox refs carry a stable `key` (last path segment) and `toString()` returning `sandbox://rtdb/<path>`","status":"conforms","evidence":["covered by the `ref` / `child` / `parent` tests"],"assurance":"eligible"},{"id":"rtdb-modular#M41","kind":"registry-row","surface":"rtdb-modular","behavior":"`onChildAdded` replays each existing direct child of the parent ref on subscribe (one fire per existing key)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-child-events.test.ts` (\"replays existing direct children on subscribe — one fire per key\"); matches oracle observation `packages/conformance/observations/rtdb-modular/rtdb-modular-onchildadded-initial-replay.json` (seeded `{k1,k2,k3}`, observed `firedKeys: ['k1','k2','k3']`).","observation:rtdb-modular-onchildadded-initial-replay","packages/pyric/test/database/modular/sandbox-child-events.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M46","kind":"registry-row","surface":"rtdb-modular","behavior":"`onChildMoved` on a plain ref (no `query(_, orderBy*)`) NEVER fires — per RTDB docs, child_moved emits only under ordered queries","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-child-events.test.ts` (\"does NOT fire on a plain ref (no ordering)\"); matches the upstream contract observed under ordered-query in `packages/conformance/observations/rtdb-modular/rtdb-modular-onchildmoved-with-orderby.json` (where ordered-query did fire — Tier 3 will wire that path; Tier 2 locks the plain-ref no-fire case).","observation:rtdb-modular-onchildmoved-with-orderby","packages/pyric/test/database/modular/sandbox-child-events.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M47","kind":"registry-row","surface":"rtdb-modular","behavior":"`off(ref)` (no event type) removes ALL listeners at that ref — value + every child event variety","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-child-events.test.ts` (\"off(ref) removes ALL listeners at the ref\" + \"off(ref) also removes value listeners at the same path\"); matches oracle observation `packages/conformance/observations/rtdb-modular/rtdb-modular-off-stops-child-fires.json` (`postOffFires: 0`).","observation:rtdb-modular-off-stops-child-fires","packages/pyric/test/database/modular/sandbox-child-events.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M48","kind":"registry-row","surface":"rtdb-modular","behavior":"`off(ref, eventType?, callback?)` variants: `off(ref, 'value')` / `off(ref, 'child_added')` / `off(ref, eventType, cb)` remove the targeted subset; returned-unsubscribe from `onChild*` is equivalent to `off(ref, eventType, cb)`","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-child-events.test.ts` (\"off(ref, \\\"child_added\\\") removes only that event variety\" + \"off(ref, \\\"value\\\") removes only value listeners\" + \"off(ref, eventType, cb) removes only the matching callback\" + \"returned-unsubscribe from onChildAdded is functionally equivalent to off()\").","packages/pyric/test/database/modular/sandbox-child-events.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M49","kind":"registry-row","surface":"rtdb-modular","behavior":"`query(ref, orderByChild(p), startAt(v), endAt(w))` window is BOTH-INCLUSIVE — children whose ordered field === `v` or === `w` are included","status":"conforms","evidence":["`unit:upstream-rtdb-probes.test.ts` (deep orderByChild nested path) + `unit:modular/queries.test.ts` (\"returns children whose ordered child is within [startAt, endAt] inclusive\"); matches oracle `rtdb-modular-orderbychild-window.json`","observation:rtdb-modular-orderbychild-window","packages/pyric/test/database/upstream-rtdb-probes.test.ts","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M5","kind":"registry-row","surface":"rtdb-modular","behavior":"`child(ref, 'sub/path')` composes paths; result inherits the parent's target","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"child(ref, 'sub') composes paths\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M6","kind":"registry-row","surface":"rtdb-modular","behavior":"`ref.parent` returns the parent ref; `root.parent === null`","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"ref.parent returns the parent ref; root.parent is null\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M60","kind":"registry-row","surface":"rtdb-modular","behavior":"`query(query(ref, c1), c2)` composes constraints — chaining folds both into one spec","status":"conforms","evidence":["`unit:modular/queries.test.ts` (\"query(query(ref, c1), c2) composes constraints\")","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M65","kind":"registry-row","surface":"rtdb-modular","behavior":"Write-boundary normalization (`nodeFromJSON`-equivalent): a value written as an array is stored as an integer-keyed object — `child(ref, '1')` returns the element, `forEach` iterates `0,1,2…` (DB-B2)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/normalization.test.ts` (\"array write is addressable by integer-string child key\" + \"forEach over an array iterates its elements\"); upstream `core/snap/nodeFromJSON.ts:118-128`, `core/snap/ChildrenNode.ts:194-230`","packages/pyric/test/database/modular/normalization.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M67","kind":"registry-row","surface":"rtdb-modular","behavior":"`null` children and empty objects are pruned at the write boundary — `set(ref, {})` is equivalent to `remove(ref)`; nested `null` collapses empty ancestors (\"empty nodes don't exist\") (DB-B3)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/normalization.test.ts` (\"set(ref, {}) is equivalent to remove\" + \"null children are pruned\"); upstream `core/snap/nodeFromJSON.ts:78-88,122-126`","packages/pyric/test/database/modular/normalization.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M7","kind":"registry-row","surface":"rtdb-modular","behavior":"`ref.root` returns the root ref of the same target","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"ref.root returns the root ref\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M70","kind":"registry-row","surface":"rtdb-modular","behavior":"`push(ref, value?)` returns a `ThenableReference` (a `DatabaseReference` with `.then`/`.catch`). The key + ref are minted CLIENT-SIDE and available synchronously even when the optional value write is rules-denied; the write is deferred onto the promise, so a denial REJECTS the awaited push rather than throwing synchronously and discarding the key (DB-B7)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/push-thenable.test.ts` (4 cases); matches oracle `packages/conformance/observations/rtdb/rtdb-push-autoid-format.json` (\"available immediately even when the subsequent server write is denied by rules\") + upstream `api/Reference_impl.ts:599-630`","observation:rtdb-push-autoid-format","packages/pyric/test/database/modular/push-thenable.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M71","kind":"registry-row","surface":"rtdb-modular","behavior":"`DataSnapshot` shape: `size` (getter), `priority` (currently always `null`), `exportVal()`, `key`, `ref`, `val()`, `exists()`, `child()`, `hasChild()`, `hasChildren()`, `forEach()`, `toJSON()`. It does NOT ship the legacy namespaced `numChildren()` method (DB-B10)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/snapshot-shape.test.ts` (\"exposes size/priority/exportVal; NOT numChildren()\"); matches oracle `packages/conformance/observations/rtdb-modular/rtdb-modular-get-snapshot-shape.json` (`hasSize: true, hasNumChildren: false`) + upstream `api/Reference_impl.ts:288-447`. **Flipped masking tests**: `modular/queries.test.ts` + `modular/sandbox-target.test.ts` asserted `snap.numChildren()` — updated to `snap.size`.","observation:rtdb-modular-get-snapshot-shape","packages/pyric/test/database/modular/snapshot-shape.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M73","kind":"registry-row","surface":"rtdb-modular","behavior":"A primitive at the ROOT is legal (`set(ref(db), 'hello')`); a subsequent child write replaces the primitive root (\"writes win\") (DB-B13)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/root-primitive.test.ts` (2 cases)","packages/pyric/test/database/modular/root-primitive.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M74","kind":"registry-row","surface":"rtdb-modular","behavior":"`onValue(ref, cb, { onlyOnce: true })` fires once then auto-unsubscribes (DB-B12)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/onvalue-onlyonce.test.ts`; upstream `api/Reference_impl.ts:975-980`","packages/pyric/test/database/modular/onvalue-onlyonce.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M8","kind":"registry-row","surface":"rtdb-modular","behavior":"`get(ref)` returns a `DataSnapshot`-shaped object with `val()`, `exists()`, `key`, `child()`, `hasChildren()`, `numChildren()`, `toJSON()`","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (snapshot shape tests)","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"ref","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"ref is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage:runtime:ref","kind":"runtime-export","surface":"storage","behavior":"ref is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"storage#13","kind":"registry-row","surface":"storage","behavior":"`ref(storage)` returns the root ref — `fullPath === ''`, `name === ''`, `parent === null`, `root === self`","status":"conforms","evidence":["`unit:reference.test.ts` (\"root reference has empty fullPath, null parent, and equal root\")","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#14","kind":"registry-row","surface":"storage","behavior":"`ref(storage, 'sessions/s1.json')` populates `fullPath`, `name` (last segment), `parent` (path without last segment)","status":"conforms","evidence":["`unit:reference.test.ts` (\"ref(storage, path) populates fullPath and name from the last segment\")","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#15","kind":"registry-row","surface":"storage","behavior":"Path normalization: leading slashes stripped (`/sessions/s1` → `sessions/s1`)","status":"conforms","evidence":["`unit:reference.test.ts` (\"normalizes leading/trailing/double slashes\")","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#16","kind":"registry-row","surface":"storage","behavior":"Path normalization: trailing slashes stripped","status":"conforms","evidence":["`unit:reference.test.ts`","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#17","kind":"registry-row","surface":"storage","behavior":"Path normalization: repeated internal slashes collapsed (`a//b` → `a/b`)","status":"conforms","evidence":["`unit:reference.test.ts`","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#18","kind":"registry-row","surface":"storage","behavior":"`ref(parent, child)` joins relative to parent's `fullPath`","status":"conforms","evidence":["`unit:reference.test.ts` (\"ref(parent, child) joins relative to the parent\")","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#19","kind":"registry-row","surface":"storage","behavior":"`parent` chain walks back to root (each `.parent` strips one segment until empty, then `null`)","status":"conforms","evidence":["`unit:reference.test.ts` (\"parent traversal walks back to root\")","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#20","kind":"registry-row","surface":"storage","behavior":"`root` accessor returns the bucket-root ref regardless of starting depth","status":"conforms","evidence":["`unit:reference.test.ts`","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#21","kind":"registry-row","surface":"storage","behavior":"`toString()` returns `gs://<bucket>/<fullPath>`","status":"conforms","evidence":["`unit:reference.test.ts` (\"toString returns gs://bucket/path\")","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#22","kind":"registry-row","surface":"storage","behavior":"Reference identity: two `ref(s, 'a/b')` calls are equal-by-`toString` but NOT `===` (value objects, not interned)","status":"conforms","evidence":["(implicit in `unit:reference.test.ts` parent-chain test — each `.parent` returns a fresh object)","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#23","kind":"registry-row","surface":"storage","behavior":"References are mirror-owned value objects; `parent` and `root` preserve the same storage handle and path semantics","status":"conforms","evidence":["`unit:reference.test.ts` pins parent traversal, root identity, bucket, and path behavior through the public reference interface.","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"}]},{"feature":"refEqual","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"refEqual is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:refEqual","kind":"runtime-export","surface":"firestore","behavior":"refEqual is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#112","kind":"registry-row","surface":"firestore","behavior":"`refEqual(a, b)` — true when paths match under the same target","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#113","kind":"registry-row","surface":"firestore","behavior":"`refEqual` is `true` for cross-flavor sandbox vs sandbox-live refs at the same path","status":"conforms","evidence":["`unit:sandbox-live-identity.test.ts` (\"refEqual returns true for live and frozen refs at the same path\")","packages/pyric/test/firestore/sandbox-live-identity.test.ts"],"assurance":"eligible"},{"id":"firestore#114","kind":"registry-row","surface":"firestore","behavior":"`refEqual` is `false` for refs at different paths","status":"conforms","evidence":["`unit:sandbox-live-identity.test.ts`","packages/pyric/test/firestore/sandbox-live-identity.test.ts"],"assurance":"eligible"},{"id":"firestore#115","kind":"registry-row","surface":"firestore","behavior":"`refEqual(sandboxRef, foreignRef)` throws `TypeError` — references not created by this sandbox mirror are unrecognized","status":"conforms","evidence":["`unit:sandbox-target.test.ts` (foreign refs throw unrecognized-reference TypeError)","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#118","kind":"registry-row","surface":"firestore","behavior":"Cross-flavor `refEqual` via `QuerySnapshot.docs[i].ref` works","status":"conforms","evidence":["`unit:sandbox-live-identity.test.ts` (\"cross-flavor refEqual via QuerySnapshot doc refs\")","packages/pyric/test/firestore/sandbox-live-identity.test.ts"],"assurance":"eligible"}]},{"feature":"refFromURL","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"refFromURL is available, has diverged fidelity, and is qualified for assurance.","caveats":["`refFromURL(db, url)` — real alias: parses the path out of the absolute database URL and delegates to `ref(db, path)`, so the returned ref resolves + reads exactly like `ref(db, path)`. Divergence: the sandbox is single-database with no host/namespace, so the URL's HOST is NOT validated against the handle (the real SDK throws if the host doesn't match the db's namespace); only the path is honored","`unit:modular/fruit-aliases.test.ts`"],"claims":[{"id":"database:runtime:refFromURL","kind":"runtime-export","surface":"database","behavior":"refFromURL is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#174","kind":"registry-row","surface":"rtdb-modular","behavior":"`refFromURL(db, url)` — real alias: parses the path out of the absolute database URL and delegates to `ref(db, path)`, so the returned ref resolves + reads exactly like `ref(db, path)`. Divergence: the sandbox is single-database with no host/namespace, so the URL's HOST is NOT validated against the handle (the real SDK throws if the host doesn't match the db's namespace); only the path is honored","status":"diverged-documented","evidence":["`unit:modular/fruit-aliases.test.ts`","packages/pyric/test/database/modular/fruit-aliases.test.ts"],"assurance":"qualified"}]},{"feature":"registerVersion","surface":"app","importPaths":["pyric/app"],"evidenceSlug":"app-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"registerVersion is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"app:runtime:registerVersion","kind":"runtime-export","surface":"app","behavior":"registerVersion is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"app#14","kind":"registry-row","surface":"app","behavior":"`registerVersion(library, version)` accepts a well-formed registration and returns undefined without throwing; malformed values emit the observed warning through the app-owned logger","status":"conforms","evidence":["oracle: `app-registry-registerversion` (firebase 12.13.0) + replay: `oracle-conformance.test.ts`","observation:app-registry-registerversion","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"reload","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"reload is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:reload","kind":"runtime-export","surface":"auth","behavior":"reload is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#86","kind":"registry-row","surface":"auth","behavior":"Re-reads the stored record into the `user` object in place, so a change made out of band (e.g. `sandbox.updateUser`) is reflected on the held reference — matching prod's server refresh. If the identity is absent from the store (including after `deleteUser`), rejects with `auth/user-token-expired`","status":"conforms","evidence":["`unit:fruit-aliases.test.ts` — an out-of-band `sandbox.updateUser` displayName change is visible on the held user after `reload`; missing-store / post-delete: `unit:upstream-auth-probes.test.ts`","packages/pyric/test/auth/fruit-aliases.test.ts","packages/pyric/test/auth/upstream-auth-probes.test.ts"],"assurance":"eligible"}]},{"feature":"remove","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"remove is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"database:runtime:remove","kind":"runtime-export","surface":"database","behavior":"remove is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#121","kind":"registry-row","surface":"rtdb-modular","behavior":"Removes the value AND all children; subsequent `get` returns `null`-val snapshot","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb/rtdb-remove-vs-set-null.json`","observation:rtdb-remove-vs-set-null"],"assurance":"eligible"},{"id":"rtdb-modular#122","kind":"registry-row","surface":"rtdb-modular","behavior":"Idempotent — `remove` on a path that's already absent resolves successfully (no-throw)","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-remove-idempotent.json` — `remove` on a never-written path observed `threw: false, afterExists: false`.","observation:rtdb-modular-remove-idempotent"],"assurance":"eligible"},{"id":"rtdb-modular#123","kind":"registry-row","surface":"rtdb-modular","behavior":"`remove(ref)` and `set(ref, null)` produce the same end state — locks the documented RTDB invariant","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb/rtdb-remove-vs-set-null.json`","observation:rtdb-remove-vs-set-null"],"assurance":"eligible"},{"id":"rtdb-modular#M12","kind":"registry-row","surface":"rtdb-modular","behavior":"`remove(ref)` is equivalent to `set(ref, null)` (same end state)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-target.test.ts` (\"remove and set(null) produce identical end-state\"); matches oracle observation `packages/conformance/observations/rtdb/rtdb-remove-vs-set-null.json`","observation:rtdb-remove-vs-set-null","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M25","kind":"registry-row","surface":"rtdb-modular","behavior":"Rules-denied remove throws the same plain-`Error` `PERMISSION_DENIED` shape","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-target.test.ts` (\"rules-denied remove throws the same plain Error shape\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M45","kind":"registry-row","surface":"rtdb-modular","behavior":"`onChildRemoved` has NO initial replay; fires once when a direct child is deleted (via `remove(child)` or `set(child, null)`); snapshot carries the PRIOR (now-removed) value","status":"conforms","evidence":["`unit:upstream-rtdb-probes.test.ts` (parent wipe fan-out via remove(parent) / set(parent, scalar)) + `unit:modular/sandbox-child-events.test.ts` (single-child delete carries PRIOR val); matches oracle `rtdb-modular-onchildremoved-fires-on-delete.json`","observation:rtdb-modular-onchildremoved-fires-on-delete","packages/pyric/test/database/upstream-rtdb-probes.test.ts","packages/pyric/test/database/modular/sandbox-child-events.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M48","kind":"registry-row","surface":"rtdb-modular","behavior":"`off(ref, eventType?, callback?)` variants: `off(ref, 'value')` / `off(ref, 'child_added')` / `off(ref, eventType, cb)` remove the targeted subset; returned-unsubscribe from `onChild*` is equivalent to `off(ref, eventType, cb)`","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-child-events.test.ts` (\"off(ref, \\\"child_added\\\") removes only that event variety\" + \"off(ref, \\\"value\\\") removes only value listeners\" + \"off(ref, eventType, cb) removes only the matching callback\" + \"returned-unsubscribe from onChildAdded is functionally equivalent to off()\").","packages/pyric/test/database/modular/sandbox-child-events.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M67","kind":"registry-row","surface":"rtdb-modular","behavior":"`null` children and empty objects are pruned at the write boundary — `set(ref, {})` is equivalent to `remove(ref)`; nested `null` collapses empty ancestors (\"empty nodes don't exist\") (DB-B3)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/normalization.test.ts` (\"set(ref, {}) is equivalent to remove\" + \"null children are pruned\"); upstream `core/snap/nodeFromJSON.ts:78-88,122-126`","packages/pyric/test/database/modular/normalization.test.ts"],"assurance":"eligible"}]},{"feature":"removeAll","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"removeAll is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#168","kind":"registry-row","surface":"firestore-rules","behavior":"`List.concat()`/`removeAll()`/`toSet()` (Item 5.2) in rules","status":"conforms","evidence":["`oracle:rules-firestore-list-methods-concat-removeall-toset` — production Firestore Rules Test API verdicts for corpus scenario \"list-methods-concat-removeall-toset\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`; all cases match production.","observation:rules-firestore-list-methods-concat-removeall-toset","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"replace","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"replace is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"rtdb-rules#11","kind":"registry-row","surface":"rtdb-rules","behavior":"String methods on a snapshot value — `beginsWith`, `contains`, `endsWith`, `matches` with a regex literal, `.length`, `toLowerCase`, `toUpperCase`, and replace-ALL `replace`","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves `String.replace` substitutes EVERY occurrence of the substring, not only the first — production ALLOWS the write whose rule is `newData.val().replace('_', '-') === 'a-b-c'` for the value `a_b_c`, which holds only under replace-all. The simulator delegated to JavaScript's `String.prototype.replace`, which given a string pattern substitutes only the first occurrence, and DENIED that write; the substitution now replaces every occurrence and the two-underscore case guards the regression. The same capture proves `toUpperCase` is a valid production rule method that the simulator's validator previously rejected outright as unknown. `oracle:rules-rtdb-r11-string-validation` matches production verdict-for-verdict on all 18 cases.","observation:rules-rtdb-r11-string-validation","packages/pyric/test/rules/rtdb/rules-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"request","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"request is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.binding.request","kind":"rules-construct","surface":"firestore-rules","behavior":"request is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.firestore.Request"],"assurance":"eligible"}]},{"feature":"request","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"request is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage.binding.request","kind":"rules-construct","surface":"storage-rules","behavior":"request is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/security/storage/request"],"assurance":"eligible"}]},{"feature":"request.auth","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"request.auth is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.binding.request.auth","kind":"rules-construct","surface":"firestore-rules","behavior":"request.auth is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.firestore.Request#auth"],"assurance":"eligible"}]},{"feature":"request.auth","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"request.auth is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#98","kind":"registry-row","surface":"storage-rules","behavior":"`evaluateStorageRules` matches `match /sessions/{id} { allow read: if request.auth != null; }` for an authed read","status":"conforms","evidence":["`unit:rules.test.ts` (\"allows authenticated reads of /sessions/{id}\")","packages/pyric/test/storage/rules.test.ts"],"assurance":"eligible"},{"id":"storage-rules#99","kind":"registry-row","surface":"storage-rules","behavior":"`evaluateStorageRules` denies anonymous reads when the rule requires `request.auth != null`","status":"conforms","evidence":["`unit:rules.test.ts` (\"denies anonymous reads\")","packages/pyric/test/storage/rules.test.ts"],"assurance":"eligible"},{"id":"storage.binding.request.auth","kind":"rules-construct","surface":"storage-rules","behavior":"request.auth is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/security/storage/request#auth"],"assurance":"eligible"}]},{"feature":"request.auth.token","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"request.auth.token is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.binding.request.auth.token","kind":"rules-construct","surface":"firestore-rules","behavior":"request.auth.token is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.firestore.Request#auth"],"assurance":"eligible"}]},{"feature":"request.auth.token","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"request.auth.token is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage.binding.request.auth.token","kind":"rules-construct","surface":"storage-rules","behavior":"request.auth.token is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/security/storage/request#auth"],"assurance":"eligible"}]},{"feature":"request.auth.uid","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"request.auth.uid is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.binding.request.auth.uid","kind":"rules-construct","surface":"firestore-rules","behavior":"request.auth.uid is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.firestore.Request#auth"],"assurance":"eligible"}]},{"feature":"request.auth.uid","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"request.auth.uid is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage.binding.request.auth.uid","kind":"rules-construct","surface":"storage-rules","behavior":"request.auth.uid is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/security/storage/request#auth"],"assurance":"eligible"}]},{"feature":"request.method","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"request.method is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.binding.request.method","kind":"rules-construct","surface":"firestore-rules","behavior":"request.method is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.firestore.Request#method"],"assurance":"eligible"}]},{"feature":"request.method","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"request.method is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#117","kind":"registry-row","surface":"storage-rules","behavior":"`request.resource.size` arithmetic bounds (`+`/`-`/`*`/`/`, `>=`/`<=`), request/existing content-type and custom `metadata` checks, `request.method`/`request.path`, a `request.auth.token` custom-claim branch, granular `allow list`, and a recursive `{allPaths=**}` public read tree","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the evaluator matches the production Storage Rules Test API verdict-for-verdict on all 8 cases (owner-scoped size-bounded upload, immutable-content-type update, list grant, public recursive read). `oracle:rules-storage-metadata-verbs-and-arithmetic` — replayed by `packages/pyric/test/storage/rules-oracle-conformance.test.ts`.","observation:rules-storage-metadata-verbs-and-arithmetic","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.binding.request.method","kind":"rules-construct","surface":"storage-rules","behavior":"request.method is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/security/storage/request"],"assurance":"eligible"}]},{"feature":"request.path","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"request.path is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.binding.request.path","kind":"rules-construct","surface":"firestore-rules","behavior":"request.path is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.firestore.Request#path"],"assurance":"eligible"}]},{"feature":"request.path","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"request.path is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#117","kind":"registry-row","surface":"storage-rules","behavior":"`request.resource.size` arithmetic bounds (`+`/`-`/`*`/`/`, `>=`/`<=`), request/existing content-type and custom `metadata` checks, `request.method`/`request.path`, a `request.auth.token` custom-claim branch, granular `allow list`, and a recursive `{allPaths=**}` public read tree","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the evaluator matches the production Storage Rules Test API verdict-for-verdict on all 8 cases (owner-scoped size-bounded upload, immutable-content-type update, list grant, public recursive read). `oracle:rules-storage-metadata-verbs-and-arithmetic` — replayed by `packages/pyric/test/storage/rules-oracle-conformance.test.ts`.","observation:rules-storage-metadata-verbs-and-arithmetic","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.binding.request.path","kind":"rules-construct","surface":"storage-rules","behavior":"request.path is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/security/storage/request"],"assurance":"eligible"}]},{"feature":"request.query","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"request.query is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["`request.path`/`request.query`/`resource.id`/`resource.__name__` globals (Item 6) in rules","`oracle:rules-firestore-globals-request-path-and-resource-id` — production Firestore Rules Test API verdicts for corpus scenario \"globals-request-path-and-resource-id\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator models `request.query` as an empty map on the empty-query case where production denies the equivalent comparison — pinned KNOWN_DIVERGENCE. Contamination scope is `request.query` ALONE: the scenario's `request.path` cases conform, and its `resource.id`/`resource.__name__` cases conform because they run on a `create` (where `resource` is null pre-write). Resource identity on an EXISTING document is scoped to firestore-rules#183."],"claims":[{"id":"firestore-rules#166","kind":"registry-row","surface":"firestore-rules","behavior":"`request.path`/`request.query`/`resource.id`/`resource.__name__` globals (Item 6) in rules","status":"diverged-documented","evidence":["`oracle:rules-firestore-globals-request-path-and-resource-id` — production Firestore Rules Test API verdicts for corpus scenario \"globals-request-path-and-resource-id\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator models `request.query` as an empty map on the empty-query case where production denies the equivalent comparison — pinned KNOWN_DIVERGENCE. Contamination scope is `request.query` ALONE: the scenario's `request.path` cases conform, and its `resource.id`/`resource.__name__` cases conform because they run on a `create` (where `resource` is null pre-write). Resource identity on an EXISTING document is scoped to firestore-rules#183.","observation:rules-firestore-globals-request-path-and-resource-id","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"ineligible"},{"id":"firestore.binding.request.query","kind":"rules-construct","surface":"firestore-rules","behavior":"request.query is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.firestore.Request#query"],"assurance":"ineligible"}]},{"feature":"request.resource","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"request.resource is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.binding.request.resource","kind":"rules-construct","surface":"firestore-rules","behavior":"request.resource is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.firestore.Request#resource"],"assurance":"eligible"}]},{"feature":"request.resource","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"request.resource is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#117","kind":"registry-row","surface":"storage-rules","behavior":"`request.resource.size` arithmetic bounds (`+`/`-`/`*`/`/`, `>=`/`<=`), request/existing content-type and custom `metadata` checks, `request.method`/`request.path`, a `request.auth.token` custom-claim branch, granular `allow list`, and a recursive `{allPaths=**}` public read tree","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the evaluator matches the production Storage Rules Test API verdict-for-verdict on all 8 cases (owner-scoped size-bounded upload, immutable-content-type update, list grant, public recursive read). `oracle:rules-storage-metadata-verbs-and-arithmetic` — replayed by `packages/pyric/test/storage/rules-oracle-conformance.test.ts`.","observation:rules-storage-metadata-verbs-and-arithmetic","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.binding.request.resource","kind":"rules-construct","surface":"storage-rules","behavior":"request.resource is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/security/storage/request#resource"],"assurance":"eligible"}]},{"feature":"request.resource.contentType","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"request.resource.contentType is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#101","kind":"registry-row","surface":"storage-rules","behavior":"`evaluateStorageRules` supports `request.resource.contentType == '<mime>'` constraints","status":"conforms","evidence":["`unit:rules.test.ts` (mime constraint inside the session-archive ruleset)","packages/pyric/test/storage/rules.test.ts"],"assurance":"eligible"},{"id":"storage.binding.request.resource.contentType","kind":"rules-construct","surface":"storage-rules","behavior":"request.resource.contentType is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/security/storage/request#resource"],"assurance":"eligible"}]},{"feature":"request.resource.data","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"request.resource.data is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#183","kind":"registry-row","surface":"firestore-rules","behavior":"Resource identity (`resource.id`/`resource.__name__`/`request.resource.id`) on an EXISTING document (RULES-B12) — production leaves the identity keys ABSENT, so reading one errors → DENY, the error survives negation, and only a determining `||` operand absorbs it","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 13 cases. Production builds `resource` (and `request.resource`) from the supplied document alone and derives NO identity from the request path, so `resource.id`/`resource.__name__`/`request.resource.id` read as absent properties — verbatim `Property id is undefined on object.` / `Property __name__ is undefined on object.` — which absorb to DENY. The simulator previously SYNTHESIZED `id`/`__name__` from the request path on get/list/update/delete, so `resource.id == id` ALLOWed where production DENIES: an over-permissive divergence, now removed. The negation cases (`resource.id != 'zzz'`, `!(resource.id == 'zzz')`) pin that the absent read is a propagating error rather than a false, which an absent-as-undefined model would false-ALLOW. `oracle:rules-firestore-resource-document-identity` — replayed by `unit:rules/oracle-conformance.test.ts`.","observation:rules-firestore-resource-document-identity","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"firestore.binding.request.resource.data","kind":"rules-construct","surface":"firestore-rules","behavior":"request.resource.data is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.firestore.Resource#data"],"assurance":"eligible"}]},{"feature":"request.resource.id","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"diverged","assurance":"ineligible","summary":"request.resource.id is available, has diverged fidelity, and is ineligible for assurance.","caveats":["request.resource.id is in the official language, but production's Rules Test API does not populate it: request.resource is built from the supplied payload alone, so `.id` is an absent property and reading it errors → DENY. The simulator matches — its handler builds request.resource as `{ data }` only (simulator/handler.ts), so the evaluator's absent-key error yields production's verdict. The same now holds for the existing document: `resource` carries `data` ONLY, no synthesized `id`/`__name__` (RULES-B12, firestore-rules#183)."],"claims":[{"id":"firestore-rules#183","kind":"registry-row","surface":"firestore-rules","behavior":"Resource identity (`resource.id`/`resource.__name__`/`request.resource.id`) on an EXISTING document (RULES-B12) — production leaves the identity keys ABSENT, so reading one errors → DENY, the error survives negation, and only a determining `||` operand absorbs it","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 13 cases. Production builds `resource` (and `request.resource`) from the supplied document alone and derives NO identity from the request path, so `resource.id`/`resource.__name__`/`request.resource.id` read as absent properties — verbatim `Property id is undefined on object.` / `Property __name__ is undefined on object.` — which absorb to DENY. The simulator previously SYNTHESIZED `id`/`__name__` from the request path on get/list/update/delete, so `resource.id == id` ALLOWed where production DENIES: an over-permissive divergence, now removed. The negation cases (`resource.id != 'zzz'`, `!(resource.id == 'zzz')`) pin that the absent read is a propagating error rather than a false, which an absent-as-undefined model would false-ALLOW. `oracle:rules-firestore-resource-document-identity` — replayed by `unit:rules/oracle-conformance.test.ts`.","observation:rules-firestore-resource-document-identity","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"firestore.binding.request.resource.id","kind":"rules-construct","surface":"firestore-rules","behavior":"request.resource.id is in the official language, but production's Rules Test API does not populate it: request.resource is built from the supplied payload alone, so `.id` is an absent property and reading it errors → DENY. The simulator matches — its handler builds request.resource as `{ data }` only (simulator/handler.ts), so the evaluator's absent-key error yields production's verdict. The same now holds for the existing document: `resource` carries `data` ONLY, no synthesized `id`/`__name__` (RULES-B12, firestore-rules#183).","status":"rejected","evidence":["https://firebase.google.com/docs/reference/rules/rules.firestore.Resource#id","Error: firestore.rules line [5], column [22]. Property id is undefined on object."],"assurance":"ineligible"}]},{"feature":"request.resource.metadata","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"request.resource.metadata is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage.binding.request.resource.metadata","kind":"rules-construct","surface":"storage-rules","behavior":"request.resource.metadata is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/security/storage/request#resource"],"assurance":"eligible"}]},{"feature":"request.resource.size","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"request.resource.size is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#100","kind":"registry-row","surface":"storage-rules","behavior":"`evaluateStorageRules` supports `request.resource.size < N` constraints (with arithmetic literals like `10 * 1024 * 1024`)","status":"conforms","evidence":["`unit:rules.test.ts` (\"allows JSON writes under 10MB\")","packages/pyric/test/storage/rules.test.ts"],"assurance":"eligible"},{"id":"storage.binding.request.resource.size","kind":"rules-construct","surface":"storage-rules","behavior":"request.resource.size is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/security/storage/request#resource"],"assurance":"eligible"}]},{"feature":"request.time","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"request.time is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#180","kind":"registry-row","surface":"firestore-rules","behavior":"`request.time` Timestamp accessors (year/month/day/hours/minutes/seconds/nanos/dayOfWeek/dayOfYear/toMillis/date/time), `math.floor/round/sqrt/pow/isNaN`, `int()/float()/string()` casts, `request.method`, and `>=` / `*` operators in rules","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 3 cases (request.time pinned via requestTime for determinism). `oracle:rules-firestore-time-math-and-casts` — replayed by `unit:rules/oracle-conformance.test.ts`.","observation:rules-firestore-time-math-and-casts","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"firestore.binding.request.time","kind":"rules-construct","surface":"firestore-rules","behavior":"request.time is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.firestore.Request#time"],"assurance":"eligible"}]},{"feature":"request.time","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"request.time is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#112","kind":"registry-row","surface":"storage-rules","behavior":"`request.time` compared against `timestamp.date(y,m,d)` and `timestamp.value(ms)` constructors","status":"conforms","evidence":["NEW ROW, 2026-07-10: production capture proves the evaluator supports `request.time` comparisons against both timestamp constructors. `oracle:rules-storage-request-time-timestamp` matches production verdict-for-verdict on all 4 cases (deadline-before/after via `timestamp.date()`, epoch-bound before/after via `timestamp.value()`).","observation:rules-storage-request-time-timestamp","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.binding.request.time","kind":"rules-construct","surface":"storage-rules","behavior":"request.time is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/security/storage/request#time"],"assurance":"eligible"}]},{"feature":"RequestOptions","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"RequestOptions is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:RequestOptions","kind":"type-export","surface":"ai","behavior":"RequestOptions is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"requiredFields","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"requiredFields is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#178","kind":"registry-row","surface":"firestore-rules","behavior":"Required-fields validation idiom in rules — `request.resource.data.keys().hasAll()/hasOnly()` and the `diff().addedKeys()/removedKeys()/changedKeys()/affectedKeys()/unchangedKeys()` MapDiff family gating field-level mutations","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 7 cases (exact required-field set on create, field-scoped update via MapDiff). `oracle:rules-firestore-required-fields-and-mapdiff` — replayed by `unit:rules/oracle-conformance.test.ts`.","observation:rules-firestore-required-fields-and-mapdiff","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"resource","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"resource is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#184","kind":"registry-row","surface":"firestore-rules","behavior":"Request-target `resource` on a missing document (RULES-B13) — get/update/delete existence guards, null comparison, and data access all error to DENY","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator matches the Firestore Rules Test API verdict-for-verdict on all 9 cases. A missing request target makes the `resource` global an error value: `resource != null`, `resource == null`, and `resource.data.value` all DENY. The simulator previously constructed `{ data: {} }` for missing get/update/delete requests, so the ordinary `resource != null` existence guard false-ALLOWed all three operations. Modeling the target as raw null fixes that guard but makes `resource == null` false-ALLOW, so the evaluator now raises `Null value error.` when the absent `resource` identifier itself is evaluated. Existing-document get/update/delete and data-access controls still ALLOW. `oracle:rules-firestore-resource-missing-document` — replayed by `packages/pyric/test/rules/oracle-conformance.test.ts`.","observation:rules-firestore-resource-missing-document","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"firestore.binding.resource","kind":"rules-construct","surface":"firestore-rules","behavior":"resource is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.firestore.Resource"],"assurance":"eligible"}]},{"feature":"resource","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"resource is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["`resource` on a create where no object exists: the create-if-absent guard `allow create: if resource == null`","divergence, over-permissive (the evaluator ALLOWs where production DENIEs, the highest-severity direction defined in `docs/storage/reference/conformance-gaps.md`). `oracle:rules-storage-verbs-umbrella-granular`, case \"create allowed when object does not exist (resource == null)\": production DENIES. Production raises a null value error on a `resource` reference in a create where no object exists, and the errored expression denies, so a `create` rule guarded by `resource == null` never allows. The evaluator models `resource` as null on create, evaluates the comparison as documented, and ALLOWS. Live-probed against production before pinning with both an omitted `resource` field and an explicit null, which denied identically, ruling out a capture-harness wire-shape bug. Both sides pinned in `unit:storage/rules-oracle-conformance.test.ts` KNOWN_DIVERGENCES. Same error-value class as the Firestore `resource` identity on a missing document."],"claims":[{"id":"storage-rules#117","kind":"registry-row","surface":"storage-rules","behavior":"`request.resource.size` arithmetic bounds (`+`/`-`/`*`/`/`, `>=`/`<=`), request/existing content-type and custom `metadata` checks, `request.method`/`request.path`, a `request.auth.token` custom-claim branch, granular `allow list`, and a recursive `{allPaths=**}` public read tree","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the evaluator matches the production Storage Rules Test API verdict-for-verdict on all 8 cases (owner-scoped size-bounded upload, immutable-content-type update, list grant, public recursive read). `oracle:rules-storage-metadata-verbs-and-arithmetic` — replayed by `packages/pyric/test/storage/rules-oracle-conformance.test.ts`.","observation:rules-storage-metadata-verbs-and-arithmetic","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage-rules#118","kind":"registry-row","surface":"storage-rules","behavior":"`resource` on a create where no object exists: the create-if-absent guard `allow create: if resource == null`","status":"diverged-documented","evidence":["divergence, over-permissive (the evaluator ALLOWs where production DENIEs, the highest-severity direction defined in `docs/storage/reference/conformance-gaps.md`). `oracle:rules-storage-verbs-umbrella-granular`, case \"create allowed when object does not exist (resource == null)\": production DENIES. Production raises a null value error on a `resource` reference in a create where no object exists, and the errored expression denies, so a `create` rule guarded by `resource == null` never allows. The evaluator models `resource` as null on create, evaluates the comparison as documented, and ALLOWS. Live-probed against production before pinning with both an omitted `resource` field and an explicit null, which denied identically, ruling out a capture-harness wire-shape bug. Both sides pinned in `unit:storage/rules-oracle-conformance.test.ts` KNOWN_DIVERGENCES. Same error-value class as the Firestore `resource` identity on a missing document.","observation:rules-storage-verbs-umbrella-granular","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"ineligible"},{"id":"storage.binding.resource","kind":"rules-construct","surface":"storage-rules","behavior":"resource is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/security/storage/resource"],"assurance":"ineligible"}]},{"feature":"resource.bucket","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"resource.bucket is available, has conforms fidelity, and is eligible for assurance.","caveats":["resource.bucket is the bucket the object resides in, sourced from the persisted record. Production returns it as a literal on the resource map; an absent bucket denies."],"claims":[{"id":"storage-rules#116","kind":"registry-row","surface":"storage-rules","behavior":"`resource.name` (full object path), `resource.timeCreated`, `resource.updated`, `resource.bucket` — the object-identity and time fields of the existing-object binding, plus `duration.value(n, unit)`","status":"conforms","evidence":["ROW CORRECTED, 2026-07-12: the fields are now modeled, sourced from the persisted object record. `oracle:rules-storage-resource-object-identity` matches production verdict-for-verdict on all 9 cases — an extension guard (`resource.name.matches`), a freshness window (`resource.timeCreated + duration.value(1, 'h')`), an immutability check (`resource.timeCreated == resource.updated`), and an absent-property negation. Production semantics pinned by the capture: `resource.name` is the object's FULL path within the bucket (GCS object-name convention, sourced from the persisted record's `fullPath`, not the client SDK's last-segment `name`); `timeCreated`/`updated` are timestamps (production rejects an int with \"Unsupported operation error. Received: int < timestamp\"); the update-time field is `updated` — there is NO `resource.timeUpdated`. An absent property is an evaluation error that absorbs to DENY and SURVIVES negation, so `resource.name != 'x'` on an object with no name denies rather than false-allowing. The prior row recorded these fields as an unsupported gap; that gap is closed.","observation:rules-storage-resource-object-identity","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.binding.resource.bucket","kind":"rules-construct","surface":"storage-rules","behavior":"resource.bucket is the bucket the object resides in, sourced from the persisted record. Production returns it as a literal on the resource map; an absent bucket denies.","status":"accepted","evidence":["https://firebase.google.com/docs/reference/security/storage/resource#bucket"],"assurance":"eligible"}]},{"feature":"resource.contentType","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"resource.contentType is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage.binding.resource.contentType","kind":"rules-construct","surface":"storage-rules","behavior":"resource.contentType is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/security/storage/resource#contentType"],"assurance":"eligible"}]},{"feature":"resource.data","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"resource.data is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#183","kind":"registry-row","surface":"firestore-rules","behavior":"Resource identity (`resource.id`/`resource.__name__`/`request.resource.id`) on an EXISTING document (RULES-B12) — production leaves the identity keys ABSENT, so reading one errors → DENY, the error survives negation, and only a determining `||` operand absorbs it","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 13 cases. Production builds `resource` (and `request.resource`) from the supplied document alone and derives NO identity from the request path, so `resource.id`/`resource.__name__`/`request.resource.id` read as absent properties — verbatim `Property id is undefined on object.` / `Property __name__ is undefined on object.` — which absorb to DENY. The simulator previously SYNTHESIZED `id`/`__name__` from the request path on get/list/update/delete, so `resource.id == id` ALLOWed where production DENIES: an over-permissive divergence, now removed. The negation cases (`resource.id != 'zzz'`, `!(resource.id == 'zzz')`) pin that the absent read is a propagating error rather than a false, which an absent-as-undefined model would false-ALLOW. `oracle:rules-firestore-resource-document-identity` — replayed by `unit:rules/oracle-conformance.test.ts`.","observation:rules-firestore-resource-document-identity","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"firestore-rules#184","kind":"registry-row","surface":"firestore-rules","behavior":"Request-target `resource` on a missing document (RULES-B13) — get/update/delete existence guards, null comparison, and data access all error to DENY","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator matches the Firestore Rules Test API verdict-for-verdict on all 9 cases. A missing request target makes the `resource` global an error value: `resource != null`, `resource == null`, and `resource.data.value` all DENY. The simulator previously constructed `{ data: {} }` for missing get/update/delete requests, so the ordinary `resource != null` existence guard false-ALLOWed all three operations. Modeling the target as raw null fixes that guard but makes `resource == null` false-ALLOW, so the evaluator now raises `Null value error.` when the absent `resource` identifier itself is evaluated. Existing-document get/update/delete and data-access controls still ALLOW. `oracle:rules-firestore-resource-missing-document` — replayed by `packages/pyric/test/rules/oracle-conformance.test.ts`.","observation:rules-firestore-resource-missing-document","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"firestore.binding.resource.data","kind":"rules-construct","surface":"firestore-rules","behavior":"resource.data is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.firestore.Resource#data"],"assurance":"eligible"}]},{"feature":"resource.id","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"diverged","assurance":"ineligible","summary":"resource.id is available, has diverged fidelity, and is ineligible for assurance.","caveats":["`get()` of a missing document (RULES-B8) in rules — resource identity (`id`/`__name__`) exposure on a mocked/missing get() result","`oracle:rules-firestore-get-missing-doc` — production Firestore Rules Test API verdicts for corpus scenario \"get-missing-doc\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator synthesizes a resource identity (`id`, `__name__`) for mocked get() results that production leaves absent, on 2 scenario cases — pinned KNOWN_DIVERGENCE"],"claims":[{"id":"firestore-rules#165","kind":"registry-row","surface":"firestore-rules","behavior":"`get()` of a missing document (RULES-B8) in rules — resource identity (`id`/`__name__`) exposure on a mocked/missing get() result","status":"diverged-documented","evidence":["`oracle:rules-firestore-get-missing-doc` — production Firestore Rules Test API verdicts for corpus scenario \"get-missing-doc\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator synthesizes a resource identity (`id`, `__name__`) for mocked get() results that production leaves absent, on 2 scenario cases — pinned KNOWN_DIVERGENCE","observation:rules-firestore-get-missing-doc","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"ineligible"},{"id":"firestore-rules#183","kind":"registry-row","surface":"firestore-rules","behavior":"Resource identity (`resource.id`/`resource.__name__`/`request.resource.id`) on an EXISTING document (RULES-B12) — production leaves the identity keys ABSENT, so reading one errors → DENY, the error survives negation, and only a determining `||` operand absorbs it","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 13 cases. Production builds `resource` (and `request.resource`) from the supplied document alone and derives NO identity from the request path, so `resource.id`/`resource.__name__`/`request.resource.id` read as absent properties — verbatim `Property id is undefined on object.` / `Property __name__ is undefined on object.` — which absorb to DENY. The simulator previously SYNTHESIZED `id`/`__name__` from the request path on get/list/update/delete, so `resource.id == id` ALLOWed where production DENIES: an over-permissive divergence, now removed. The negation cases (`resource.id != 'zzz'`, `!(resource.id == 'zzz')`) pin that the absent read is a propagating error rather than a false, which an absent-as-undefined model would false-ALLOW. `oracle:rules-firestore-resource-document-identity` — replayed by `unit:rules/oracle-conformance.test.ts`.","observation:rules-firestore-resource-document-identity","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"firestore.binding.resource.id","kind":"rules-construct","surface":"firestore-rules","behavior":"resource.id is enumerated in the firestore rules-language inventory","status":"rejected","evidence":["https://firebase.google.com/docs/reference/rules/rules.firestore.Resource#id","Error: firestore.rules line [5], column [22]. Property id is undefined on object. Absent on an EXISTING document too — production derives no identity from the request path. The error PROPAGATES: `resource.id != 'zzz'` DENIES (it does not become true), and only a determining `||` operand absorbs it (RULES-B12, firestore-rules#183)."],"assurance":"ineligible"}]},{"feature":"resource.metadata","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"resource.metadata is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#114","kind":"registry-row","surface":"storage-rules","behavior":"`resource.metadata.<key>` custom-metadata access in dotted (`resource.metadata.owner`) and bracket (`resource.metadata['owner']`) form, including missing-key deny","status":"conforms","evidence":["NEW ROW, 2026-07-10: production capture proves dotted and bracket metadata access resolve identically, and a missing key denies. `oracle:rules-storage-metadata-access` matches production verdict-for-verdict on all 5 cases.","observation:rules-storage-metadata-access","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.binding.resource.metadata","kind":"rules-construct","surface":"storage-rules","behavior":"resource.metadata is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/security/storage/resource#metadata"],"assurance":"eligible"}]},{"feature":"resource.__name__","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"diverged","assurance":"ineligible","summary":"resource.__name__ is available, has diverged fidelity, and is ineligible for assurance.","caveats":["`get()` of a missing document (RULES-B8) in rules — resource identity (`id`/`__name__`) exposure on a mocked/missing get() result","`oracle:rules-firestore-get-missing-doc` — production Firestore Rules Test API verdicts for corpus scenario \"get-missing-doc\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator synthesizes a resource identity (`id`, `__name__`) for mocked get() results that production leaves absent, on 2 scenario cases — pinned KNOWN_DIVERGENCE"],"claims":[{"id":"firestore-rules#165","kind":"registry-row","surface":"firestore-rules","behavior":"`get()` of a missing document (RULES-B8) in rules — resource identity (`id`/`__name__`) exposure on a mocked/missing get() result","status":"diverged-documented","evidence":["`oracle:rules-firestore-get-missing-doc` — production Firestore Rules Test API verdicts for corpus scenario \"get-missing-doc\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator synthesizes a resource identity (`id`, `__name__`) for mocked get() results that production leaves absent, on 2 scenario cases — pinned KNOWN_DIVERGENCE","observation:rules-firestore-get-missing-doc","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"ineligible"},{"id":"firestore-rules#183","kind":"registry-row","surface":"firestore-rules","behavior":"Resource identity (`resource.id`/`resource.__name__`/`request.resource.id`) on an EXISTING document (RULES-B12) — production leaves the identity keys ABSENT, so reading one errors → DENY, the error survives negation, and only a determining `||` operand absorbs it","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 13 cases. Production builds `resource` (and `request.resource`) from the supplied document alone and derives NO identity from the request path, so `resource.id`/`resource.__name__`/`request.resource.id` read as absent properties — verbatim `Property id is undefined on object.` / `Property __name__ is undefined on object.` — which absorb to DENY. The simulator previously SYNTHESIZED `id`/`__name__` from the request path on get/list/update/delete, so `resource.id == id` ALLOWed where production DENIES: an over-permissive divergence, now removed. The negation cases (`resource.id != 'zzz'`, `!(resource.id == 'zzz')`) pin that the absent read is a propagating error rather than a false, which an absent-as-undefined model would false-ALLOW. `oracle:rules-firestore-resource-document-identity` — replayed by `unit:rules/oracle-conformance.test.ts`.","observation:rules-firestore-resource-document-identity","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"firestore.binding.resource.__name__","kind":"rules-construct","surface":"firestore-rules","behavior":"resource.__name__ is enumerated in the firestore rules-language inventory","status":"rejected","evidence":["https://firebase.google.com/docs/reference/rules/rules.firestore.Resource#__name__","Error: firestore.rules line [5], column [22]. Property __name__ is undefined on object. Absent on an EXISTING document too — production derives no identity from the request path. The error propagates through negation and absorbs to DENY (RULES-B12, firestore-rules#183)."],"assurance":"ineligible"}]},{"feature":"resource.name","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"resource.name is available, has conforms fidelity, and is eligible for assurance.","caveats":["resource.name is the object's FULL path within the bucket (GCS object-name convention, e.g. `uploads/pic.png`), sourced from the persisted record's fullPath — NOT the client SDK's last-path-segment name. Production returns it as a literal on the resource map; an absent name is an evaluation error that denies."],"claims":[{"id":"storage-rules#116","kind":"registry-row","surface":"storage-rules","behavior":"`resource.name` (full object path), `resource.timeCreated`, `resource.updated`, `resource.bucket` — the object-identity and time fields of the existing-object binding, plus `duration.value(n, unit)`","status":"conforms","evidence":["ROW CORRECTED, 2026-07-12: the fields are now modeled, sourced from the persisted object record. `oracle:rules-storage-resource-object-identity` matches production verdict-for-verdict on all 9 cases — an extension guard (`resource.name.matches`), a freshness window (`resource.timeCreated + duration.value(1, 'h')`), an immutability check (`resource.timeCreated == resource.updated`), and an absent-property negation. Production semantics pinned by the capture: `resource.name` is the object's FULL path within the bucket (GCS object-name convention, sourced from the persisted record's `fullPath`, not the client SDK's last-segment `name`); `timeCreated`/`updated` are timestamps (production rejects an int with \"Unsupported operation error. Received: int < timestamp\"); the update-time field is `updated` — there is NO `resource.timeUpdated`. An absent property is an evaluation error that absorbs to DENY and SURVIVES negation, so `resource.name != 'x'` on an object with no name denies rather than false-allowing. The prior row recorded these fields as an unsupported gap; that gap is closed.","observation:rules-storage-resource-object-identity","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.binding.resource.name","kind":"rules-construct","surface":"storage-rules","behavior":"resource.name is the object's FULL path within the bucket (GCS object-name convention, e.g. `uploads/pic.png`), sourced from the persisted record's fullPath — NOT the client SDK's last-path-segment name. Production returns it as a literal on the resource map; an absent name is an evaluation error that denies.","status":"accepted","evidence":["https://firebase.google.com/docs/reference/security/storage/resource#name"],"assurance":"eligible"}]},{"feature":"resource.size","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"resource.size is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage.binding.resource.size","kind":"rules-construct","surface":"storage-rules","behavior":"resource.size is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/security/storage/resource#size"],"assurance":"eligible"}]},{"feature":"resource.timeCreated","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"resource.timeCreated is available, has conforms fidelity, and is eligible for assurance.","caveats":["resource.timeCreated is a timestamp (ISO-8601 in the persisted record; the evaluator compares it as epoch millis against request.time). Production rejects an int in a timestamp comparison; an absent timeCreated denies."],"claims":[{"id":"storage-rules#116","kind":"registry-row","surface":"storage-rules","behavior":"`resource.name` (full object path), `resource.timeCreated`, `resource.updated`, `resource.bucket` — the object-identity and time fields of the existing-object binding, plus `duration.value(n, unit)`","status":"conforms","evidence":["ROW CORRECTED, 2026-07-12: the fields are now modeled, sourced from the persisted object record. `oracle:rules-storage-resource-object-identity` matches production verdict-for-verdict on all 9 cases — an extension guard (`resource.name.matches`), a freshness window (`resource.timeCreated + duration.value(1, 'h')`), an immutability check (`resource.timeCreated == resource.updated`), and an absent-property negation. Production semantics pinned by the capture: `resource.name` is the object's FULL path within the bucket (GCS object-name convention, sourced from the persisted record's `fullPath`, not the client SDK's last-segment `name`); `timeCreated`/`updated` are timestamps (production rejects an int with \"Unsupported operation error. Received: int < timestamp\"); the update-time field is `updated` — there is NO `resource.timeUpdated`. An absent property is an evaluation error that absorbs to DENY and SURVIVES negation, so `resource.name != 'x'` on an object with no name denies rather than false-allowing. The prior row recorded these fields as an unsupported gap; that gap is closed.","observation:rules-storage-resource-object-identity","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.binding.resource.timeCreated","kind":"rules-construct","surface":"storage-rules","behavior":"resource.timeCreated is a timestamp (ISO-8601 in the persisted record; the evaluator compares it as epoch millis against request.time). Production rejects an int in a timestamp comparison; an absent timeCreated denies.","status":"accepted","evidence":["https://firebase.google.com/docs/reference/security/storage/resource#timeCreated"],"assurance":"eligible"}]},{"feature":"resource.updated","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"resource.updated is available, has conforms fidelity, and is eligible for assurance.","caveats":["resource.updated is the object's last-update timestamp. The field is `updated` — the Storage rules language has NO `resource.timeUpdated` (live-probed: `timeUpdated` reads as an absent property). Renamed from the earlier mis-identified `storage.binding.resource.timeUpdated`."],"claims":[{"id":"storage-rules#116","kind":"registry-row","surface":"storage-rules","behavior":"`resource.name` (full object path), `resource.timeCreated`, `resource.updated`, `resource.bucket` — the object-identity and time fields of the existing-object binding, plus `duration.value(n, unit)`","status":"conforms","evidence":["ROW CORRECTED, 2026-07-12: the fields are now modeled, sourced from the persisted object record. `oracle:rules-storage-resource-object-identity` matches production verdict-for-verdict on all 9 cases — an extension guard (`resource.name.matches`), a freshness window (`resource.timeCreated + duration.value(1, 'h')`), an immutability check (`resource.timeCreated == resource.updated`), and an absent-property negation. Production semantics pinned by the capture: `resource.name` is the object's FULL path within the bucket (GCS object-name convention, sourced from the persisted record's `fullPath`, not the client SDK's last-segment `name`); `timeCreated`/`updated` are timestamps (production rejects an int with \"Unsupported operation error. Received: int < timestamp\"); the update-time field is `updated` — there is NO `resource.timeUpdated`. An absent property is an evaluation error that absorbs to DENY and SURVIVES negation, so `resource.name != 'x'` on an object with no name denies rather than false-allowing. The prior row recorded these fields as an unsupported gap; that gap is closed.","observation:rules-storage-resource-object-identity","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.binding.resource.updated","kind":"rules-construct","surface":"storage-rules","behavior":"resource.updated is the object's last-update timestamp. The field is `updated` — the Storage rules language has NO `resource.timeUpdated` (live-probed: `timeUpdated` reads as an absent property). Renamed from the earlier mis-identified `storage.binding.resource.timeUpdated`.","status":"accepted","evidence":["https://firebase.google.com/docs/reference/security/storage/resource#updated"],"assurance":"eligible"}]},{"feature":"ResponseModality","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"ResponseModality is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:ResponseModality","kind":"runtime-export","surface":"ai","behavior":"ResponseModality is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:ResponseModality","kind":"type-export","surface":"ai","behavior":"ResponseModality is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"RetrievalConfig","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"RetrievalConfig is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:RetrievalConfig","kind":"type-export","surface":"ai","behavior":"RetrievalConfig is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"RetrievedContextAttribution","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"RetrievedContextAttribution is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:RetrievedContextAttribution","kind":"type-export","surface":"ai","behavior":"RetrievedContextAttribution is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"revokeAccessToken","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"revokeAccessToken is available, has diverged fidelity, and is qualified for assurance.","caveats":["Accepted no-op. In production this reaches OUTSIDE Firebase entirely — it tells the identity provider (in practice Apple) to revoke an OAuth access token, which is a call landing on Apple's servers. There is no external IdP behind a sandbox sign-in, so there is no token out there to revoke and nothing this call could truthfully do. It resolves (so the account-deletion flow Apple requires an app to ship runs end to end against the sandbox) and changes no sandbox state (because claiming otherwise would be a lie).","`unit:types.test.ts` — the export resolves. Deliberately not oracle-probed: a successful probe would revoke a real token at a real IdP, which is a side effect on someone else's system that a conformance run has no business causing."],"claims":[{"id":"auth:runtime:revokeAccessToken","kind":"runtime-export","surface":"auth","behavior":"revokeAccessToken is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#179","kind":"registry-row","surface":"auth","behavior":"Accepted no-op. In production this reaches OUTSIDE Firebase entirely — it tells the identity provider (in practice Apple) to revoke an OAuth access token, which is a call landing on Apple's servers. There is no external IdP behind a sandbox sign-in, so there is no token out there to revoke and nothing this call could truthfully do. It resolves (so the account-deletion flow Apple requires an app to ship runs end to end against the sandbox) and changes no sandbox state (because claiming otherwise would be a lie).","status":"diverged-documented","evidence":["`unit:types.test.ts` — the export resolves. Deliberately not oracle-probed: a successful probe would revoke a real token at a real IdP, which is a side effect on someone else's system that a conformance run has no business causing.","packages/pyric/test/auth/types.test.ts"],"assurance":"qualified"}]},{"feature":"Role","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"Role is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:Role","kind":"type-export","surface":"ai","behavior":"Role is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"root","surface":"rtdb","importPaths":[],"evidenceSlug":"database-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"root is available, has unverified fidelity, and is qualified for assurance.","caveats":["`ref(db, path)` returns a tagged `DatabaseReference` carrying `key`, `parent`, `root`, `toString()`","upstream `firebase/database` contract","`ref(db)` with no path returns the root ref (`key === null`, `parent === null`)","upstream contract","`ref.parent` is `null` at root, otherwise the parent ref","`ref.key` is the final path segment, `null` for root"],"claims":[{"id":"rtdb-modular#100","kind":"registry-row","surface":"rtdb-modular","behavior":"`ref(db, path)` returns a tagged `DatabaseReference` carrying `key`, `parent`, `root`, `toString()`","status":"unverified","evidence":["upstream `firebase/database` contract"],"assurance":"qualified"},{"id":"rtdb-modular#101","kind":"registry-row","surface":"rtdb-modular","behavior":"`ref(db)` with no path returns the root ref (`key === null`, `parent === null`)","status":"unverified","evidence":["upstream contract"],"assurance":"qualified"},{"id":"rtdb-modular#103","kind":"registry-row","surface":"rtdb-modular","behavior":"`ref.parent` is `null` at root, otherwise the parent ref","status":"unverified","evidence":["upstream contract"],"assurance":"qualified"},{"id":"rtdb-modular#104","kind":"registry-row","surface":"rtdb-modular","behavior":"`ref.key` is the final path segment, `null` for root","status":"unverified","evidence":["upstream contract"],"assurance":"qualified"},{"id":"rtdb-modular#M4","kind":"registry-row","surface":"rtdb-modular","behavior":"`ref(db, path?)` returns a path-tagged `DatabaseReference`; default is root","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"ref(db) returns a root ref\" + \"ref(db, ...) returns a path ref\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M6","kind":"registry-row","surface":"rtdb-modular","behavior":"`ref.parent` returns the parent ref; `root.parent === null`","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"ref.parent returns the parent ref; root.parent is null\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M7","kind":"registry-row","surface":"rtdb-modular","behavior":"`ref.root` returns the root ref of the same target","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"ref.root returns the root ref\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M73","kind":"registry-row","surface":"rtdb-modular","behavior":"A primitive at the ROOT is legal (`set(ref(db), 'hello')`); a subsequent child write replaces the primitive root (\"writes win\") (DB-B13)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/root-primitive.test.ts` (2 cases)","packages/pyric/test/database/modular/root-primitive.test.ts"],"assurance":"eligible"}]},{"feature":"root","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"root is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb-rules#14","kind":"registry-row","surface":"rtdb-rules","behavior":"The `root` binding — `root.child(...).exists()` resolved against the database root","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator resolves the `root` binding and reports a missing child as absent exactly as production does. The scope is bounded by the rig: the capture runner mounts the scenario subtree under a per-run randomly-named namespace while the replay suite mounts it at the root, so a rule naming any PRESENT path through `root` would address a different node on each side and diverge for harness reasons. Only a sentinel key absent under BOTH roots is mount-invariant, so that is what this row verifies; a populated `root` lookup remains unverified and needs a rig that can seed outside the scenario subtree and mount both sides at the same depth. `oracle:rules-rtdb-r14-root-lookup` matches production verdict-for-verdict on all 3 cases.","observation:rules-rtdb-r14-root-lookup","packages/pyric/test/rules/rtdb/rules-conformance.test.ts"],"assurance":"eligible"},{"id":"rtdb.binding.root","kind":"rules-construct","surface":"rtdb-rules","behavior":"root is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/rules#root"],"assurance":"qualified"}]},{"feature":"rule-kind.allow-create","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"rule-kind.allow-create is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.rule-kind.allow-create","kind":"rules-construct","surface":"firestore-rules","behavior":"rule-kind.allow-create is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-structure#granular_operations"],"assurance":"eligible"}]},{"feature":"rule-kind.allow-create","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"rule-kind.allow-create is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#96","kind":"registry-row","surface":"storage-rules","behavior":"`evaluateStorageRules` supports granular verbs (`get`/`list`/`create`/`update`/`delete`) alongside `read`/`write` umbrella expansion, comma-separated verb lists, and per-verb default-deny","status":"conforms","evidence":["STALE ROW, corrected 2026-07-10: production capture proves the evaluator already supports the full six-verb grant surface (umbrella read→{get,list}, write→{create,update,delete}, single granular grants, comma-separated grants, per-verb deny-by-default), matching production verdict-for-verdict on 12 of the scenario's 13 non-existence cases. `oracle:rules-storage-verbs-umbrella-granular` (all `read`/`write`/`get`/comma-verb cases). One related existence-semantics case in the same scenario diverges over-permissively and is carried by `#118 Rules` (the `resource == null` create-if-absent guard), not by this granular-verb row.","observation:rules-storage-verbs-umbrella-granular","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.rule-kind.allow-create","kind":"rules-construct","surface":"storage-rules","behavior":"rule-kind.allow-create is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"rule-kind.allow-delete","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"rule-kind.allow-delete is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.rule-kind.allow-delete","kind":"rules-construct","surface":"firestore-rules","behavior":"rule-kind.allow-delete is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-structure#granular_operations"],"assurance":"eligible"}]},{"feature":"rule-kind.allow-delete","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"rule-kind.allow-delete is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#96","kind":"registry-row","surface":"storage-rules","behavior":"`evaluateStorageRules` supports granular verbs (`get`/`list`/`create`/`update`/`delete`) alongside `read`/`write` umbrella expansion, comma-separated verb lists, and per-verb default-deny","status":"conforms","evidence":["STALE ROW, corrected 2026-07-10: production capture proves the evaluator already supports the full six-verb grant surface (umbrella read→{get,list}, write→{create,update,delete}, single granular grants, comma-separated grants, per-verb deny-by-default), matching production verdict-for-verdict on 12 of the scenario's 13 non-existence cases. `oracle:rules-storage-verbs-umbrella-granular` (all `read`/`write`/`get`/comma-verb cases). One related existence-semantics case in the same scenario diverges over-permissively and is carried by `#118 Rules` (the `resource == null` create-if-absent guard), not by this granular-verb row.","observation:rules-storage-verbs-umbrella-granular","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.rule-kind.allow-delete","kind":"rules-construct","surface":"storage-rules","behavior":"rule-kind.allow-delete is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"rule-kind.allow-get","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"rule-kind.allow-get is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.rule-kind.allow-get","kind":"rules-construct","surface":"firestore-rules","behavior":"rule-kind.allow-get is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-structure#granular_operations"],"assurance":"eligible"}]},{"feature":"rule-kind.allow-get","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"rule-kind.allow-get is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#96","kind":"registry-row","surface":"storage-rules","behavior":"`evaluateStorageRules` supports granular verbs (`get`/`list`/`create`/`update`/`delete`) alongside `read`/`write` umbrella expansion, comma-separated verb lists, and per-verb default-deny","status":"conforms","evidence":["STALE ROW, corrected 2026-07-10: production capture proves the evaluator already supports the full six-verb grant surface (umbrella read→{get,list}, write→{create,update,delete}, single granular grants, comma-separated grants, per-verb deny-by-default), matching production verdict-for-verdict on 12 of the scenario's 13 non-existence cases. `oracle:rules-storage-verbs-umbrella-granular` (all `read`/`write`/`get`/comma-verb cases). One related existence-semantics case in the same scenario diverges over-permissively and is carried by `#118 Rules` (the `resource == null` create-if-absent guard), not by this granular-verb row.","observation:rules-storage-verbs-umbrella-granular","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.rule-kind.allow-get","kind":"rules-construct","surface":"storage-rules","behavior":"rule-kind.allow-get is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"rule-kind.allow-list","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"rule-kind.allow-list is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.rule-kind.allow-list","kind":"rules-construct","surface":"firestore-rules","behavior":"rule-kind.allow-list is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-structure#granular_operations"],"assurance":"eligible"}]},{"feature":"rule-kind.allow-list","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"rule-kind.allow-list is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#96","kind":"registry-row","surface":"storage-rules","behavior":"`evaluateStorageRules` supports granular verbs (`get`/`list`/`create`/`update`/`delete`) alongside `read`/`write` umbrella expansion, comma-separated verb lists, and per-verb default-deny","status":"conforms","evidence":["STALE ROW, corrected 2026-07-10: production capture proves the evaluator already supports the full six-verb grant surface (umbrella read→{get,list}, write→{create,update,delete}, single granular grants, comma-separated grants, per-verb deny-by-default), matching production verdict-for-verdict on 12 of the scenario's 13 non-existence cases. `oracle:rules-storage-verbs-umbrella-granular` (all `read`/`write`/`get`/comma-verb cases). One related existence-semantics case in the same scenario diverges over-permissively and is carried by `#118 Rules` (the `resource == null` create-if-absent guard), not by this granular-verb row.","observation:rules-storage-verbs-umbrella-granular","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.rule-kind.allow-list","kind":"rules-construct","surface":"storage-rules","behavior":"rule-kind.allow-list is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"rule-kind.allow-read","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"rule-kind.allow-read is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.rule-kind.allow-read","kind":"rules-construct","surface":"firestore-rules","behavior":"rule-kind.allow-read is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-structure#basic_read_write_rules"],"assurance":"eligible"}]},{"feature":"rule-kind.allow-read","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"rule-kind.allow-read is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#96","kind":"registry-row","surface":"storage-rules","behavior":"`evaluateStorageRules` supports granular verbs (`get`/`list`/`create`/`update`/`delete`) alongside `read`/`write` umbrella expansion, comma-separated verb lists, and per-verb default-deny","status":"conforms","evidence":["STALE ROW, corrected 2026-07-10: production capture proves the evaluator already supports the full six-verb grant surface (umbrella read→{get,list}, write→{create,update,delete}, single granular grants, comma-separated grants, per-verb deny-by-default), matching production verdict-for-verdict on 12 of the scenario's 13 non-existence cases. `oracle:rules-storage-verbs-umbrella-granular` (all `read`/`write`/`get`/comma-verb cases). One related existence-semantics case in the same scenario diverges over-permissively and is carried by `#118 Rules` (the `resource == null` create-if-absent guard), not by this granular-verb row.","observation:rules-storage-verbs-umbrella-granular","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.rule-kind.allow-read","kind":"rules-construct","surface":"storage-rules","behavior":"rule-kind.allow-read is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"rule-kind.allow-update","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"rule-kind.allow-update is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.rule-kind.allow-update","kind":"rules-construct","surface":"firestore-rules","behavior":"rule-kind.allow-update is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-structure#granular_operations"],"assurance":"eligible"}]},{"feature":"rule-kind.allow-update","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"rule-kind.allow-update is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#96","kind":"registry-row","surface":"storage-rules","behavior":"`evaluateStorageRules` supports granular verbs (`get`/`list`/`create`/`update`/`delete`) alongside `read`/`write` umbrella expansion, comma-separated verb lists, and per-verb default-deny","status":"conforms","evidence":["STALE ROW, corrected 2026-07-10: production capture proves the evaluator already supports the full six-verb grant surface (umbrella read→{get,list}, write→{create,update,delete}, single granular grants, comma-separated grants, per-verb deny-by-default), matching production verdict-for-verdict on 12 of the scenario's 13 non-existence cases. `oracle:rules-storage-verbs-umbrella-granular` (all `read`/`write`/`get`/comma-verb cases). One related existence-semantics case in the same scenario diverges over-permissively and is carried by `#118 Rules` (the `resource == null` create-if-absent guard), not by this granular-verb row.","observation:rules-storage-verbs-umbrella-granular","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.rule-kind.allow-update","kind":"rules-construct","surface":"storage-rules","behavior":"rule-kind.allow-update is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"rule-kind.allow-write","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"rule-kind.allow-write is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.rule-kind.allow-write","kind":"rules-construct","surface":"firestore-rules","behavior":"rule-kind.allow-write is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-structure#basic_read_write_rules"],"assurance":"eligible"}]},{"feature":"rule-kind.allow-write","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"rule-kind.allow-write is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#96","kind":"registry-row","surface":"storage-rules","behavior":"`evaluateStorageRules` supports granular verbs (`get`/`list`/`create`/`update`/`delete`) alongside `read`/`write` umbrella expansion, comma-separated verb lists, and per-verb default-deny","status":"conforms","evidence":["STALE ROW, corrected 2026-07-10: production capture proves the evaluator already supports the full six-verb grant surface (umbrella read→{get,list}, write→{create,update,delete}, single granular grants, comma-separated grants, per-verb deny-by-default), matching production verdict-for-verdict on 12 of the scenario's 13 non-existence cases. `oracle:rules-storage-verbs-umbrella-granular` (all `read`/`write`/`get`/comma-verb cases). One related existence-semantics case in the same scenario diverges over-permissively and is carried by `#118 Rules` (the `resource == null` create-if-absent guard), not by this granular-verb row.","observation:rules-storage-verbs-umbrella-granular","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.rule-kind.allow-write","kind":"rules-construct","surface":"storage-rules","behavior":"rule-kind.allow-write is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"rule-kind.function","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"rule-kind.function is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#186","kind":"registry-row","surface":"firestore-rules","behavior":"Function declarations at GLOBAL and SERVICE scope in a Firestore ruleset, with match-scope shadowing","status":"conforms","evidence":["ROW CORRECTED, 2026-07-17 (same day): the simulator now seeds the match-tree walk with global- and service-scope function declarations (declaration order global → service → match preserves inner-shadows-outer), so the previously-abstaining cases evaluate. `oracle:rules-firestore-global-and-service-scope-functions` — production Firestore Rules Test API verdicts captured 2026-07-17 — now replays verdict-for-verdict against the local simulator with all 5 cases matching (shadowing included), asserted by `unit:rules/oracle-conformance.test.ts`. The prior unsupported row recorded the honest UNSUPPORTED abstention; that gap is closed (#346).","observation:rules-firestore-global-and-service-scope-functions","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"firestore.rule-kind.function","kind":"rules-construct","surface":"firestore-rules","behavior":"rule-kind.function is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-conditions#functions"],"assurance":"eligible"}]},{"feature":"rule-kind.function","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"rule-kind.function is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#124","kind":"registry-row","surface":"storage-rules","behavior":"Function declarations at GLOBAL scope (above `service`) and SERVICE scope (inside `service`, outside any match), with inner-shadows-outer resolution","status":"conforms","evidence":["NEW ROW, 2026-07-17: production capture proves production accepts functions declared at global and service scope and resolves a match-scope function over a same-named global (inner shadows outer). `oracle:rules-storage-function-scopes-and-shadowing` matches production verdict-for-verdict on all 5 cases. The shared grammar previously rejected both placements at parse (PR #333 grammar fix); the storage evaluator attaches global- and service-scope functions to the root match block, which the capture proves is verdict-equivalent to production's scoping for this surface.","observation:rules-storage-function-scopes-and-shadowing","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.rule-kind.function","kind":"rules-construct","surface":"storage-rules","behavior":"rule-kind.function is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"rule-kind.import","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"rule-kind.import is available, has unverified fidelity, and is qualified for assurance.","caveats":["Discrepancy: `import { fn } from 'module'` under `rules_version = '2+modules'` is a pyric resolver extension (rules/modules/resolver.ts), not stock Firebase rules — production Firestore only knows rules_version '1'/'2' and has no import statement."],"claims":[{"id":"firestore.rule-kind.import","kind":"rules-construct","surface":"firestore-rules","behavior":"Discrepancy: `import { fn } from 'module'` under `rules_version = '2+modules'` is a pyric resolver extension (rules/modules/resolver.ts), not stock Firebase rules — production Firestore only knows rules_version '1'/'2' and has no import statement.","status":"unprobeable","evidence":["https://firebase.google.com/docs/firestore/security/rules-structure#rules_version","the `import`/2+modules form requires module resolution (resolveModules) before simulation; the SimulateFirestoreRulesHandler evaluates already-resolved source only."],"assurance":"qualified"}]},{"feature":"rule-kind.indexOn","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"rule-kind.indexOn is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.rule-kind.indexOn","kind":"rules-construct","surface":"rtdb-rules","behavior":"rule-kind.indexOn is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/database/security/indexing-data"],"assurance":"qualified"}]},{"feature":"rule-kind.let","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"rule-kind.let is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.rule-kind.let","kind":"rules-construct","surface":"firestore-rules","behavior":"rule-kind.let is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-conditions#functions"],"assurance":"eligible"}]},{"feature":"rule-kind.let","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"rule-kind.let is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage.rule-kind.let","kind":"rules-construct","surface":"storage-rules","behavior":"rule-kind.let is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"rule-kind.location-wildcard","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"rule-kind.location-wildcard is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.rule-kind.location-wildcard","kind":"rules-construct","surface":"rtdb-rules","behavior":"rule-kind.location-wildcard is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/database/security/core-syntax#variables"],"assurance":"qualified"}]},{"feature":"rule-kind.match","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"rule-kind.match is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.rule-kind.match","kind":"rules-construct","surface":"firestore-rules","behavior":"rule-kind.match is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-structure#match_paths"],"assurance":"eligible"}]},{"feature":"rule-kind.match","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"rule-kind.match is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage.rule-kind.match","kind":"rules-construct","surface":"storage-rules","behavior":"rule-kind.match is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"rule-kind.read","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"rule-kind.read is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.rule-kind.read","kind":"rules-construct","surface":"rtdb-rules","behavior":"rule-kind.read is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/rules#.read"],"assurance":"qualified"}]},{"feature":"rule-kind.rules_version","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"rule-kind.rules_version is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#185","kind":"registry-row","surface":"firestore-rules","behavior":"A ruleset with NO `rules_version` declaration — production accepts it and defaults to v1","status":"conforms","evidence":["NEW ROW, 2026-07-17: production capture proves a version-less ruleset deploys and evaluates (production defaults `rules_version` to v1; the shared grammar previously rejected the file at parse — PR #333 grammar fix, the same evidence that reclassified corpus file 001-missing-version.rules from invalid to edge-cases). `oracle:rules-firestore-optional-rules-version` matches the local simulator verdict-for-verdict on all 3 cases.","observation:rules-firestore-optional-rules-version","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"firestore.rule-kind.rules_version","kind":"rules-construct","surface":"firestore-rules","behavior":"rule-kind.rules_version is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-structure#rules_version"],"assurance":"eligible"}]},{"feature":"rule-kind.rules_version","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"rule-kind.rules_version is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage.rule-kind.rules_version","kind":"rules-construct","surface":"storage-rules","behavior":"rule-kind.rules_version is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"rule-kind.validate","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"rule-kind.validate is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.rule-kind.validate","kind":"rules-construct","surface":"rtdb-rules","behavior":"rule-kind.validate is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/rules#.validate"],"assurance":"qualified"}]},{"feature":"rule-kind.write","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"rule-kind.write is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.rule-kind.write","kind":"rules-construct","surface":"rtdb-rules","behavior":"rule-kind.write is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/rules#.write"],"assurance":"qualified"}]},{"feature":"ruleset","surface":"rtdb","importPaths":["pyric/rules/internal/rtdb"],"evidenceSlug":"database-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"ruleset is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"rtdb#87","kind":"registry-row","surface":"rtdb","behavior":"`ruleset(...)` builds an environment-independent compiled RTDB rules tree from path definitions + expression objects","status":"conforms","evidence":["`unit:constraints/ruleset.test.ts`","packages/pyric/test/rules/rtdb/constraints/ruleset.test.ts"],"assurance":"eligible"}]},{"feature":"runTransaction","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"runTransaction is available, has diverged fidelity, and is qualified for assurance.","caveats":["Retry behavior — prod retries on contention up to 5 times; sandbox is single-threaded, no contention possible","divergence: contention story not modeled; sandbox just runs once"],"claims":[{"id":"firestore:runtime:runTransaction","kind":"runtime-export","surface":"firestore","behavior":"runTransaction is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#91","kind":"registry-row","surface":"firestore","behavior":"Atomic read-write — all reads in `fn` see a consistent snapshot, writes commit together","status":"conforms","evidence":["`unit:sandbox-target.test.ts`, `playground:firestore-transaction`; get-missing/deleted + empty txn + nested update: `unit:upstream-transform-txn-listener-probes.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts","packages/pyric/test/firestore/upstream-transform-txn-listener-probes.test.ts"],"assurance":"eligible"},{"id":"firestore#92","kind":"registry-row","surface":"firestore","behavior":"Identity is frozen at `runTransaction` start — mid-transaction `setUser` does NOT re-auth in-flight reads","status":"conforms","evidence":["(documented invariant)"],"assurance":"eligible"},{"id":"firestore#93","kind":"registry-row","surface":"firestore","behavior":"Retry behavior — prod retries on contention up to 5 times; sandbox is single-threaded, no contention possible","status":"diverged-documented","evidence":["divergence: contention story not modeled; sandbox just runs once"],"assurance":"qualified"},{"id":"firestore#94","kind":"registry-row","surface":"firestore","behavior":"Throws `FirebaseError('permission-denied')` on rule denial inside the transaction (the inner write's denial — not a generic `aborted`). Sandbox throws `FirestoreCompatError` with the same `code: 'permission-denied'`","status":"conforms","evidence":["`unit:sandbox-target.test.ts` (writes-reject branch), oracle: `packages/conformance/observations/firestore/firestore-transaction-rules-denied-error.json` (prod throws `FirebaseError` with `code: 'permission-denied'`, NOT `aborted`; the inner callback ran once and the rules-rejected write surfaces as a regular permission-denied at commit)","observation:firestore-transaction-rules-denied-error","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"runTransaction","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"runTransaction is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["Concurrent contention / retry-on-conflict — single-client sandbox doesn't model real concurrency; the documented \"up to 25 retries\" contract is degenerate (the fn is invoked once)","matrix #161 documents the same gap on the spec side; oracle observation hard to obtain from a single client (oracle row stays `?`)","Concurrent contention — if another client writes between the read and write, the update fn is retried with the new current value (typically up to 25 retries by default)","hard to observe deterministically from a single client"],"claims":[{"id":"database:runtime:runTransaction","kind":"runtime-export","surface":"database","behavior":"runTransaction is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#158","kind":"registry-row","surface":"rtdb-modular","behavior":"Basic success — `runTransaction(ref, current => (current ?? 0) + 1)` resolves `{ committed: true, snapshot }` where `snapshot.val()` is the new value","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-runtransaction-success.json` — observed `committed: true, snapVal: 1` after running `current => (current ?? 0) + 1` against an empty ref.","observation:rtdb-modular-runtransaction-on-rules-denied-path","observation:rtdb-modular-runtransaction-options-applylocally","observation:rtdb-modular-runtransaction-success"],"assurance":"eligible"},{"id":"rtdb-modular#159","kind":"registry-row","surface":"rtdb-modular","behavior":"Returning `undefined` from the update fn **aborts** the transaction — resolves `{ committed: false }`, no write performed (RTDB-specific; distinct from Firestore where the only abort path is throwing)","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-runtransaction-abort-undefined.json` — seeded `100` then transaction returned `undefined`; observed `committed: false, snapVal: null, afterValOnServer: 100` (existing value preserved).","observation:rtdb-modular-runtransaction-abort-undefined"],"assurance":"eligible"},{"id":"rtdb-modular#160","kind":"registry-row","surface":"rtdb-modular","behavior":"The update fn is called with the CURRENT server value (may be `null` if the ref is empty); the fn's return value is the proposed new value","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-runtransaction-success.json` — observed `seenCurrentValues: [null]` on first invocation against an empty ref (a single call, no speculative re-runs against `undefined`). NOTE — adjacent divergence pinned in `modular/oracle-conformance.test.ts`: for a SEEDED path, prod speculatively invokes the update fn twice (first with `null`, then the real value; `rtdb-modular-runtransaction-current-value-arg.json` `seededArgs.length: 2`) while the sandbox invokes once with the actual value. The argument-semantics claim of this row holds for the effective invocation on both sides. WARNING for update-fn authors: prod may invoke your fn first with `null` even when data exists — the pattern `if (current === null) return;` (abort-on-empty) silently loses writes on prod while working on the sandbox, and side effects inside the fn can run twice on prod. RESOLVED by the warm-client capture `rtdb-modular-runtransaction-warm-client-speculation`: a warm prod client (active listener + prior get) receives a SINGLE invocation with the cached value, exactly matching the sandbox. The cold-cache speculative double-call is an artifact of an empty client cache, which the always-warm in-process sandbox structurally never has; the sandbox behavior IS the warm-client contract.","observation:rtdb-modular-runtransaction-current-value-arg","observation:rtdb-modular-runtransaction-options-applylocally","observation:rtdb-modular-runtransaction-success"],"assurance":"eligible"},{"id":"rtdb-modular#161","kind":"registry-row","surface":"rtdb-modular","behavior":"Concurrent contention — if another client writes between the read and write, the update fn is retried with the new current value (typically up to 25 retries by default)","status":"unverified","evidence":["hard to observe deterministically from a single client"],"assurance":"qualified"},{"id":"rtdb-modular#162","kind":"registry-row","surface":"rtdb-modular","behavior":"Result snapshot's `.val()` reflects the committed value (or the existing value if aborted)","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-runtransaction-success.json` — observed `snapVal: 1` matching the committed value.","observation:rtdb-modular-runtransaction-returns-committed-snapshot","observation:rtdb-modular-runtransaction-success"],"assurance":"eligible"},{"id":"rtdb-modular#M37","kind":"registry-row","surface":"rtdb-modular","behavior":"`runTransaction(ref, fn, options?)` resolves to `{ committed: boolean, snapshot: DataSnapshot }` for the happy path — the update fn return value is written, committed is `true`, and `snapshot.val()` reflects the committed value","status":"conforms","evidence":["Sandbox aligned: `unit:modular/transaction.test.ts` (\"resolves to { committed: boolean, snapshot } with the committed value\"); matches oracle observations `packages/conformance/observations/rtdb-modular/rtdb-modular-runtransaction-success.json` + `rtdb-modular-runtransaction-returns-committed-snapshot.json` (against blockingfun, fb-js-sdk 12.13.0)","observation:rtdb-modular-runtransaction-success","observation:rtdb-modular-runtransaction-warm-client-speculation","packages/pyric/test/database/modular/transaction.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M37f","kind":"registry-row","surface":"rtdb-modular","behavior":"Rules-denied transaction does NOT write — pre-transaction value at the path is preserved through the rejection","status":"conforms","evidence":["`unit:modular/transaction.test.ts` (\"does not write to the path when rules deny\") — locked alongside the M37e shape claim","packages/pyric/test/database/modular/transaction.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M37h","kind":"registry-row","surface":"rtdb-modular","behavior":"Concurrent contention / retry-on-conflict — single-client sandbox doesn't model real concurrency; the documented \"up to 25 retries\" contract is degenerate (the fn is invoked once)","status":"unsupported","evidence":["matrix #161 documents the same gap on the spec side; oracle observation hard to obtain from a single client (oracle row stays `?`)"],"assurance":"ineligible"},{"id":"rtdb-modular#M68","kind":"registry-row","surface":"rtdb-modular","behavior":"Write validation: an `undefined` payload, a non-finite number (`NaN`/`±Infinity`), or a key containing a forbidden char (`.`, `#`, `$`, `/`, `[`, `]`, control chars) is rejected with a plain `Error` (DB-B1)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/normalization.test.ts` (\"rejects an undefined payload\" + \"rejects an invalid key\" + \"rejects a non-finite number\"); upstream `core/util/validation.ts:45,58,112-199`","packages/pyric/test/database/modular/normalization.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M76","kind":"registry-row","surface":"rtdb-modular","behavior":"`.validate` rules are enforced on modular sandbox writes through `set`, atomic `update`, and `runTransaction`; a descendant validation failure rejects the operation without changing state.","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` executes all three write paths against a required-child `.validate` rule and proves each rejects without committing state. The shared `SimulateHandler` behavior is production-locked by RTDB rules corpus rows #4 and #15.","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"SafetyRating","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"SafetyRating is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:SafetyRating","kind":"type-export","surface":"ai","behavior":"SafetyRating is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"SafetySetting","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"SafetySetting is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:SafetySetting","kind":"type-export","surface":"ai","behavior":"SafetySetting is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"SAMLAuthProvider","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"SAMLAuthProvider is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:SAMLAuthProvider","kind":"runtime-export","surface":"auth","behavior":"SAMLAuthProvider is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth:type:SAMLAuthProvider","kind":"type-export","surface":"auth","behavior":"SAMLAuthProvider is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#181","kind":"registry-row","surface":"auth","behavior":"Provider marker classes. `TwitterAuthProvider.credential(token, secret)` takes a token AND a secret — Twitter is the one OAuth 1.0a provider in the set, where the OAuth 2.0 providers take a single access token. `SAMLAuthProvider`'s constructor ENFORCES the `saml.` providerId prefix (throwing `auth/argument-error` otherwise), because that id is what routes an assertion to the right configured IdP and a typo there would silently target nothing. SAML has no client-constructible credential, so the class has no `credential()` factory.","status":"conforms","evidence":["`unit:types.test.ts` — construction, PROVIDER_ID values, and the SAML prefix guard.","packages/pyric/test/auth/types.test.ts"],"assurance":"eligible"}]},{"feature":"Schema","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"Schema is available, has diverged fidelity, and is qualified for assurance.","caveats":["`Schema.enumString` serializes the enum values with type `string` and format `enum`","`unit:helpers-schema.test.ts` test `ai#schema-string-enum` (upstream toJSON request shape; GoogleAI accepts only enum and date-time formats)"],"claims":[{"id":"ai:runtime:Schema","kind":"runtime-export","surface":"ai","behavior":"Schema is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:Schema","kind":"type-export","surface":"ai","behavior":"Schema is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai#schema-anyof","kind":"registry-row","surface":"ai","behavior":"`Schema.anyOf` returns an `AnyOfSchema` whose JSON carries an `anyOf` array of sub-schemas and no top-level type","status":"conforms","evidence":["`unit:upstream-ai-probes.test.ts` (I2 empty anyOf → invalid-schema) + `unit:helpers-schema.test.ts` test `ai#schema-anyof`","packages/pyric/test/ai/upstream-ai-probes.test.ts","packages/pyric/test/ai/helpers-schema.test.ts"],"assurance":"eligible"},{"id":"ai#schema-object-tojson","kind":"registry-row","surface":"ai","behavior":"`Schema.object` serializes to type `object` with `properties`, and `required` is derived by excluding `optionalProperties`","status":"conforms","evidence":["`unit:upstream-ai-probes.test.ts` (I2 empty optionalProperties + propertyOrdering) + `unit:helpers-schema.test.ts` test `ai#schema-object-tojson`","packages/pyric/test/ai/upstream-ai-probes.test.ts","packages/pyric/test/ai/helpers-schema.test.ts"],"assurance":"eligible"},{"id":"ai#schema-primitives","kind":"registry-row","surface":"ai","behavior":"Each primitive builder serializes its `SchemaType`, and `array` carries `items`","status":"conforms","evidence":["`unit:helpers-schema.test.ts` test `ai#schema-primitives` (upstream toJSON request shape)","packages/pyric/test/ai/helpers-schema.test.ts"],"assurance":"eligible"},{"id":"ai#schema-rides-request","kind":"registry-row","surface":"ai","behavior":"A built `Schema` serializes into `generationConfig.responseSchema` on the request and drives JSON output","status":"conforms","evidence":["Capture ai-structured-output-shape replayed by packages/pyric/test/ai/helpers-schema.test.ts test `ai#schema-rides-request`","observation:ai-structured-output-shape","packages/pyric/test/ai/helpers-schema.test.ts"],"assurance":"eligible"},{"id":"ai#schema-string-enum","kind":"registry-row","surface":"ai","behavior":"`Schema.enumString` serializes the enum values with type `string` and format `enum`","status":"diverged-documented","evidence":["`unit:helpers-schema.test.ts` test `ai#schema-string-enum` (upstream toJSON request shape; GoogleAI accepts only enum and date-time formats)","packages/pyric/test/ai/helpers-schema.test.ts"],"assurance":"qualified"}]},{"feature":"SchemaInterface","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"SchemaInterface is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:SchemaInterface","kind":"type-export","surface":"ai","behavior":"SchemaInterface is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"SchemaParams","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"SchemaParams is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:SchemaParams","kind":"type-export","surface":"ai","behavior":"SchemaParams is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"SchemaRequest","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"SchemaRequest is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:SchemaRequest","kind":"type-export","surface":"ai","behavior":"SchemaRequest is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"SchemaShared","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"SchemaShared is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:SchemaShared","kind":"type-export","surface":"ai","behavior":"SchemaShared is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"SchemaType","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"SchemaType is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:SchemaType","kind":"runtime-export","surface":"ai","behavior":"SchemaType is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:SchemaType","kind":"type-export","surface":"ai","behavior":"SchemaType is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"script","surface":"ai","importPaths":[],"evidenceSlug":"ai-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"script is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"ai#scripted-deterministic","kind":"registry-row","surface":"ai","behavior":"The same unscripted request twice yields an identical envelope, candidates and usage included","status":"conforms","evidence":["`unit:engines.test.ts` test `ai#scripted-deterministic` (determinism claim from the scripted authoring deltas)","packages/pyric/test/ai/engines.test.ts"],"assurance":"eligible"},{"id":"ai#scripted-matchers","kind":"registry-row","surface":"ai","behavior":"Entries match by substring, regex, or predicate on the request; a matching entry wins over the plain queue","status":"conforms","evidence":["`unit:engines.test.ts` test `ai#scripted-matchers` (ruling 2 of the scripted authoring deltas)","packages/pyric/test/ai/engines.test.ts"],"assurance":"eligible"},{"id":"ai#scripted-queue-order","kind":"registry-row","surface":"ai","behavior":"Script entries without matchers are consumed in FIFO queue order","status":"conforms","evidence":["`unit:engines.test.ts` test `ai#scripted-queue-order` (ruling 2 of the scripted authoring deltas)","packages/pyric/test/ai/engines.test.ts"],"assurance":"eligible"},{"id":"ai#scripted-raw-envelope","kind":"registry-row","surface":"ai","behavior":"A raw Gemini envelope entry is returned verbatim, so an observation `behavior.raw` pastes in directly and captures are the corpus","status":"conforms","evidence":["`unit:engines.test.ts` test `ai#scripted-raw-envelope` (ruling 3 of the scripted authoring deltas)","packages/pyric/test/ai/engines.test.ts"],"assurance":"eligible"},{"id":"ai#scripted-shorthand-functioncall","kind":"registry-row","surface":"ai","behavior":"A `functionCall` shorthand expands to a model turn whose functionCall part carries a minted `thoughtSignature`","status":"conforms","evidence":["`unit:engines.test.ts` test `ai#scripted-shorthand-functioncall` (capture ai-error-fncall-missing-thought-signature cited as the motivating rejection)","observation:ai-error-fncall-missing-thought-signature","packages/pyric/test/ai/engines.test.ts"],"assurance":"eligible"},{"id":"ai#scripted-shorthand-text","kind":"registry-row","surface":"ai","behavior":"A `text` shorthand expands to a wire-true envelope: finishReason STOP, usageMetadata with serviceTier, modelVersion, responseId","status":"conforms","evidence":["`unit:engines.test.ts` test `ai#scripted-shorthand-text` (capture ai-generate-minimal-envelope cited as the expansion target)","observation:ai-generate-minimal-envelope","packages/pyric/test/ai/engines.test.ts"],"assurance":"eligible"},{"id":"ai#scripted-stream-chunks","kind":"registry-row","surface":"ai","behavior":"A chunk-array shorthand declares chunk boundaries and the engine applies the captured framing, so authors never hand-write SSE","status":"conforms","evidence":["`unit:engines.test.ts` test `ai#scripted-stream-chunks` (capture ai-generate-stream-framing cited as the framing source)","observation:ai-generate-stream-framing","packages/pyric/test/ai/engines.test.ts"],"assurance":"eligible"},{"id":"ai#scripted-text-assertable","kind":"registry-row","surface":"ai","behavior":"Scripted text is the one place generated text values may be asserted: `response.text()` returns the scripted string exactly","status":"conforms","evidence":["`unit:engines.test.ts` test `ai#scripted-text-assertable` (evidence tier ruling 1: generated text is never compared anywhere else)","packages/pyric/test/ai/engines.test.ts"],"assurance":"eligible"},{"id":"ai#scripted-zero-config","kind":"registry-row","surface":"ai","behavior":"With no script the engine returns a deterministic synthesized response derived from the request, wire-true in shape: the captured envelope key sets hold","status":"conforms","evidence":["`unit:engines.test.ts` test `ai#scripted-zero-config` (capture ai-generate-minimal-envelope cited as the shape source)","observation:ai-generate-minimal-envelope","packages/pyric/test/ai/engines.test.ts"],"assurance":"eligible"}]},{"feature":"SDK_VERSION","surface":"app","importPaths":["pyric/app"],"evidenceSlug":"app-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"SDK_VERSION is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"app:runtime:SDK_VERSION","kind":"runtime-export","surface":"app","behavior":"SDK_VERSION is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"app#11","kind":"registry-row","surface":"app","behavior":"`SDK_VERSION` is the Firebase client SDK semver string whose behavior pyric currently mirrors, pinned to the oracle version (`12.13.0`)","status":"conforms","evidence":["oracle: `app-registry-sdk-version` (firebase 12.13.0) + replay: `oracle-conformance.test.ts`","observation:app-registry-sdk-version","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"SearchEntrypoint","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"SearchEntrypoint is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:SearchEntrypoint","kind":"type-export","surface":"ai","behavior":"SearchEntrypoint is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"Segment","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"Segment is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:Segment","kind":"type-export","surface":"ai","behavior":"Segment is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"semantic.deny-by-default","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"semantic.deny-by-default is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.semantic.deny-by-default","kind":"rules-construct","surface":"rtdb-rules","behavior":"semantic.deny-by-default is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/database/security/core-syntax"],"assurance":"qualified"}]},{"feature":"semantic.deny-by-default","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"semantic.deny-by-default is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#96","kind":"registry-row","surface":"storage-rules","behavior":"`evaluateStorageRules` supports granular verbs (`get`/`list`/`create`/`update`/`delete`) alongside `read`/`write` umbrella expansion, comma-separated verb lists, and per-verb default-deny","status":"conforms","evidence":["STALE ROW, corrected 2026-07-10: production capture proves the evaluator already supports the full six-verb grant surface (umbrella read→{get,list}, write→{create,update,delete}, single granular grants, comma-separated grants, per-verb deny-by-default), matching production verdict-for-verdict on 12 of the scenario's 13 non-existence cases. `oracle:rules-storage-verbs-umbrella-granular` (all `read`/`write`/`get`/comma-verb cases). One related existence-semantics case in the same scenario diverges over-permissively and is carried by `#118 Rules` (the `resource == null` create-if-absent guard), not by this granular-verb row.","observation:rules-storage-verbs-umbrella-granular","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.semantic.deny-by-default","kind":"rules-construct","surface":"storage-rules","behavior":"semantic.deny-by-default is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"semantic.error-absorption-and","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"semantic.error-absorption-and is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#163","kind":"registry-row","surface":"firestore-rules","behavior":"CEL tri-state error absorption in `||`/`&&` (RULES-B3) — `error || true` → ALLOW, `error && false` → DENY, commutative absorption (not JS left-to-right short-circuit)","status":"conforms","evidence":["`oracle:rules-firestore-error-absorption-and-or` — production Firestore Rules Test API verdicts for corpus scenario \"error-absorption-and-or\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`; all cases match production.","observation:rules-firestore-error-absorption-and-or","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"firestore.semantic.error-absorption-and","kind":"rules-construct","surface":"firestore-rules","behavior":"semantic.error-absorption-and is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"semantic.error-absorption-or","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"semantic.error-absorption-or is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#163","kind":"registry-row","surface":"firestore-rules","behavior":"CEL tri-state error absorption in `||`/`&&` (RULES-B3) — `error || true` → ALLOW, `error && false` → DENY, commutative absorption (not JS left-to-right short-circuit)","status":"conforms","evidence":["`oracle:rules-firestore-error-absorption-and-or` — production Firestore Rules Test API verdicts for corpus scenario \"error-absorption-and-or\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`; all cases match production.","observation:rules-firestore-error-absorption-and-or","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"firestore.semantic.error-absorption-or","kind":"rules-construct","surface":"firestore-rules","behavior":"semantic.error-absorption-or is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"semantic.get-budget","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"semantic.get-budget is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"firestore.semantic.get-budget","kind":"rules-construct","surface":"firestore-rules","behavior":"semantic.get-budget is enumerated in the firestore rules-language inventory","status":"unprobeable","evidence":["https://firebase.google.com/docs/firestore/security/rules-conditions#access_other_documents","the get() budget (cap 10 per evaluation) is a resource-limit semantic, not expressible as a single-expression micro-scenario."],"assurance":"qualified"}]},{"feature":"semantic.hierarchical-match-cascade","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"semantic.hierarchical-match-cascade is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.semantic.hierarchical-match-cascade","kind":"rules-construct","surface":"firestore-rules","behavior":"semantic.hierarchical-match-cascade is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-structure#hierarchical_data"],"assurance":"eligible"}]},{"feature":"semantic.read-cascade","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"semantic.read-cascade is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb-rules#10","kind":"registry-row","surface":"rtdb-rules","behavior":"Snapshot structure and type guards — `hasChild`, `parent()`, `isString`, `isNumber`, `isBoolean`","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator resolves the type predicates and the `parent()` path climb as production does, including RTDB's rule that a child `.validate` runs only for children PRESENT in `newData` — the name-without-age write is denied by that field's own parent guard, not by the absent sibling's type rule, which never runs. `oracle:rules-rtdb-r10-snapshot-type-guards` matches production verdict-for-verdict on all 7 cases.","observation:rules-rtdb-r10-snapshot-type-guards","packages/pyric/test/rules/rtdb/rules-conformance.test.ts"],"assurance":"eligible"},{"id":"rtdb-rules#3","kind":"registry-row","surface":"rtdb-rules","behavior":"Write-rule CASCADE — a truthy ancestor `.write` grants the write regardless of a deeper `!data.exists()` rule, so the populated-path write ALLOWS","status":"conforms","evidence":["`oracle:rules-rtdb-r3-data-exists` — production verdicts captured by deploy-observe-restore, replayed verdict-for-verdict. Production ALLOWS the write to the populated path even though the child rule is `!data.exists()`: the ancestor `.write: auth != null` already granted it, and RTDB never consults a deeper rule to revoke a grant. All 3 cases match; the simulator models the same cascade.","observation:rules-rtdb-r3-data-exists","packages/pyric/test/rules/rtdb/rules-conformance.test.ts"],"assurance":"eligible"},{"id":"rtdb-rules#5","kind":"registry-row","surface":"rtdb-rules","behavior":"Cascade is GRANT-ONLY — a root `.read: true` grants every descendant read (authed and anonymous), and a deeper `.write: false` cannot revoke a truthy ancestor `.write` grant","status":"conforms","evidence":["`oracle:rules-rtdb-r5-cascade-root-grant` — production verdicts captured by deploy-observe-restore, replayed verdict-for-verdict; all 4 cases ALLOW in production, including the write to a node whose own `.write` is literal `false`. The simulator reproduces grant-only cascade rather than treating the deeper `false` as a veto.","observation:rules-rtdb-r5-cascade-root-grant","packages/pyric/test/rules/rtdb/rules-conformance.test.ts"],"assurance":"eligible"},{"id":"rtdb-rules#8","kind":"registry-row","surface":"rtdb-rules","behavior":"`newData` is projected at the RULE node, not the written path — a root `.write` reading `newData.hasChildren(['owner'])` sees `{item:{...}}` for a write one level deeper, so the predicate is false and the write DENIES","status":"conforms","evidence":["`oracle:rules-rtdb-r8-combined-check` — production verdicts captured by deploy-observe-restore, replayed verdict-for-verdict. Production DENIES all three writes, including the \"matching owner\" case whose `owner` field lives under `/item` rather than at the rule node; only the auth-gated read allows. All 4 cases match, so the simulator projects `newData` at the same node production does — rule placement relative to the written path decides the outcome.","observation:rules-rtdb-r8-combined-check","packages/pyric/test/rules/rtdb/rules-conformance.test.ts"],"assurance":"eligible"},{"id":"rtdb.semantic.read-cascade","kind":"rules-construct","surface":"rtdb-rules","behavior":"semantic.read-cascade is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/database/security/core-syntax#read-and-write-rules-cascade"],"assurance":"qualified"}]},{"feature":"semantic.read-umbrella","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"semantic.read-umbrella is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#96","kind":"registry-row","surface":"storage-rules","behavior":"`evaluateStorageRules` supports granular verbs (`get`/`list`/`create`/`update`/`delete`) alongside `read`/`write` umbrella expansion, comma-separated verb lists, and per-verb default-deny","status":"conforms","evidence":["STALE ROW, corrected 2026-07-10: production capture proves the evaluator already supports the full six-verb grant surface (umbrella read→{get,list}, write→{create,update,delete}, single granular grants, comma-separated grants, per-verb deny-by-default), matching production verdict-for-verdict on 12 of the scenario's 13 non-existence cases. `oracle:rules-storage-verbs-umbrella-granular` (all `read`/`write`/`get`/comma-verb cases). One related existence-semantics case in the same scenario diverges over-permissively and is carried by `#118 Rules` (the `resource == null` create-if-absent guard), not by this granular-verb row.","observation:rules-storage-verbs-umbrella-granular","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.semantic.read-umbrella","kind":"rules-construct","surface":"storage-rules","behavior":"semantic.read-umbrella is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"semantic.recursive-wildcard","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"semantic.recursive-wildcard is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.semantic.recursive-wildcard","kind":"rules-construct","surface":"firestore-rules","behavior":"semantic.recursive-wildcard is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/firestore/security/rules-structure#recursive_wildcards"],"assurance":"eligible"}]},{"feature":"semantic.recursive-wildcard","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"semantic.recursive-wildcard is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage.semantic.recursive-wildcard","kind":"rules-construct","surface":"storage-rules","behavior":"semantic.recursive-wildcard is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"semantic.regex-literal","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"semantic.regex-literal is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.semantic.regex-literal","kind":"rules-construct","surface":"rtdb-rules","behavior":"semantic.regex-literal is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/string#matches"],"assurance":"qualified"}]},{"feature":"semantic.type-dispatch","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"semantic.type-dispatch is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"firestore.semantic.type-dispatch","kind":"rules-construct","surface":"firestore-rules","behavior":"semantic.type-dispatch is enumerated in the firestore rules-language inventory","status":"unprobeable","evidence":["https://firebase.google.com/docs/reference/rules/rules","type-based method dispatch is a meta-semantic exercised by every method call; it has no standalone micro-scenario of its own."],"assurance":"qualified"}]},{"feature":"semantic.validate-non-cascade","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"semantic.validate-non-cascade is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb-rules#10","kind":"registry-row","surface":"rtdb-rules","behavior":"Snapshot structure and type guards — `hasChild`, `parent()`, `isString`, `isNumber`, `isBoolean`","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator resolves the type predicates and the `parent()` path climb as production does, including RTDB's rule that a child `.validate` runs only for children PRESENT in `newData` — the name-without-age write is denied by that field's own parent guard, not by the absent sibling's type rule, which never runs. `oracle:rules-rtdb-r10-snapshot-type-guards` matches production verdict-for-verdict on all 7 cases.","observation:rules-rtdb-r10-snapshot-type-guards","packages/pyric/test/rules/rtdb/rules-conformance.test.ts"],"assurance":"eligible"},{"id":"rtdb-rules#15","kind":"registry-row","surface":"rtdb-rules","behavior":"`.validate` reaches ancestors of the written path — each applicable rule is evaluated against the merged post-write value at its own location","status":"conforms","evidence":["`oracle:rules-rtdb-r15-validate-ancestor-scope` — production DENIES a deep write that leaves its validated ancestor without the required child, while the same write under a rule-free ancestor ALLOWS and the write ALLOWS once the ancestor requirement is seeded. The simulator now walks validation from the root through the write location against the merged post-write tree and matches all 5 captured production cases.","observation:rules-rtdb-r15-validate-ancestor-scope","packages/pyric/test/rules/rtdb/rules-conformance.test.ts"],"assurance":"eligible"},{"id":"rtdb-rules#4","kind":"registry-row","surface":"rtdb-rules","behavior":"`.validate` VETO — a failing child `.validate` denies a write the `.write` rule would otherwise permit (validate does not cascade and cannot be overridden)","status":"conforms","evidence":["`oracle:rules-rtdb-r4-validate-structure` — production verdicts captured by deploy-observe-restore, replayed verdict-for-verdict; both cases match production. This row was the corpus's one historical simulator-vs-production divergence: at the 2026-05-18 agreement capture the simulator ALLOWED the missing-body write because it did not veto on the child `.validate`. The simulator now denies it, and this fresh capture re-confirms production's DENY, so the divergence is RESOLVED and needs no pin.","observation:rules-rtdb-r4-validate-structure","packages/pyric/test/rules/rtdb/rules-conformance.test.ts"],"assurance":"eligible"},{"id":"rtdb.semantic.validate-non-cascade","kind":"rules-construct","surface":"rtdb-rules","behavior":"semantic.validate-non-cascade is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/database/security/core-syntax#validation-rules"],"assurance":"qualified"}]},{"feature":"semantic.write-cascade","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"semantic.write-cascade is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb-rules#3","kind":"registry-row","surface":"rtdb-rules","behavior":"Write-rule CASCADE — a truthy ancestor `.write` grants the write regardless of a deeper `!data.exists()` rule, so the populated-path write ALLOWS","status":"conforms","evidence":["`oracle:rules-rtdb-r3-data-exists` — production verdicts captured by deploy-observe-restore, replayed verdict-for-verdict. Production ALLOWS the write to the populated path even though the child rule is `!data.exists()`: the ancestor `.write: auth != null` already granted it, and RTDB never consults a deeper rule to revoke a grant. All 3 cases match; the simulator models the same cascade.","observation:rules-rtdb-r3-data-exists","packages/pyric/test/rules/rtdb/rules-conformance.test.ts"],"assurance":"eligible"},{"id":"rtdb-rules#4","kind":"registry-row","surface":"rtdb-rules","behavior":"`.validate` VETO — a failing child `.validate` denies a write the `.write` rule would otherwise permit (validate does not cascade and cannot be overridden)","status":"conforms","evidence":["`oracle:rules-rtdb-r4-validate-structure` — production verdicts captured by deploy-observe-restore, replayed verdict-for-verdict; both cases match production. This row was the corpus's one historical simulator-vs-production divergence: at the 2026-05-18 agreement capture the simulator ALLOWED the missing-body write because it did not veto on the child `.validate`. The simulator now denies it, and this fresh capture re-confirms production's DENY, so the divergence is RESOLVED and needs no pin.","observation:rules-rtdb-r4-validate-structure","packages/pyric/test/rules/rtdb/rules-conformance.test.ts"],"assurance":"eligible"},{"id":"rtdb-rules#5","kind":"registry-row","surface":"rtdb-rules","behavior":"Cascade is GRANT-ONLY — a root `.read: true` grants every descendant read (authed and anonymous), and a deeper `.write: false` cannot revoke a truthy ancestor `.write` grant","status":"conforms","evidence":["`oracle:rules-rtdb-r5-cascade-root-grant` — production verdicts captured by deploy-observe-restore, replayed verdict-for-verdict; all 4 cases ALLOW in production, including the write to a node whose own `.write` is literal `false`. The simulator reproduces grant-only cascade rather than treating the deeper `false` as a veto.","observation:rules-rtdb-r5-cascade-root-grant","packages/pyric/test/rules/rtdb/rules-conformance.test.ts"],"assurance":"eligible"},{"id":"rtdb.semantic.write-cascade","kind":"rules-construct","surface":"rtdb-rules","behavior":"semantic.write-cascade is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/database/security/core-syntax#read-and-write-rules-cascade"],"assurance":"qualified"}]},{"feature":"semantic.write-umbrella","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"semantic.write-umbrella is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#96","kind":"registry-row","surface":"storage-rules","behavior":"`evaluateStorageRules` supports granular verbs (`get`/`list`/`create`/`update`/`delete`) alongside `read`/`write` umbrella expansion, comma-separated verb lists, and per-verb default-deny","status":"conforms","evidence":["STALE ROW, corrected 2026-07-10: production capture proves the evaluator already supports the full six-verb grant surface (umbrella read→{get,list}, write→{create,update,delete}, single granular grants, comma-separated grants, per-verb deny-by-default), matching production verdict-for-verdict on 12 of the scenario's 13 non-existence cases. `oracle:rules-storage-verbs-umbrella-granular` (all `read`/`write`/`get`/comma-verb cases). One related existence-semantics case in the same scenario diverges over-permissively and is carried by `#118 Rules` (the `resource == null` create-if-absent guard), not by this granular-verb row.","observation:rules-storage-verbs-umbrella-granular","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.semantic.write-umbrella","kind":"rules-construct","surface":"storage-rules","behavior":"semantic.write-umbrella is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"eligible"}]},{"feature":"send","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"send is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#4","kind":"registry-row","surface":"messaging-admin","behavior":"Sends one message via FCM v1 and resolves with the resource name `projects/<projectId>/messages/<numeric id>`. `dryRun=true` returns the SAME shape (fake id), so callers cannot distinguish validation from acceptance by shape. Topic, condition, token, notification-only, data-only, and webpush-config sends are all accepted. Malformed sends fail server-side validation with HTTP 4xx `google.rpc` error envelopes carrying both a `google.rpc.BadRequest` (fieldViolations) and a `google.firebase.fcm.v1.FcmError` (errorCode); detail ordering is not contractual. The documented data-payload cap is 4096 bytes.","status":"conforms","evidence":["oracle: 10 send-plane observations — accept paths `messaging-send-topic-accepted`, `messaging-send-condition-accepted`, `messaging-send-notification-only-vs-data-only-accepted`, `messaging-send-webpush-config-accepted`; error envelopes `messaging-send-no-target-error-envelope`, `messaging-send-invalid-token-error-envelope`, `messaging-send-invalid-condition-error-envelope`, `messaging-send-invalid-topic-name-error-envelope`, `messaging-send-oversized-payload-error-envelope`, `messaging-send-webpush-invalid-ttl-error-envelope`. Replayed by the conformance suite.","observation:messaging-send-topic-accepted","observation:messaging-send-condition-accepted","observation:messaging-send-notification-only-vs-data-only-accepted","observation:messaging-send-webpush-config-accepted","observation:messaging-send-no-target-error-envelope","observation:messaging-send-invalid-token-error-envelope","observation:messaging-send-invalid-condition-error-envelope","observation:messaging-send-invalid-topic-name-error-envelope","observation:messaging-send-oversized-payload-error-envelope","observation:messaging-send-webpush-invalid-ttl-error-envelope","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"sendEach","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"sendEach is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#5","kind":"registry-row","surface":"messaging-admin","behavior":"Sends an array of up to 500 messages, one RPC per message; resolves a `BatchResponse` whose `responses` are ordered to match the input. Total failure is signalled by a throw or an all-failure `BatchResponse`.","status":"conforms","evidence":["Upstream typings/JSDoc (firebase-admin 13.10.0 `messaging`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"messaging-admin#6","kind":"registry-row","surface":"messaging-admin","behavior":"Fans a `MulticastMessage` (up to 500 tokens) out through `sendEach`.","status":"conforms","evidence":["Upstream typings/JSDoc (firebase-admin 13.10.0 `messaging`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"messaging-admin#9","kind":"registry-row","surface":"messaging-admin","behavior":"Forces HTTP/1.1 transport for `sendEach` / `sendEachForMulticast`; deprecated.","status":"conforms","evidence":["Upstream typings/JSDoc (firebase-admin 13.10.0 `messaging`, `@deprecated`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"sendEachForMulticast","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"sendEachForMulticast is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#9","kind":"registry-row","surface":"messaging-admin","behavior":"Forces HTTP/1.1 transport for `sendEach` / `sendEachForMulticast`; deprecated.","status":"conforms","evidence":["Upstream typings/JSDoc (firebase-admin 13.10.0 `messaging`, `@deprecated`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"sendEmailVerification","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"sendEmailVerification is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:sendEmailVerification","kind":"runtime-export","surface":"auth","behavior":"sendEmailVerification is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#156","kind":"registry-row","surface":"auth","behavior":"Throws `auth/missing-email` for a user with no email on the account (an anonymous user). For a real account the mail goes out and NOTHING ELSE HAPPENS: `user.emailVerified` stays `false`. Verification happens when the code in the message is redeemed (`applyActionCode`), not when it is sent.","status":"conforms","evidence":["ORACLE-BACKED on the anonymous reject: `auth-sendemailverification-shape` captured `anonymousUserCode: auth/missing-email` against prod. The send-does-not-verify property is the one the whole flow turns on and is unit-backed (`unit:sandbox-email-link.test.ts` asserts `emailVerified` is still false after the send and true only after the code is applied) — it cannot be oracle-confirmed end to end because confirming it would require reading a real inbox.","observation:auth-sendemailverification-shape","packages/pyric/test/auth/oracle-conformance.test.ts","packages/pyric/test/auth/sandbox-email-link.test.ts"],"assurance":"eligible"}]},{"feature":"sendMessage","surface":"ai","importPaths":[],"evidenceSlug":"ai-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"sendMessage is available, has diverged fidelity, and is qualified for assurance.","caveats":["`sendMessage` appends the user turn and the model turn; `getHistory()` returns the ordered `Content[]` with alternating roles","`unit:chat-session.test.ts` test `ai#chat-history-threads` (no capture; history threading claim)"],"claims":[{"id":"ai#chat-history-threads","kind":"registry-row","surface":"ai","behavior":"`sendMessage` appends the user turn and the model turn; `getHistory()` returns the ordered `Content[]` with alternating roles","status":"diverged-documented","evidence":["`unit:chat-session.test.ts` test `ai#chat-history-threads` (no capture; history threading claim)","packages/pyric/test/ai/chat-session.test.ts"],"assurance":"qualified"},{"id":"ai#chat-sendmessage-envelope","kind":"registry-row","surface":"ai","behavior":"A `sendMessage` result carries the same envelope facts as `generateContent`: the four top-level keys and role `model`","status":"conforms","evidence":["Capture ai-generate-minimal-envelope replayed by packages/pyric/test/ai/chat-session.test.ts test `ai#chat-sendmessage-envelope`","observation:ai-generate-minimal-envelope","packages/pyric/test/ai/chat-session.test.ts"],"assurance":"eligible"}]},{"feature":"sendMessageStream","surface":"ai","importPaths":[],"evidenceSlug":"ai-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"sendMessageStream is available, has diverged fidelity, and is qualified for assurance.","caveats":["Exactly one user turn is recorded per `sendMessageStream` call; the mirror implements the 2.13.0 fixed semantics, not the installed 2.12.0 duplicate-user-turn bug","`unit:chat-session.test.ts` test `ai#chat-stream-single-user-turn` (no capture; divergence pinned by ruling, see notes)"],"claims":[{"id":"ai#chat-sendmessagestream","kind":"registry-row","surface":"ai","behavior":"`sendMessageStream` returns a stream plus a response promise; history updates after aggregation completes","status":"conforms","evidence":["`unit:chat-session.test.ts` test `ai#chat-sendmessagestream` (no capture; streaming turn claim)","packages/pyric/test/ai/chat-session.test.ts"],"assurance":"eligible"},{"id":"ai#chat-stream-single-user-turn","kind":"registry-row","surface":"ai","behavior":"Exactly one user turn is recorded per `sendMessageStream` call; the mirror implements the 2.13.0 fixed semantics, not the installed 2.12.0 duplicate-user-turn bug","status":"diverged-documented","evidence":["`unit:chat-session.test.ts` test `ai#chat-stream-single-user-turn` (no capture; divergence pinned by ruling, see notes)","packages/pyric/test/ai/chat-session.test.ts"],"assurance":"qualified"}]},{"feature":"sendPasswordResetEmail","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"sendPasswordResetEmail is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:sendPasswordResetEmail","kind":"runtime-export","surface":"auth","behavior":"sendPasswordResetEmail is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#155","kind":"registry-row","surface":"auth","behavior":"For an address NO account owns, prod RESOLVES silently — it does not throw `auth/user-not-found`. Email Enumeration Protection is on by default and refusing to leak account existence is the point. The sandbox matches: it resolves and mails nothing. A malformed address still throws `auth/invalid-email`. For a real account, the sandbox mails a reset code; `confirmPasswordReset` redeems it and the new password signs in while the old one throws `auth/wrong-password`.","status":"conforms","evidence":["ORACLE-BACKED on the enumeration-protection behavior — the fact most likely to be got wrong: `auth-sendpasswordresetemail-unknown-user` captured `resolvedForUnknownUser: true`, `unknownUserCode: null`, `malformedEmailCode: auth/invalid-email`. A shim that threw `auth/user-not-found` here would hand agent code an account oracle production deliberately removed. Reset round trip unit-backed in `unit:sandbox-email-link.test.ts`.","observation:auth-sendpasswordresetemail-unknown-user","packages/pyric/test/auth/oracle-conformance.test.ts","packages/pyric/test/auth/sandbox-email-link.test.ts"],"assurance":"eligible"}]},{"feature":"SendResponse","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"SendResponse is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#36","kind":"registry-row","surface":"messaging-admin","behavior":"Batch send result; `responses` is a `SendResponse[]`.","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `messaging-api`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"messaging-admin#37","kind":"registry-row","surface":"messaging-admin","behavior":"Per-message batch entry — on success `messageId` is set, on failure `error` is set.","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `messaging-api`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"sendSignInLinkToEmail","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"sendSignInLinkToEmail is available, has diverged fidelity, and is qualified for assurance.","caveats":["Prod rejects a continue URL whose domain is not on the project's authorized-domains list. The sandbox has NO domain allowlist and does not invent one: it accepts any parseable continue URL. A continue URL that would be rejected in production is accepted here.","The sandbox has no project config to hold an authorized-domains list, so there is nothing to check against; inventing an allowlist would mean inventing a policy the user never set. The probe attempted the server arm (`auth-sendsigninlinktoemail-settings-validation`, `unauthorizedDomain`) but the oracle project has email-link sign-in disabled, so it answered `auth/operation-not-allowed` rather than `auth/unauthorized-continue-uri` — the divergence is declared from the documented contract, not from a capture we do not have."],"claims":[{"id":"auth:runtime:sendSignInLinkToEmail","kind":"runtime-export","surface":"auth","behavior":"sendSignInLinkToEmail is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#153","kind":"registry-row","surface":"auth","behavior":"ActionCodeSettings validation, enforced CLIENT-side before any request leaves the process: a missing or unparseable `url` throws `auth/invalid-continue-uri` (NOT `auth/missing-continue-uri`, despite the constant's name), and `handleCodeInApp` other than `true` throws `auth/argument-error`. On success the sandbox mints a single-use code and posts the message to the outbox.","status":"conforms","evidence":["ORACLE-BACKED on both client-side arms (project-independent — prod threw before any network call): `auth-sendsigninlinktoemail-settings-validation` captured `missingUrl: auth/invalid-continue-uri` and `handleCodeInAppFalse: auth/argument-error`. Replayed in `unit:oracle-conformance.test.ts`; the send path is unit-backed in `unit:sandbox-email-link.test.ts`.","observation:auth-sendsigninlinktoemail-settings-validation","packages/pyric/test/auth/oracle-conformance.test.ts","packages/pyric/test/auth/sandbox-email-link.test.ts"],"assurance":"eligible"},{"id":"auth#163","kind":"registry-row","surface":"auth","behavior":"Prod rejects a continue URL whose domain is not on the project's authorized-domains list. The sandbox has NO domain allowlist and does not invent one: it accepts any parseable continue URL. A continue URL that would be rejected in production is accepted here.","status":"diverged-documented","evidence":["The sandbox has no project config to hold an authorized-domains list, so there is nothing to check against; inventing an allowlist would mean inventing a policy the user never set. The probe attempted the server arm (`auth-sendsigninlinktoemail-settings-validation`, `unauthorizedDomain`) but the oracle project has email-link sign-in disabled, so it answered `auth/operation-not-allowed` rather than `auth/unauthorized-continue-uri` — the divergence is declared from the documented contract, not from a capture we do not have.","packages/pyric/test/auth/sandbox-email-link.test.ts"],"assurance":"qualified"}]},{"feature":"serializeRtdbRules","surface":"rtdb","importPaths":["pyric/rules/internal/rtdb"],"evidenceSlug":"database-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"serializeRtdbRules is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"rtdb#90","kind":"registry-row","surface":"rtdb","behavior":"`serializeRtdbRules(compiled)` produces the Firebase rules-JSON payload for the compiled tree","status":"conforms","evidence":["`unit:compiled-rules.test.ts`","packages/pyric/test/rules/rtdb/compiled-rules.test.ts"],"assurance":"eligible"},{"id":"rtdb#91","kind":"registry-row","surface":"rtdb","behavior":"Round-trip `compileRtdbRules(serializeRtdbRules(compiled))` produces an equivalent rules tree (locked path/expression-text equality, not object identity)","status":"conforms","evidence":["`unit:compiled-rules.test.ts`","packages/pyric/test/rules/rtdb/compiled-rules.test.ts"],"assurance":"eligible"},{"id":"rtdb#92","kind":"registry-row","surface":"rtdb","behavior":"Path-variable segments (`$userId`, `$gameId`) preserved across the round-trip","status":"conforms","evidence":["`unit:compiled-rules.test.ts`","packages/pyric/test/rules/rtdb/compiled-rules.test.ts"],"assurance":"eligible"},{"id":"rtdb#93","kind":"registry-row","surface":"rtdb","behavior":"`.indexOn` arrays preserved across the round-trip","status":"conforms","evidence":["`unit:compiled-rules.test.ts`","packages/pyric/test/rules/rtdb/compiled-rules.test.ts"],"assurance":"eligible"}]},{"feature":"serverTimestamp","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"serverTimestamp is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:serverTimestamp","kind":"runtime-export","surface":"firestore","behavior":"serverTimestamp is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#104a","kind":"registry-row","surface":"firestore","behavior":"**Unified Timestamp storage (FS-B4)** — a `Timestamp` written directly via the modular SDK (`setDoc({createdAt: Timestamp.now()})`) is stored as the same rules-internal `Timestamp` that `serverTimestamp()`/`Date` resolve to. Pre-FS-B4 a user-written `Timestamp` was the compat class only (not a `RulesValue`), so `request.resource.data.createdAt is timestamp` returned **false** for it while a `serverTimestamp()` write passed the same rule, and the two paths stored two different classes. A write-boundary converter now normalizes both.","status":"conforms","evidence":["`unit:firestore/sandbox-converters/user-timestamp.test.ts` (`is timestamp` passes for a user Timestamp; unified storage class; range-filter regression guard — verified failing pre-fix by removing the converter registration)","packages/pyric/test/firestore/sandbox-converters/user-timestamp.test.ts"],"assurance":"eligible"},{"id":"firestore#99","kind":"registry-row","surface":"firestore","behavior":"`serverTimestamp()` resolves to a `Timestamp` after the write commits","status":"conforms","evidence":["`unit:sandbox-target.test.ts`, `playground:firestore-sentinels` (bundled) + `playground:firestore-row-99-servertimestamp-resolves` (one-claim), oracle: `packages/conformance/observations/firestore/firestore-row-99-servertimestamp-resolves-to-timestamp.json` — `setDoc({at: serverTimestamp()})` then `getDoc` yields `at instanceof Timestamp === true`, `constructor.name === 'Timestamp'`, with both `.seconds` (number) and `.nanoseconds` (number) present.","observation:firestore-row-99-servertimestamp-resolves-to-timestamp","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"serverTimestamp","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"serverTimestamp is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"database:runtime:serverTimestamp","kind":"runtime-export","surface":"database","behavior":"serverTimestamp is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#153","kind":"registry-row","surface":"rtdb-modular","behavior":"`serverTimestamp()` resolves server-side to a **number** (epoch milliseconds) — diverges from Firestore's `Timestamp` instance","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb/rtdb-servertimestamp-resolves.json` — observed `createdAtType: 'number', createdAt: 1779075391118` (i.e. a plain JS number, NOT a `Timestamp` object).","observation:rtdb-servertimestamp-resolves"],"assurance":"eligible"},{"id":"rtdb-modular#154","kind":"registry-row","surface":"rtdb-modular","behavior":"`serverTimestamp()` as a field value in `set` or `update` writes the `{\".sv\": \"timestamp\"}` sentinel; the read-back value is the resolved number","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb/rtdb-servertimestamp-resolves.json` — read-back showed `createdAtSentinelShape: false` (sentinel resolved server-side; client sees the number, not the `.sv` placeholder).","observation:rtdb-servertimestamp-resolves"],"assurance":"eligible"},{"id":"rtdb-modular#M20","kind":"registry-row","surface":"rtdb-modular","behavior":"`serverTimestamp()` returns the `{ \".sv\": \"timestamp\" }` sentinel marker the wire encoder recognises","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-target.test.ts` (\"serverTimestamp() returns the documented shape\"); matches the prod wire contract","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M21","kind":"registry-row","surface":"rtdb-modular","behavior":"`serverTimestamp()` resolves to a number (epoch ms) on read-back","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-target.test.ts` (\"resolves to a number on read-back\"); matches oracle observation `packages/conformance/observations/rtdb/rtdb-servertimestamp-resolves.json` (prod observation blocked on rules; sandbox locks the contract directly)","observation:rtdb-servertimestamp-resolves","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M22","kind":"registry-row","surface":"rtdb-modular","behavior":"`serverTimestamp()` sentinels resolve when nested inside multi-path update payloads","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"resolves sentinels nested deep inside an update payload\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"SessionResumptionConfig","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"SessionResumptionConfig is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:SessionResumptionConfig","kind":"type-export","surface":"ai","behavior":"SessionResumptionConfig is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"set","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"set is available, has unverified fidelity, and is qualified for assurance.","caveats":["Replaces the value at the path entirely; resolves to `undefined` (unlike `setDoc` which resolves to `void`, RTDB's `set` is documented as `Promise<void>`)","upstream contract"],"claims":[{"id":"database:runtime:set","kind":"runtime-export","surface":"database","behavior":"set is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#111","kind":"registry-row","surface":"rtdb-modular","behavior":"Replaces the value at the path entirely; resolves to `undefined` (unlike `setDoc` which resolves to `void`, RTDB's `set` is documented as `Promise<void>`)","status":"unverified","evidence":["upstream contract"],"assurance":"qualified"},{"id":"rtdb-modular#112","kind":"registry-row","surface":"rtdb-modular","behavior":"`set(ref, null)` removes the path entirely — equivalent to `remove(ref)`, subsequent `get` returns `null`-val snapshot","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-set-null-equals-remove.json` — observed `beforeExists: true → afterExists: false, afterVal: null` after `set(ref, null)`.","observation:rtdb-modular-set-null-equals-remove"],"assurance":"eligible"},{"id":"rtdb-modular#113","kind":"registry-row","surface":"rtdb-modular","behavior":"Nested objects overwrite — `set(ref, {a: 1})` after `set(ref, {a: 1, b: 2})` leaves `{a: 1}` only, NOT a merge (RTDB `set` is replacement, not merge)","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-set-replaces-not-merges.json` — observed `final: {a: 1}` with `b` absent after the second set.","observation:rtdb-modular-set-replaces-not-merges"],"assurance":"eligible"},{"id":"rtdb-modular#114","kind":"registry-row","surface":"rtdb-modular","behavior":"Primitive round-trip — numbers, strings, booleans, arrays all survive a set→get cycle","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb/rtdb-set-then-get-roundtrip.json` — the payload round-trips structurally on both sides (this row's claim holds). NOTE — adjacent divergence pinned in `oracle-conformance.test.ts`: prod returns object children in LEXICOGRAPHIC key order (the capture's `roundTripEqual: false` — a `JSON.stringify` round-trip against a non-sorted payload fails), while the sandbox preserves insertion order (stringify round-trip succeeds). Key-order-sensitive consumers behave differently.","observation:rtdb-set-then-get-roundtrip","packages/pyric/test/database/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#115","kind":"registry-row","surface":"rtdb-modular","behavior":"Rules-denied write throws plain `Error` with `code: 'PERMISSION_DENIED'` (same shape as #110)","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb/rtdb-rules-denied-error-code.json`","observation:rtdb-rules-denied-error-code"],"assurance":"eligible"},{"id":"rtdb-modular#M10","kind":"registry-row","surface":"rtdb-modular","behavior":"`set(ref, value)` replaces the value at the path","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-target.test.ts` (\"round-trips a primitive value\" + \"round-trips nested objects\"); matches oracle observation `packages/conformance/observations/rtdb/rtdb-set-then-get-roundtrip.json` (prod observation blocked on rules; sandbox locks the contract directly)","observation:rtdb-set-then-get-roundtrip","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M11","kind":"registry-row","surface":"rtdb-modular","behavior":"`set(ref, null)` deletes the subtree at the path","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-target.test.ts` (\"set(ref, null) deletes the path\"); matches oracle observation `packages/conformance/observations/rtdb/rtdb-remove-vs-set-null.json`","observation:rtdb-remove-vs-set-null","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M12","kind":"registry-row","surface":"rtdb-modular","behavior":"`remove(ref)` is equivalent to `set(ref, null)` (same end state)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-target.test.ts` (\"remove and set(null) produce identical end-state\"); matches oracle observation `packages/conformance/observations/rtdb/rtdb-remove-vs-set-null.json`","observation:rtdb-remove-vs-set-null","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M23","kind":"registry-row","surface":"rtdb-modular","behavior":"Rules-denied write throws a plain `Error` (NOT a `FirebaseError`) with `.code === 'PERMISSION_DENIED'` (uppercase snake-case) and `.message === 'PERMISSION_DENIED: Permission denied'`","status":"conforms","evidence":["Sandbox aligned: `unit:modular/sandbox-target.test.ts` (\"rules-denied set throws a plain Error with PERMISSION_DENIED code\"); matches oracle observation `packages/conformance/observations/rtdb/rtdb-rules-denied-error-code.json` (against blockingfun, fb-js-sdk 12.13.0)","observation:rtdb-rules-denied-error-code","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M37e","kind":"registry-row","surface":"rtdb-modular","behavior":"Rules-denied transaction rejects with a plain `Error` whose `message === 'permission_denied'` (lowercase) and NO `.code` field — DIFFERENT from `set`/`get`'s `'PERMISSION_DENIED: Permission denied'` shape with uppercase `.code`.","status":"conforms","evidence":["Sandbox aligned: `unit:modular/transaction.test.ts` (\"rejects with a plain Error whose message is \\\"permission_denied\\\"\"); matches oracle observation `packages/conformance/observations/rtdb-modular/rtdb-modular-runtransaction-on-rules-denied-path.json` (against blockingfun: `message: 'permission_denied', code: null, constructorName: 'Error'`).","observation:rtdb-modular-runtransaction-on-rules-denied-path","packages/pyric/test/database/modular/transaction.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M45","kind":"registry-row","surface":"rtdb-modular","behavior":"`onChildRemoved` has NO initial replay; fires once when a direct child is deleted (via `remove(child)` or `set(child, null)`); snapshot carries the PRIOR (now-removed) value","status":"conforms","evidence":["`unit:upstream-rtdb-probes.test.ts` (parent wipe fan-out via remove(parent) / set(parent, scalar)) + `unit:modular/sandbox-child-events.test.ts` (single-child delete carries PRIOR val); matches oracle `rtdb-modular-onchildremoved-fires-on-delete.json`","observation:rtdb-modular-onchildremoved-fires-on-delete","packages/pyric/test/database/upstream-rtdb-probes.test.ts","packages/pyric/test/database/modular/sandbox-child-events.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M67","kind":"registry-row","surface":"rtdb-modular","behavior":"`null` children and empty objects are pruned at the write boundary — `set(ref, {})` is equivalent to `remove(ref)`; nested `null` collapses empty ancestors (\"empty nodes don't exist\") (DB-B3)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/normalization.test.ts` (\"set(ref, {}) is equivalent to remove\" + \"null children are pruned\"); upstream `core/snap/nodeFromJSON.ts:78-88,122-126`","packages/pyric/test/database/modular/normalization.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M68","kind":"registry-row","surface":"rtdb-modular","behavior":"Write validation: an `undefined` payload, a non-finite number (`NaN`/`±Infinity`), or a key containing a forbidden char (`.`, `#`, `$`, `/`, `[`, `]`, control chars) is rejected with a plain `Error` (DB-B1)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/normalization.test.ts` (\"rejects an undefined payload\" + \"rejects an invalid key\" + \"rejects a non-finite number\"); upstream `core/util/validation.ts:45,58,112-199`","packages/pyric/test/database/modular/normalization.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M73","kind":"registry-row","surface":"rtdb-modular","behavior":"A primitive at the ROOT is legal (`set(ref(db), 'hello')`); a subsequent child write replaces the primitive root (\"writes win\") (DB-B13)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/root-primitive.test.ts` (2 cases)","packages/pyric/test/database/modular/root-primitive.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M76","kind":"registry-row","surface":"rtdb-modular","behavior":"`.validate` rules are enforced on modular sandbox writes through `set`, atomic `update`, and `runTransaction`; a descendant validation failure rejects the operation without changing state.","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` executes all three write paths against a required-child `.validate` rule and proves each rejects without committing state. The shared `SimulateHandler` behavior is production-locked by RTDB rules corpus rows #4 and #15.","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"set.difference","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"set.difference is available, has unsupported fidelity, and is ineligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.set.difference","kind":"rules-construct","surface":"firestore-rules","behavior":"set.difference is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.List#function_difference_"],"assurance":"ineligible"}]},{"feature":"set.hasAll","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"set.hasAll is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.set.hasAll","kind":"rules-construct","surface":"firestore-rules","behavior":"set.hasAll is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.List#function_hasAll_"],"assurance":"eligible"}]},{"feature":"set.hasAny","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"set.hasAny is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.set.hasAny","kind":"rules-construct","surface":"firestore-rules","behavior":"set.hasAny is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.List#function_hasAny_"],"assurance":"eligible"}]},{"feature":"set.hasOnly","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"set.hasOnly is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.set.hasOnly","kind":"rules-construct","surface":"firestore-rules","behavior":"set.hasOnly is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.List#function_hasOnly_"],"assurance":"eligible"}]},{"feature":"set.intersection","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"set.intersection is available, has unsupported fidelity, and is ineligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.set.intersection","kind":"rules-construct","surface":"firestore-rules","behavior":"set.intersection is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.List#function_intersection_"],"assurance":"ineligible"}]},{"feature":"set.size","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"set.size is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.set.size","kind":"rules-construct","surface":"firestore-rules","behavior":"set.size is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.List#function_size_"],"assurance":"eligible"}]},{"feature":"set.union","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"set.union is available, has unsupported fidelity, and is ineligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.set.union","kind":"rules-construct","surface":"firestore-rules","behavior":"set.union is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.List#function_union_"],"assurance":"ineligible"}]},{"feature":"setData","surface":"rtdb","importPaths":[],"evidenceSlug":"database-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"setData is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"rtdb-modular#M34","kind":"registry-row","surface":"rtdb-modular","behavior":"`sandbox.setData(db, { '/path': value })` bulk-loads data, bypassing rules","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"sandbox.setData seeds the tree (rule-bypass)\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"setDoc","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"setDoc is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:setDoc","kind":"runtime-export","surface":"firestore","behavior":"setDoc is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#26","kind":"registry-row","surface":"firestore","behavior":"No options → replaces the existing document entirely","status":"conforms","evidence":["`unit:sandbox-target.test.ts` (\"setDoc default replaces\")","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#27","kind":"registry-row","surface":"firestore","behavior":"`{ merge: true }` → **deep-merges nested maps** (FS-B6), preserving unspecified fields at every level: `setDoc({a:{b:2}}, {merge:true})` over `{a:{c:1}}` yields `{a:{b:2,c:1}}`. Pre-FS-B6 the wrapper shallow-replaced the whole `a` map.","status":"conforms","evidence":["`unit:sandbox-target.test.ts`, `unit:admin-compat/field-path-merge.test.ts` (FS-B6 nested deep-merge; verified failing pre-fix)","packages/pyric/test/firestore/sandbox-target.test.ts","packages/pyric/test/sandbox/firestore/admin-compat/field-path-merge.test.ts"],"assurance":"eligible"},{"id":"firestore#28","kind":"registry-row","surface":"firestore","behavior":"`{ mergeFields: [...] }` → writes only the listed **dot-separated field paths** into the existing doc (FS-B6); other keys in `data` are ignored, other fields in the existing doc preserved. `mergeFields: ['a.b']` reaches into a nested map.","status":"conforms","evidence":["`unit:sandbox-target.test.ts`, `unit:admin-compat/field-path-merge.test.ts` (dotted mergeField); mask edges (delete/transform outside mask, empty mask, deleteField in mask): `unit:upstream-write-aggregate-probes.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts","packages/pyric/test/sandbox/firestore/admin-compat/field-path-merge.test.ts","packages/pyric/test/firestore/upstream-write-aggregate-probes.test.ts"],"assurance":"eligible"},{"id":"firestore#29","kind":"registry-row","surface":"firestore","behavior":"Passing both `merge` and `mergeFields` — `mergeFields` wins on sandbox (matches JS SDK effective behavior)","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#30","kind":"registry-row","surface":"firestore","behavior":"Sentinels (`serverTimestamp`, `increment`, `arrayUnion`, `arrayRemove`, `deleteField`) resolve in the same call","status":"conforms","evidence":["`unit:sandbox-target.test.ts`, `playground:firestore-sentinels`, oracle: `packages/conformance/observations/firestore/firestore-row-30-sentinels-in-setdoc.json` — `setDoc({createdAt: serverTimestamp(), count: 5, tags: ['a']})` followed by `getDoc` returns `createdAt` as a `Timestamp` instance (constructor name `Timestamp`, has `seconds` + `nanoseconds`), `count === 5` (number), `tags === ['a']`. Sentinels resolve server-side and the follow-up read sees concrete values, not the sentinel placeholders.","observation:firestore-row-30-sentinels-in-setdoc","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#31","kind":"registry-row","surface":"firestore","behavior":"Converter (via `withConverter`) runs `toFirestore(data)` before the write","status":"conforms","evidence":["`unit:sandbox-target.test.ts` (\"withConverter on a DocumentReference round-trips\")","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#32","kind":"registry-row","surface":"firestore","behavior":"Rules-denied write throws `permission-denied` (sandbox) / `FirebaseError` (prod)","status":"conforms","evidence":["`unit:sandbox-target.test.ts` (\"getDoc denies when rules reject\"), `playground:rules-data-validation`, oracle: `packages/conformance/observations/firestore/firestore-write-denied-error-code.json` (prod `setDoc` on a denied path throws a `FirebaseError` with `.code === 'permission-denied'`, `.message === '7 PERMISSION_DENIED: Missing or insufficient permissions.'`, `instanceof Error`)","observation:firestore-write-denied-error-code","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"setIndexConfiguration","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"setIndexConfiguration is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Index-tuning / GC-policy APIs have no real knob to turn in an in-memory sandbox today, but sibling cache-factory tokens are already honest inert tokens; these are buildable the same way and not genuinely out of scope."],"claims":[{"id":"firestore:runtime:setIndexConfiguration","kind":"runtime-export","surface":"firestore","behavior":"Index-tuning / GC-policy APIs have no real knob to turn in an in-memory sandbox today, but sibling cache-factory tokens are already honest inert tokens; these are buildable the same way and not genuinely out of scope.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"}]},{"feature":"setLogLevel","surface":"app","importPaths":["pyric/app"],"evidenceSlug":"app-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"setLogLevel is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"app:runtime:setLogLevel","kind":"runtime-export","surface":"app","behavior":"setLogLevel is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"app#13","kind":"registry-row","surface":"app","behavior":"`onLog(cb)` / `setLogLevel(level)` are a functioning app-owned diagnostic-logger seam: registering a handler returns undefined, raising the threshold takes effect, and a malformed `registerVersion` emits a `warn` entry (type `@firebase/app`) to the handler","status":"conforms","evidence":["oracle: `app-registry-onlog-setloglevel` (firebase 12.13.0) + replay: `oracle-conformance.test.ts`","observation:app-registry-onlog-setloglevel","packages/pyric/test/app/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"setLogLevel","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"setLogLevel is available, has diverged fidelity, and is qualified for assurance.","caveats":["Accepted no-op — the sandbox has no modular-SDK-style logger to wire a level into; it uses host-level `console` logging directly, gated by `pyric dev`'s own flags, not this call","`unit:firestore/tier1-cache-init-align.test.ts`"],"claims":[{"id":"firestore:runtime:setLogLevel","kind":"runtime-export","surface":"firestore","behavior":"setLogLevel is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#149","kind":"registry-row","surface":"firestore","behavior":"Accepted no-op — the sandbox has no modular-SDK-style logger to wire a level into; it uses host-level `console` logging directly, gated by `pyric dev`'s own flags, not this call","status":"diverged-documented","evidence":["`unit:firestore/tier1-cache-init-align.test.ts`","packages/pyric/test/firestore/tier1-cache-init-align.test.ts"],"assurance":"qualified"}]},{"feature":"SetOptions","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"SetOptions is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"firestore:type:SetOptions","kind":"type-export","surface":"firestore","behavior":"SetOptions is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"setPersistence","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"setPersistence is available, has diverged fidelity, and is qualified for assurance.","caveats":["Actually changes where the auth state is persisted","divergence: sandbox is a no-op. Prod respects the marker."],"claims":[{"id":"auth:runtime:setPersistence","kind":"runtime-export","surface":"auth","behavior":"setPersistence is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#41","kind":"registry-row","surface":"auth","behavior":"Accepts `inMemoryPersistence` / `browserSessionPersistence` / `browserLocalPersistence` markers without throwing","status":"conforms","evidence":["`unit:types.test.ts`","packages/pyric/test/auth/types.test.ts"],"assurance":"eligible"},{"id":"auth#42","kind":"registry-row","surface":"auth","behavior":"Returns `Promise<void>`","status":"conforms","evidence":["`unit:types.test.ts`","packages/pyric/test/auth/types.test.ts"],"assurance":"eligible"},{"id":"auth#43","kind":"registry-row","surface":"auth","behavior":"Actually changes where the auth state is persisted","status":"diverged-documented","evidence":["divergence: sandbox is a no-op. Prod respects the marker."],"assurance":"qualified"},{"id":"auth#43a","kind":"registry-row","surface":"auth","behavior":"An unrecognized persistence marker is rejected with `auth/argument-error` rather than silently coerced to LOCAL","status":"conforms","evidence":["`unit:sandbox-cluster-b9-b12.test.ts` (locks AUTH-B12)","packages/pyric/test/auth/sandbox-cluster-b9-b12.test.ts"],"assurance":"eligible"}]},{"feature":"setPriority","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"setPriority is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Firebase's legacy priority ordering system is absent; the sandbox exposes orderByChild/Key/Value only today. Priority ordering is data-modelable as a sort key, so this is revisitable scope rather than a hard sandbox limitation."],"claims":[{"id":"database:runtime:setPriority","kind":"runtime-export","surface":"database","behavior":"Firebase's legacy priority ordering system is absent; the sandbox exposes orderByChild/Key/Value only today. Priority ordering is data-modelable as a sort key, so this is revisitable scope rather than a hard sandbox limitation.","status":"deferred","evidence":["upstream:firebase/database"],"assurance":"not-applicable"}]},{"feature":"setRules","surface":"firestore","importPaths":[],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"setRules is available, has diverged fidelity, and is qualified for assurance.","caveats":["DEFERRED sub-items of row 138: strict bool in `&&`/`||`/ternary (`1 && true` should error) — corpus-coupled, needs emulator; a FLOAT stored in JSON test-data reads as int (`data.x is float`→false; prod uses the stored Firestore type tag) — needs a `__type:'float'` test-data revive marker; `resource`-null-on-create (RULES-B12 rest)","DEFERRED — see the design rationale (limitation + sub-items); strict-bool also in `step-07`."],"claims":[{"id":"firestore#127","kind":"registry-row","surface":"firestore","behavior":"`request.auth.uid` reads through to `sandbox.currentUser?.uid` on sandbox-live","status":"conforms","evidence":["`playground:auth-anonymous`, `playground:rules-cross-doc-get`"],"assurance":"eligible"},{"id":"firestore#128","kind":"registry-row","surface":"firestore","behavior":"`request.auth == null` when sandbox.currentUser is null (anonymous path)","status":"conforms","evidence":["`unit:sandbox-live-identity.test.ts` (\"anonymous fallback\")","packages/pyric/test/firestore/sandbox-live-identity.test.ts"],"assurance":"eligible"},{"id":"firestore#129","kind":"registry-row","surface":"firestore","behavior":"Cross-doc `get(/databases/$(database)/documents/...)` in rules works under sandbox; `get()` of a **missing** doc ERRORS (guard with `exists()`), and `get(p).id` / `get(p).__name__` expose the doc identity (RULES-B8)","status":"conforms","evidence":["`playground:rules-cross-doc-get`, `unit:rules/simulator/evaluator.test.ts` (RULES-B8 block)","packages/pyric/test/rules/simulator/evaluator.test.ts"],"assurance":"eligible"},{"id":"firestore#130","kind":"registry-row","surface":"firestore","behavior":"`request.resource.data.<field>` field validation in rules works under sandbox; an **undefined** field read ERRORS (deny), it does NOT read as null (RULES-B2) — guard with `'f' in data` / `data.get('f', d)`","status":"conforms","evidence":["`playground:rules-data-validation`, `unit:rules/simulator/evaluator.test.ts` (RULES-B2 block)","packages/pyric/test/rules/simulator/evaluator.test.ts"],"assurance":"eligible"},{"id":"firestore#131","kind":"registry-row","surface":"firestore","behavior":"`resource.data.<field>` (existing doc on writes) works under sandbox; undefined-field reads ERROR (RULES-B2)","status":"conforms","evidence":["`playground:rules-resource-data-field`, `unit:rules/simulator/evaluator.test.ts` (RULES-B2 block)","packages/pyric/test/rules/simulator/evaluator.test.ts"],"assurance":"eligible"},{"id":"firestore#132","kind":"registry-row","surface":"firestore","behavior":"Custom claims in `request.auth.token.<claim>`","status":"conforms","evidence":["`playground:rules-custom-claims`"],"assurance":"eligible"},{"id":"firestore#133","kind":"registry-row","surface":"firestore","behavior":"Tri-state error semantics: DOTTED field access of a missing key (`resource.data.typo`), access on null/undefined, undefined variables, and `get()`-of-missing ERROR → deny; `&&`/`||` absorb operand errors **commutatively** (CEL: `error || true` → true, `error && false` → false). NOTE: DYNAMIC index access `data[expr]` stays null-on-miss (the documented may-be-absent-lookup idiom; only dotted access is doc-confirmed to error). (RULES-B2/B3/B8)","status":"conforms","evidence":["`unit:rules/simulator/evaluator.test.ts` (RULES-B2 / RULES-B3 / RULES-B8 blocks)","packages/pyric/test/rules/simulator/evaluator.test.ts"],"assurance":"eligible"},{"id":"firestore#134","kind":"registry-row","surface":"firestore","behavior":"`matches()` is a **full-string** anchored RE2 test; `replace()`/`split()` take regexes (`replace` = all occurrences) (RULES-B4)","status":"conforms","evidence":["`unit:rules/simulator/evaluator.test.ts` (RULES-B4 block)","packages/pyric/test/rules/simulator/evaluator.test.ts"],"assurance":"eligible"},{"id":"firestore#135","kind":"registry-row","surface":"firestore","behavior":"No JS prototype-chain leakage: `'toString' in data` → false, `data.constructor` errors; `in`/`hasAll`/`get` use own keys only (RULES-B7)","status":"conforms","evidence":["`unit:rules/simulator/evaluator.test.ts` (RULES-B7 block)","packages/pyric/test/rules/simulator/evaluator.test.ts"],"assurance":"eligible"},{"id":"firestore#136","kind":"registry-row","surface":"firestore","behavior":"Type-strict operators: `+` requires matching operand types (`'a' + 1` errors; `[1]+[2]` concatenates); ordered compares (`< > <= >=`) error across types; list membership uses value equality; `is map` excludes MapDiff/Set (RULES-B6 partial / B9 / B12 partial)","status":"conforms","evidence":["`unit:rules/simulator/evaluator.test.ts` (RULES-B6 / B9 / B12 blocks)","packages/pyric/test/rules/simulator/evaluator.test.ts"],"assurance":"eligible"},{"id":"firestore#136b","kind":"registry-row","surface":"firestore","behavior":"`FirestoreSet` VALUE equality: `diff.addedKeys() == [uid].toSet()` compares set contents (order-insensitive); `set == list` is false, not an error (RULES-B13). Pre-fix, ANY two sets compared EQUAL (generic-object deep-equals saw no enumerable keys) — a false-PERMISSIVE divergence found by joining validation","status":"conforms","evidence":["`unit:rules/simulator/set-equality.test.ts`; live validation: 10/10 both engines","packages/pyric/test/rules/simulator/set-equality.test.ts"],"assurance":"eligible"},{"id":"firestore#137","kind":"registry-row","surface":"firestore","behavior":"`update` exposes `request.resource.data` / `getAfter()` as the existing doc **merged** with the payload via the `writeMode: { kind: 'update' }` path (the agent-facing `simulate()` opt-in); a sparse no-writeMode payload that drops a field now ERRORS on that field (RULES-B2) rather than silently reading null (RULES-B10)","status":"conforms","evidence":["`unit:rules/simulator/handler.test.ts` (RULES-B10 block)","packages/pyric/test/rules/simulator/handler.test.ts"],"assurance":"eligible"},{"id":"firestore#138","kind":"registry-row","surface":"firestore","behavior":"Int/float distinction (`1.5 is int`→false, `1 is float`→false, `1.0 is float`→true) + integer division (`10 / 4 == 2`) + int div/mod-by-zero ERRORS (RULES-B5); strict `int('12abc')`/`float('abc')`/`bool('false')`/`bool('yes')` parsing (RULES-B6 rest); `string(1.0)`→\"1.0\" (RULES-B12 rest)","status":"conforms","evidence":["`unit:rules/simulator/evaluator.test.ts` (RULES-B5 + \"RULES-B6 remainder\" blocks); `unit:rules/simulator/handler.test.ts` (\"RULES-B5 end-to-end\" block)","packages/pyric/test/rules/simulator/evaluator.test.ts","packages/pyric/test/rules/simulator/handler.test.ts"],"assurance":"eligible"},{"id":"firestore#138a","kind":"registry-row","surface":"firestore","behavior":"DEFERRED sub-items of row 138: strict bool in `&&`/`||`/ternary (`1 && true` should error) — corpus-coupled, needs emulator; a FLOAT stored in JSON test-data reads as int (`data.x is float`→false; prod uses the stored Firestore type tag) — needs a `__type:'float'` test-data revive marker; `resource`-null-on-create (RULES-B12 rest)","status":"diverged-documented","evidence":["DEFERRED — see the design rationale (limitation + sub-items); strict-bool also in `step-07`."],"assurance":"qualified"},{"id":"firestore#139","kind":"registry-row","surface":"firestore","behavior":"Query-proof EVALUATION — the rules-side decision (\"rules are not filters\"): given a `list` rule + query constraints, decide provable-or-reject (a doc-dependent rule like `resource.data.visibility == 'public'` is provable ONLY with a matching `where('visibility','==','public')`; otherwise the whole query is rejected) (RULES-B11 rules-side)","status":"conforms","evidence":["`unit:rules/simulator/query-proof.test.ts`","packages/pyric/test/rules/simulator/query-proof.test.ts"],"assurance":"eligible"},{"id":"firestore#139a","kind":"registry-row","surface":"firestore","behavior":"Query-proof ENFORCEMENT wiring — `silentReadCollection` + `readQueryCandidates` call `evaluateQueryProof` (via `sandbox/firestore/list-query-proof.ts`) instead of the per-doc silent-omission filter; structured `where`/`limit`/`orderBy` constraints are threaded from `QueryImpl.structuredConstraints()` through both the one-shot (`getDocs`/aggregate) and listener (`SnapshotTarget` applier `.structured`) paths, and `request.query.{limit,offset,orderBy}` is populated on list test cases (RULES-B11 cross-file)","status":"conforms","evidence":["`unit:firestore/query-proof-enforcement.test.ts` (both paths; verified failing pre-fix); prover scope caveat: row 24c","packages/pyric/test/firestore/query-proof-enforcement.test.ts"],"assurance":"eligible"}]},{"feature":"setRules","surface":"rtdb","importPaths":[],"evidenceSlug":"database-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"setRules is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"rtdb-modular#M33","kind":"registry-row","surface":"rtdb-modular","behavior":"`sandbox.setRules(db, rulesJson)` deploys rules to the in-process simulator; `setRules(db, null)` clears rules (default-allow)","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"sandbox.setRules(db, null) clears rules\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"setRules","surface":"storage","importPaths":[],"evidenceSlug":"storage-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"setRules is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage#105","kind":"registry-row","surface":"storage","behavior":"Op-level enforcement: `uploadBytes` against a denied path throws `storage/unauthorized` on sandbox / `storage/unauthorized` on prod, `.code` exposed on both","status":"conforms","evidence":["ST-B1 fixed: sandbox now throws a `StorageError` (see `src/storage/errors.ts`) whose `.code === 'storage/unauthorized'` — matching prod's `FirebaseError.code`. Probe: `unit:error-codes.test.ts` (\"unauthorized when rules deny the operation\"). Residual divergence (documented, not a `.code` gap): the sandbox `StorageError.name` is `'StorageError'` (plain `Error` subclass, same shape as Firestore's `SandboxError`) where prod reports `name: 'FirebaseError'` / `isFirebaseError: true`, and the message wording differs (sandbox embeds the matched-rule reason chain). Oracle-locked: `packages/conformance/observations/storage/storage-rules-denied-error-code.json` (against blockingfun, fb-js-sdk 12.13.0: `code: 'storage/unauthorized'`, message `\"Firebase Storage: User does not have permission to access '<path>'.\"`, `name: 'FirebaseError'`, `isFirebaseError: true`).","observation:storage-rules-denied-error-code","packages/pyric/test/storage/error-codes.test.ts"],"assurance":"eligible"},{"id":"storage#106","kind":"registry-row","surface":"storage","behavior":"`getMetadata` against a denied path throws `storage/unauthorized`","status":"conforms","evidence":["`unit:rules.test.ts` (operation-integration section)","packages/pyric/test/storage/rules.test.ts"],"assurance":"eligible"},{"id":"storage#107","kind":"registry-row","surface":"storage","behavior":"`updateMetadata` against a denied path throws `storage/unauthorized`","status":"conforms","evidence":["`unit:rules.test.ts`","packages/pyric/test/storage/rules.test.ts"],"assurance":"eligible"},{"id":"storage#108","kind":"registry-row","surface":"storage","behavior":"`deleteObject` against a denied path throws `storage/unauthorized`","status":"conforms","evidence":["`unit:rules.test.ts`","packages/pyric/test/storage/rules.test.ts"],"assurance":"eligible"},{"id":"storage#109","kind":"registry-row","surface":"storage","behavior":"Ordinary SDK object paths are evaluated under Firebase Storage's canonical `/b/{bucket}/o/{object}` rules namespace while metadata preserves the ordinary object path","status":"conforms","evidence":["`unit:rules.test.ts` (\"maps ordinary SDK object paths into the canonical bucket rules namespace\"). Production's canonical `/b/{bucket}/o/...` namespace is independently captured on the `storage-rules` surface; this adapter mapping seam is unit-backed rather than presented as a production observation.","packages/pyric/test/storage/rules.test.ts"],"assurance":"eligible"}]},{"feature":"SettableMetadata","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"SettableMetadata is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"storage:type:SettableMetadata","kind":"type-export","surface":"storage","behavior":"SettableMetadata is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"setWithPriority","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"setWithPriority is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Firebase's legacy priority ordering system is absent; the sandbox exposes orderByChild/Key/Value only today. Priority ordering is data-modelable as a sort key, so this is revisitable scope rather than a hard sandbox limitation."],"claims":[{"id":"database:runtime:setWithPriority","kind":"runtime-export","surface":"database","behavior":"Firebase's legacy priority ordering system is absent; the sandbox exposes orderByChild/Key/Value only today. Priority ordering is data-modelable as a sort key, so this is revisitable scope rather than a hard sandbox limitation.","status":"deferred","evidence":["upstream:firebase/database"],"assurance":"not-applicable"}]},{"feature":"signInAnonymously","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"signInAnonymously is available, has diverged fidelity, and is qualified for assurance.","caveats":["Auto-generates a uid for fresh sign-ins (sandbox format: `anonymous-{N}`)","`unit:sandbox-anonymous.test.ts` — prod uids are 28-char base64-ish; sandbox uses a readable counter for debuggability","Anonymous users persist across page reload via configured `Persistence` (prod only — sandbox has no persistence layer)","divergence: sandbox memory only; within one tab the user persists, across reload they don't"],"claims":[{"id":"auth:runtime:signInAnonymously","kind":"runtime-export","surface":"auth","behavior":"signInAnonymously is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#10","kind":"registry-row","surface":"auth","behavior":"Fires `onAuthStateChanged` exactly once per state transition (no same-value double-fire)","status":"conforms","evidence":["`unit:sandbox-listeners.test.ts`, `playground:auth-anonymous` (bundled) + `playground:auth-row-10-onauthstatechanged-one-per-transition` (one-claim) — fix from #399 + oracle: `packages/conformance/observations/auth/auth-row-10-onauthstatechanged-one-per-transition.json` (against blockingfun, fb-js-sdk 12.13.0: subscribe → 1 initial null fire → `signInAnonymously` → +1 → `signOut` → +1 → `signInAnonymously` → +1. `eachTransitionFiredExactlyOnce: true` — every transition produces exactly one fire)","observation:auth-row-10-onauthstatechanged-one-per-transition","packages/pyric/test/auth/sandbox-listeners.test.ts"],"assurance":"eligible"},{"id":"auth#11","kind":"registry-row","surface":"auth","behavior":"Writes through to `sandbox.currentUser` so rules engines see `request.auth.uid`","status":"conforms","evidence":["`unit:sandbox-anonymous.test.ts`, `playground:auth-anonymous` (bundled) + `playground:auth-row-11-anon-uid-visible-to-rules` (one-claim)","packages/pyric/test/auth/sandbox-anonymous.test.ts"],"assurance":"eligible"},{"id":"auth#12","kind":"registry-row","surface":"auth","behavior":"Anonymous users persist across page reload via configured `Persistence` (prod only — sandbox has no persistence layer)","status":"diverged-documented","evidence":["divergence: sandbox memory only; within one tab the user persists, across reload they don't"],"assurance":"qualified"},{"id":"auth#6","kind":"registry-row","surface":"auth","behavior":"Returns `UserCredential` with `providerId: null`, `operationType: 'signIn'`, and a `User` with `isAnonymous: true`, `email: null`, `displayName: null`","status":"conforms","evidence":["`unit:sandbox-anonymous.test.ts`, `playground:auth-anonymous` (bundled) + `playground:auth-row-6-anon-credential-shape` (one-claim) + oracle: `packages/conformance/observations/auth/auth-anonymous-credential-providerid.json` (`providerId: null` against blockingfun, fb-js-sdk 12.13.0). Prior matrix language said `providerId: 'anonymous'`; corrected after empirical observation. Sandbox aligned to prod in the same commit.","observation:auth-anonymous-credential-providerid","packages/pyric/test/auth/sandbox-anonymous.test.ts"],"assurance":"eligible"},{"id":"auth#7","kind":"registry-row","surface":"auth","behavior":"Auto-generates a uid for fresh sign-ins (sandbox format: `anonymous-{N}`)","status":"diverged-documented","evidence":["`unit:sandbox-anonymous.test.ts` — prod uids are 28-char base64-ish; sandbox uses a readable counter for debuggability","packages/pyric/test/auth/sandbox-anonymous.test.ts"],"assurance":"qualified"},{"id":"auth#8","kind":"registry-row","surface":"auth","behavior":"If an anonymous user is already signed in, returns the SAME user (no fresh uid mint)","status":"conforms","evidence":["`unit:sandbox-anonymous.test.ts` (\"idempotent while signed in\") — fix from #399","packages/pyric/test/auth/sandbox-anonymous.test.ts"],"assurance":"eligible"},{"id":"auth#9","kind":"registry-row","surface":"auth","behavior":"After `signOut`, a subsequent `signInAnonymously` mints a fresh uid","status":"conforms","evidence":["`unit:sandbox-anonymous.test.ts`, `playground:auth-anonymous` (bundled) + `playground:auth-row-9-anon-fresh-uid-after-signout` (one-claim)","packages/pyric/test/auth/sandbox-anonymous.test.ts"],"assurance":"eligible"}]},{"feature":"SignInMethod","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"SignInMethod is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:SignInMethod","kind":"runtime-export","surface":"auth","behavior":"SignInMethod is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#172","kind":"registry-row","surface":"auth","behavior":"The constant maps, value for value. `OperationType.SIGN_IN === 'signIn'`, `SignInMethod.EMAIL_LINK === 'emailLink'`, `ProviderId.GOOGLE === 'google.com'`, `ActionCodeOperation.PASSWORD_RESET === 'PASSWORD_RESET'`, and the 106-entry `AuthErrorCodes` map (`INVALID_OOB_CODE === 'auth/invalid-action-code'`, `PROVIDER_ALREADY_LINKED === 'auth/provider-already-linked'`, `NO_SUCH_PROVIDER === 'auth/no-such-provider'`, `USER_MISMATCH === 'auth/user-mismatch'`, …).","status":"conforms","evidence":["ORACLE-BACKED, snapshotted straight from the shipped SDK: `auth-mechanical-surface-constants` against firebase-js-sdk 12.13.0, replayed value-for-value in `unit:oracle-conformance.test.ts`. This matters more than it looks: consumer code COMPARES against these constants, so a mirror that got a string wrong would turn every such comparison into a silent `false` — a worse failure than the export simply being absent, because it typechecks and runs. NOTE: the capture's `persistenceTypes` block is deliberately NOT asserted — the harness runs under Node, where firebase/auth stubs the browser-only persistence tokens to `type: 'NONE'` (it reports 'NONE' even for `browserLocalPersistence`, which is unambiguously 'LOCAL'); asserting it would be asserting a harness artifact. See auth#178.","observation:auth-mechanical-surface-constants","packages/pyric/test/auth/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"signInWithCredential","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"signInWithCredential is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["Opens a popup window in prod","divergence: sandbox skips the popup; mock pre-stage replaces the popup result","Cancels with `auth/popup-closed-by-user` when the user dismisses the popup (prod)","not modeled — would require the host to expose a \"cancel\" affordance on the mock"],"claims":[{"id":"auth:runtime:signInWithCredential","kind":"runtime-export","surface":"auth","behavior":"signInWithCredential is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#44","kind":"registry-row","surface":"auth","behavior":"Returns the pre-staged `UserCredential` registered via `sandbox.mockSignInResult(auth, …)`","status":"conforms","evidence":["`unit:sandbox-providers.test.ts`","packages/pyric/test/auth/sandbox-providers.test.ts"],"assurance":"eligible"},{"id":"auth#45","kind":"registry-row","surface":"auth","behavior":"Throws `auth/no-mock-configured` when no mock is pre-staged","status":"conforms","evidence":["`unit:sandbox-providers.test.ts`","packages/pyric/test/auth/sandbox-providers.test.ts"],"assurance":"eligible"},{"id":"auth#46","kind":"registry-row","surface":"auth","behavior":"Mock is consumed after one read (subsequent call without a fresh stage throws again)","status":"conforms","evidence":["`unit:sandbox-providers.test.ts`","packages/pyric/test/auth/sandbox-providers.test.ts"],"assurance":"eligible"},{"id":"auth#47","kind":"registry-row","surface":"auth","behavior":"After successful sign-in, `currentUser` becomes the mock's `user`, listeners fire","status":"conforms","evidence":["`unit:sandbox-providers.test.ts`","packages/pyric/test/auth/sandbox-providers.test.ts"],"assurance":"eligible"},{"id":"auth#47a","kind":"registry-row","surface":"auth","behavior":"The credential's rich `User` (email / displayName / isAnonymous) survives the transition — popup/redirect/credential/`setUser` do NOT clobber it down to the bare `AuthState`; `cred.user === auth.currentUser` (reference identity, matches upstream `_updateCurrentUser(userCredential.user)`)","status":"conforms","evidence":["`unit:sandbox-user-identity.test.ts` (locks AUTH-B1)","packages/pyric/test/auth/sandbox-user-identity.test.ts"],"assurance":"eligible"},{"id":"auth#48","kind":"registry-row","surface":"auth","behavior":"Opens a popup window in prod","status":"diverged-documented","evidence":["divergence: sandbox skips the popup; mock pre-stage replaces the popup result"],"assurance":"qualified"},{"id":"auth#49","kind":"registry-row","surface":"auth","behavior":"Cancels with `auth/popup-closed-by-user` when the user dismisses the popup (prod)","status":"unsupported","evidence":["not modeled — would require the host to expose a \"cancel\" affordance on the mock"],"assurance":"ineligible"},{"id":"auth#70","kind":"registry-row","surface":"auth","behavior":"Provider-flow sign-ins (popup / redirect / credential) record the flow's `providerId` on the identity in the user DB (upsert for unknown uids; append-if-missing for known ones) and reject disabled accounts with `auth/user-disabled` before any state change","status":"conforms","evidence":["`unit:sandbox-user-admin.test.ts` (\"provider tracking\", \"disabled users\") — provider recording is sandbox bookkeeping for `listIdentities`/`listUsers`; prod's auto-link semantics are narrower (same-email Google auto-link only) and not modeled","packages/pyric/test/auth/sandbox-user-admin.test.ts"],"assurance":"eligible"}]},{"feature":"signInWithCustomToken","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"signInWithCustomToken is available, has diverged fidelity, and is qualified for assurance.","caveats":["Throws `auth/invalid-custom-token` for a malformed token and for the empty string. The sandbox accepts a token in the two shapes it can honestly read: a JSON (optionally base64url) `{uid, claims}` payload — exactly what `admin.auth().createCustomToken` signs, so the pyric-admin mint and this redeem compose — or a real three-part JWT whose payload segment carries `uid`/`sub`. The SIGNATURE IS NOT VERIFIED: the sandbox has no service-account key. The identity is created if it does not exist, and the credential carries `providerId: null` (custom-token sign-in is not a federated provider).","ORACLE-BACKED on the reject path: `auth-signinwithcustomtoken-invalid` captured `auth/invalid-custom-token` for both a malformed token and the empty string, replayed in `unit:oracle-conformance.test.ts`. Diverged on the ACCEPT path, declared rather than hidden: prod verifies an RS256 signature against the project's service-account key and the sandbox has no key, so it reads the token's claims WITHOUT verifying them. A forged token that prod would reject is accepted here. The happy path cannot be oracle-probed from a Web SDK client at all (it needs an Admin-SDK-signed JWT)."],"claims":[{"id":"auth:runtime:signInWithCustomToken","kind":"runtime-export","surface":"auth","behavior":"signInWithCustomToken is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#173","kind":"registry-row","surface":"auth","behavior":"Throws `auth/invalid-custom-token` for a malformed token and for the empty string. The sandbox accepts a token in the two shapes it can honestly read: a JSON (optionally base64url) `{uid, claims}` payload — exactly what `admin.auth().createCustomToken` signs, so the pyric-admin mint and this redeem compose — or a real three-part JWT whose payload segment carries `uid`/`sub`. The SIGNATURE IS NOT VERIFIED: the sandbox has no service-account key. The identity is created if it does not exist, and the credential carries `providerId: null` (custom-token sign-in is not a federated provider).","status":"diverged-documented","evidence":["ORACLE-BACKED on the reject path: `auth-signinwithcustomtoken-invalid` captured `auth/invalid-custom-token` for both a malformed token and the empty string, replayed in `unit:oracle-conformance.test.ts`. Diverged on the ACCEPT path, declared rather than hidden: prod verifies an RS256 signature against the project's service-account key and the sandbox has no key, so it reads the token's claims WITHOUT verifying them. A forged token that prod would reject is accepted here. The happy path cannot be oracle-probed from a Web SDK client at all (it needs an Admin-SDK-signed JWT).","observation:auth-signinwithcustomtoken-invalid","packages/pyric/test/auth/oracle-conformance.test.ts"],"assurance":"qualified"}]},{"feature":"signInWithEmailAndPassword","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"signInWithEmailAndPassword is available, has diverged fidelity, and is qualified for assurance.","caveats":["An EMPTY password throws `auth/missing-password` (message \"A non-empty password must be provided\"), fired before the user-DB lookup so it can't be used to enumerate seeded emails. Upstream maps the `MISSING_PASSWORD` server error (`core/errors.ts:92,282,563`). ⚠ best-known semantics — message text not yet captured against a live project (STOP-flagged for an oracle pass; the `.code` is the load-bearing part).","`unit:sandbox-cluster-b9-b12.test.ts` (locks AUTH-B11)"],"claims":[{"id":"auth:runtime:signInWithEmailAndPassword","kind":"runtime-export","surface":"auth","behavior":"signInWithEmailAndPassword is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#13","kind":"registry-row","surface":"auth","behavior":"Returns `UserCredential` with `providerId: null` (NOT `'password'` — only OAuth/phone responses carry a providerId; upstream `providerIdForResponse` returns null for email/password), `operationType: 'signIn'`, and a `User` with the stored uid + email","status":"conforms","evidence":["`unit:sandbox-email-password.test.ts` + oracle: `packages/conformance/observations/auth/auth-createUser-operationType.json` (`providerId: null` against blockingfun, fb-js-sdk 12.13.0). Prior matrix language said `providerId: 'password'`; corrected after the oracle contradicted it (AUTH-B2).","observation:auth-createUser-operationType","packages/pyric/test/auth/sandbox-email-password.test.ts"],"assurance":"eligible"},{"id":"auth#14","kind":"registry-row","surface":"auth","behavior":"Throws `auth/user-not-found` when the email isn't seeded / hasn't been created","status":"conforms","evidence":["`unit:sandbox-email-password.test.ts` + oracle: `packages/conformance/observations/auth/auth-user-not-found-error-code.json` (`code: 'auth/user-not-found'` against blockingfun, fb-js-sdk 12.13.0; matches sandbox)","observation:auth-user-not-found-error-code","packages/pyric/test/auth/sandbox-email-password.test.ts"],"assurance":"eligible"},{"id":"auth#15","kind":"registry-row","surface":"auth","behavior":"Throws `auth/wrong-password` when the password doesn't match","status":"conforms","evidence":["`unit:sandbox-email-password.test.ts`, `playground:auth-email-password` (bundled) + `playground:auth-row-15-wrong-password-rejects` (one-claim) + oracle: `packages/conformance/observations/auth/auth-wrong-password-error-code.json` (`code: 'auth/wrong-password'` against blockingfun, fb-js-sdk 12.13.0; matches sandbox)","observation:auth-wrong-password-error-code","packages/pyric/test/auth/sandbox-email-password.test.ts"],"assurance":"eligible"},{"id":"auth#15a","kind":"registry-row","surface":"auth","behavior":"An EMPTY password throws `auth/missing-password` (message \"A non-empty password must be provided\"), fired before the user-DB lookup so it can't be used to enumerate seeded emails. Upstream maps the `MISSING_PASSWORD` server error (`core/errors.ts:92,282,563`). ⚠ best-known semantics — message text not yet captured against a live project (STOP-flagged for an oracle pass; the `.code` is the load-bearing part).","status":"diverged-documented","evidence":["`unit:sandbox-cluster-b9-b12.test.ts` (locks AUTH-B11)","packages/pyric/test/auth/sandbox-cluster-b9-b12.test.ts"],"assurance":"qualified"},{"id":"auth#16","kind":"registry-row","surface":"auth","behavior":"Re-signing in after `signOut` returns the **same** uid (passwords persist within the sandbox lifetime)","status":"conforms","evidence":["`playground:auth-email-password` (bundled) + `playground:auth-row-16-resignin-same-uid` (one-claim)"],"assurance":"eligible"},{"id":"auth#17","kind":"registry-row","surface":"auth","behavior":"Fires `onAuthStateChanged` with the new user once","status":"conforms","evidence":["`unit:sandbox-listeners.test.ts` + oracle: `packages/conformance/observations/auth/auth-row-17-signin-email-password-fires-once.json` (against blockingfun, fb-js-sdk 12.13.0: createUser → signOut → subscribe (1 initial null fire) → `signInWithEmailAndPassword` → `firesForSignIn: 1` with the signed-in uid, `lastFireUidMatches: true`)","observation:auth-row-17-signin-email-password-fires-once","packages/pyric/test/auth/sandbox-listeners.test.ts"],"assurance":"eligible"},{"id":"auth#18","kind":"registry-row","surface":"auth","behavior":"Email validation (RFC 5322ish) — rejects empty, missing `@`, missing local-part, missing domain with `auth/invalid-email`. Runs on both `signInWithEmailAndPassword` and `createUserWithEmailAndPassword` before any user-DB lookup, so consumers shipping malformed input see the same error sandbox vs prod.","status":"conforms","evidence":["`unit:sandbox-email-password.test.ts` + oracle: `packages/conformance/observations/auth/auth-row-18-invalid-email-error-code.json` (`code: 'auth/invalid-email'`, message `Firebase: Error (auth/invalid-email).` against blockingfun, fb-js-sdk 12.13.0)","observation:auth-row-18-invalid-email-error-code","packages/pyric/test/auth/sandbox-email-password.test.ts"],"assurance":"eligible"},{"id":"auth#19","kind":"registry-row","surface":"auth","behavior":"Password strength requirements — rejects passwords shorter than 6 chars with `auth/weak-password` on `createUserWithEmailAndPassword`. Strength is NOT enforced on `signInWithEmailAndPassword` so previously-seeded weak passwords still let the user in (matches prod's separation of registration vs sign-in).","status":"conforms","evidence":["`unit:sandbox-email-password.test.ts` + oracle: `packages/conformance/observations/auth/auth-row-19-weak-password-error-code.json` (`code: 'auth/weak-password'`, message `Firebase: Password should be at least 6 characters (auth/weak-password).` against blockingfun, fb-js-sdk 12.13.0; matrix language \"≥6 chars per prod default\" empirically confirmed)","observation:auth-row-19-weak-password-error-code","packages/pyric/test/auth/sandbox-email-password.test.ts"],"assurance":"eligible"},{"id":"auth#69","kind":"registry-row","surface":"auth","behavior":"Disabled accounts (`sandbox.updateUser(…, {disabled: true})`) reject sign-in with `auth/user-disabled` and prod's documented message (`The user account has been disabled by an administrator.`). Sandbox checks disabled BEFORE the password compare (anti-probing); the exact prod ordering of disabled-vs-wrong-password needs an oracle capture","status":"conforms","evidence":["`unit:sandbox-user-admin.test.ts` (\"disabled users\")","packages/pyric/test/auth/sandbox-user-admin.test.ts"],"assurance":"eligible"}]},{"feature":"signInWithEmailLink","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"signInWithEmailLink is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:signInWithEmailLink","kind":"runtime-export","surface":"auth","behavior":"signInWithEmailLink is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#154","kind":"registry-row","surface":"auth","behavior":"Redeems the code in a sign-in link. A link carrying no `oobCode` throws `auth/argument-error` CLIENT-side (the SDK never reaches the server to ask about a code it cannot find in the link). A first-time sign-in for an address CREATES the account, `getAdditionalUserInfo(cred).isNewUser` is `true`, and the account arrives `emailVerified: true` — redeeming a code mailed to that address is proof of control. The code is single-use.","status":"conforms","evidence":["ORACLE-BACKED on the client-side reject (`auth-signinwithemaillink-invalid-link`: `noOobCode: auth/argument-error`). The REDEMPTION path could not be probed: the oracle project has email-link sign-in disabled, so the server arm answered `auth/operation-not-allowed`. That half is unit-backed end to end against the sandbox outbox (`unit:sandbox-email-link.test.ts` drives send -> read the outbox -> sign in).","observation:auth-signinwithemaillink-invalid-link","packages/pyric/test/auth/oracle-conformance.test.ts","packages/pyric/test/auth/sandbox-email-link.test.ts"],"assurance":"eligible"}]},{"feature":"signInWithPhoneNumber","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"signInWithPhoneNumber is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["MFA / phone / reCAPTCHA is deferred, not out of scope — reCAPTCHA/SMS are external infrastructure Pyric can mock with the OAuth resolver pattern, and TOTP is pure algorithm work."],"claims":[{"id":"auth:runtime:signInWithPhoneNumber","kind":"runtime-export","surface":"auth","behavior":"MFA / phone / reCAPTCHA is deferred, not out of scope — reCAPTCHA/SMS are external infrastructure Pyric can mock with the OAuth resolver pattern, and TOTP is pure algorithm work.","status":"deferred","evidence":["registry:auth#180"],"assurance":"not-applicable"}]},{"feature":"signInWithPopup","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"signInWithPopup is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["Opens a popup window in prod","divergence: sandbox skips the popup; mock pre-stage replaces the popup result","Cancels with `auth/popup-closed-by-user` when the user dismisses the popup (prod)","not modeled — would require the host to expose a \"cancel\" affordance on the mock"],"claims":[{"id":"auth:runtime:signInWithPopup","kind":"runtime-export","surface":"auth","behavior":"signInWithPopup is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#44","kind":"registry-row","surface":"auth","behavior":"Returns the pre-staged `UserCredential` registered via `sandbox.mockSignInResult(auth, …)`","status":"conforms","evidence":["`unit:sandbox-providers.test.ts`","packages/pyric/test/auth/sandbox-providers.test.ts"],"assurance":"eligible"},{"id":"auth#45","kind":"registry-row","surface":"auth","behavior":"Throws `auth/no-mock-configured` when no mock is pre-staged","status":"conforms","evidence":["`unit:sandbox-providers.test.ts`","packages/pyric/test/auth/sandbox-providers.test.ts"],"assurance":"eligible"},{"id":"auth#46","kind":"registry-row","surface":"auth","behavior":"Mock is consumed after one read (subsequent call without a fresh stage throws again)","status":"conforms","evidence":["`unit:sandbox-providers.test.ts`","packages/pyric/test/auth/sandbox-providers.test.ts"],"assurance":"eligible"},{"id":"auth#47","kind":"registry-row","surface":"auth","behavior":"After successful sign-in, `currentUser` becomes the mock's `user`, listeners fire","status":"conforms","evidence":["`unit:sandbox-providers.test.ts`","packages/pyric/test/auth/sandbox-providers.test.ts"],"assurance":"eligible"},{"id":"auth#47a","kind":"registry-row","surface":"auth","behavior":"The credential's rich `User` (email / displayName / isAnonymous) survives the transition — popup/redirect/credential/`setUser` do NOT clobber it down to the bare `AuthState`; `cred.user === auth.currentUser` (reference identity, matches upstream `_updateCurrentUser(userCredential.user)`)","status":"conforms","evidence":["`unit:sandbox-user-identity.test.ts` (locks AUTH-B1)","packages/pyric/test/auth/sandbox-user-identity.test.ts"],"assurance":"eligible"},{"id":"auth#48","kind":"registry-row","surface":"auth","behavior":"Opens a popup window in prod","status":"diverged-documented","evidence":["divergence: sandbox skips the popup; mock pre-stage replaces the popup result"],"assurance":"qualified"},{"id":"auth#49","kind":"registry-row","surface":"auth","behavior":"Cancels with `auth/popup-closed-by-user` when the user dismisses the popup (prod)","status":"unsupported","evidence":["not modeled — would require the host to expose a \"cancel\" affordance on the mock"],"assurance":"ineligible"},{"id":"auth#70","kind":"registry-row","surface":"auth","behavior":"Provider-flow sign-ins (popup / redirect / credential) record the flow's `providerId` on the identity in the user DB (upsert for unknown uids; append-if-missing for known ones) and reject disabled accounts with `auth/user-disabled` before any state change","status":"conforms","evidence":["`unit:sandbox-user-admin.test.ts` (\"provider tracking\", \"disabled users\") — provider recording is sandbox bookkeeping for `listIdentities`/`listUsers`; prod's auto-link semantics are narrower (same-email Google auto-link only) and not modeled","packages/pyric/test/auth/sandbox-user-admin.test.ts"],"assurance":"eligible"}]},{"feature":"signInWithRedirect","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"signInWithRedirect is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:signInWithRedirect","kind":"runtime-export","surface":"auth","behavior":"signInWithRedirect is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#49a","kind":"registry-row","surface":"auth","behavior":"`signInWithRedirect(auth, provider, resolver?)` resolves the flow (per-call resolver → injected → one-shot mock → `auth/argument-error`), signs the user in, and stashes the credential for one `getRedirectResult`","status":"conforms","evidence":["`unit:sandbox-resolver.test.ts`","packages/pyric/test/auth/sandbox-resolver.test.ts"],"assurance":"eligible"},{"id":"auth#49c","kind":"registry-row","surface":"auth","behavior":"`sandbox.setAuthFlowResolver(auth, resolver | null)` installs / clears the popup/redirect resolver (the analog of browser `getAuth` wiring `browserPopupRedirectResolver`)","status":"conforms","evidence":["`unit:sandbox-resolver.test.ts`","packages/pyric/test/auth/sandbox-resolver.test.ts"],"assurance":"eligible"},{"id":"auth#49d","kind":"registry-row","surface":"auth","behavior":"`sandbox.listIdentities(auth)` snapshots every seeded/created identity for a host account-picker (sandbox-only — no `firebase/auth` equivalent)","status":"conforms","evidence":["`unit:sandbox-resolver.test.ts`","packages/pyric/test/auth/sandbox-resolver.test.ts"],"assurance":"eligible"}]},{"feature":"signOut","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"signOut is available, has diverged fidelity, and is qualified for assurance.","caveats":["Clears the active session's persistence in prod; sandbox has no persistence","divergence: same memory-only constraint as the anonymous persistence row"],"claims":[{"id":"auth:runtime:signOut","kind":"runtime-export","surface":"auth","behavior":"signOut is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#25","kind":"registry-row","surface":"auth","behavior":"Sets `currentUser` to `null` synchronously after resolution","status":"conforms","evidence":["`playground:auth-anonymous` (bundled) + `playground:auth-row-25-signout-currentuser-null` (one-claim), `unit:sandbox-anonymous.test.ts` + oracle: `packages/conformance/observations/auth/auth-row-25-signout-currentuser-null-sync.json` (`currentUserIsNullSync: true` against blockingfun, fb-js-sdk 12.13.0 — `auth.currentUser` read in the synchronous continuation immediately after `await signOut(auth)` is already `null`, with no microtask/macrotask required to settle)","observation:auth-row-25-signout-currentuser-null-sync","packages/pyric/test/auth/sandbox-anonymous.test.ts"],"assurance":"eligible"},{"id":"auth#26","kind":"registry-row","surface":"auth","behavior":"Fires `onAuthStateChanged` with `null` exactly once","status":"conforms","evidence":["`unit:sandbox-listeners.test.ts`, `playground:auth-anonymous` (bundled) + `playground:auth-row-26-signout-fires-null-once` (one-claim) + oracle: `packages/conformance/observations/auth/auth-row-26-signout-fires-null-once.json` (against blockingfun, fb-js-sdk 12.13.0: subscribe (1 initial null fire) → `signInAnonymously` → `signOut` → `firesForSignOut: 1` with `lastFireUidWasNull: true`)","observation:auth-row-26-signout-fires-null-once","packages/pyric/test/auth/sandbox-listeners.test.ts"],"assurance":"eligible"},{"id":"auth#27","kind":"registry-row","surface":"auth","behavior":"Idempotent — `signOut` on already-signed-out user is a no-op (no listener fire)","status":"conforms","evidence":["`playground:auth-signout-idempotent` + oracle-confirmed: `packages/conformance/observations/auth/auth-signout-idempotent.json` (`threw: false, redundantSignOutFiredListener: false` against blockingfun)","observation:auth-signout-idempotent"],"assurance":"eligible"},{"id":"auth#28","kind":"registry-row","surface":"auth","behavior":"Clears the active session's persistence in prod; sandbox has no persistence","status":"diverged-documented","evidence":["divergence: same memory-only constraint as the anonymous persistence row"],"assurance":"qualified"}]},{"feature":"simulateRtdbRules","surface":"rtdb","importPaths":["pyric/rules/internal/rtdb"],"evidenceSlug":"database-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"simulateRtdbRules is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["The removed stateful simulator returned a generate-before-simulate error when no IR had been generated","The stateless `simulateRtdbRules(compiled, input)` API requires a compiled rules tree and has no generate-before-simulate lifecycle.","Cross-path `root.child(…).val()` reads return `null` for paths NOT present in `mockData` — divergence from real prod rules where the engine reads the live database","divergence: the simulator uses ONLY what's in `mockData`. Real rules engine reads from the live RTDB. Documented in `validated.ts` (\"simulation uses empty mockData, so cross-path rule lookups … will evaluate as false\")"],"claims":[{"id":"rtdb#59","kind":"registry-row","surface":"rtdb","behavior":"The removed stateful simulator returned a generate-before-simulate error when no IR had been generated","status":"unsupported","evidence":["The stateless `simulateRtdbRules(compiled, input)` API requires a compiled rules tree and has no generate-before-simulate lifecycle."],"assurance":"ineligible"},{"id":"rtdb#60","kind":"registry-row","surface":"rtdb","behavior":"Returns `{ success: false, error: { code: 'INVALID_INPUT' } }` when input doesn't parse against `SimulationInputSchema` (e.g. path missing leading slash, operation not in read / write / validate)","status":"conforms","evidence":["`unit:simulation/handler.test.ts`","packages/pyric/test/rules/rtdb/simulation/handler.test.ts"],"assurance":"eligible"},{"id":"rtdb#61","kind":"registry-row","surface":"rtdb","behavior":"Walks ancestors from root → target; the first ancestor whose rule expression evaluates to `true` grants access — matches RTDB's documented \"rules cascade from root, true at any ancestor grants\" semantics","status":"conforms","evidence":["`unit:simulation/handler.test.ts`","packages/pyric/test/rules/rtdb/simulation/handler.test.ts"],"assurance":"eligible"},{"id":"rtdb#62","kind":"registry-row","surface":"rtdb","behavior":"Path variables (`$userId`) are bound from the URL path and exposed in `pathVariableBindings` (also without the `$` prefix for ergonomic access in expressions)","status":"conforms","evidence":["`unit:simulation/handler.test.ts`","packages/pyric/test/rules/rtdb/simulation/handler.test.ts"],"assurance":"eligible"},{"id":"rtdb#63","kind":"registry-row","surface":"rtdb","behavior":"`auth` context: when `null`, `auth` is null inside expressions; when present, `auth.uid` and `auth.token.*` are bound","status":"conforms","evidence":["`unit:simulation/handler.test.ts`, `unit:grammar/simulator.test.ts`","packages/pyric/test/rules/rtdb/grammar/simulator.test.ts","packages/pyric/test/rules/rtdb/simulation/handler.test.ts"],"assurance":"eligible"},{"id":"rtdb#64","kind":"registry-row","surface":"rtdb","behavior":"`mockData` becomes the value of `data` at every path during evaluation; `newData` is the proposed value for write/validate","status":"conforms","evidence":["`unit:simulation/handler.test.ts`","packages/pyric/test/rules/rtdb/simulation/handler.test.ts"],"assurance":"eligible"},{"id":"rtdb#65","kind":"registry-row","surface":"rtdb","behavior":"`data.child(\"…\")`, `data.parent()`, `data.exists()`, `data.val()` evaluate against the in-process snapshot — matches the documented `DataSnapshot` rule-context surface","status":"conforms","evidence":["`unit:grammar/simulator.test.ts`","packages/pyric/test/rules/rtdb/grammar/simulator.test.ts"],"assurance":"eligible"},{"id":"rtdb#66","kind":"registry-row","surface":"rtdb","behavior":"Cross-path `root.child(…).val()` reads return `null` for paths NOT present in `mockData` — divergence from real prod rules where the engine reads the live database","status":"diverged-documented","evidence":["divergence: the simulator uses ONLY what's in `mockData`. Real rules engine reads from the live RTDB. Documented in `validated.ts` (\"simulation uses empty mockData, so cross-path rule lookups … will evaluate as false\")"],"assurance":"qualified"},{"id":"rtdb#67","kind":"registry-row","surface":"rtdb","behavior":"An expression that fails to parse (`parsed.valid === false`) produces an unsupported result rather than silently granting or fabricating a deny","status":"conforms","evidence":["`unit:simulation/handler.test.ts`","packages/pyric/test/rules/rtdb/simulation/handler.test.ts"],"assurance":"eligible"},{"id":"rtdb#68","kind":"registry-row","surface":"rtdb","behavior":"When no ancestor rule allows, the result is `{ allowed: false }` with `matchedPath` set to the deepest matched node","status":"conforms","evidence":["`unit:simulation/handler.test.ts`","packages/pyric/test/rules/rtdb/simulation/handler.test.ts"],"assurance":"eligible"},{"id":"rtdb#69","kind":"registry-row","surface":"rtdb","behavior":"When NO ancestor has a rule for the operation at all, returns `{ success: false, error: { code: 'NO_MATCHING_RULE' } }`","status":"conforms","evidence":["`unit:simulation/handler.test.ts`","packages/pyric/test/rules/rtdb/simulation/handler.test.ts"],"assurance":"eligible"},{"id":"rtdb#70","kind":"registry-row","surface":"rtdb","behavior":"Evaluation errors (grammar mismatch, unknown identifier) surface as `EVALUATION_ERROR`","status":"conforms","evidence":["`unit:simulation/handler.test.ts`","packages/pyric/test/rules/rtdb/simulation/handler.test.ts"],"assurance":"eligible"},{"id":"rtdb#71","kind":"registry-row","surface":"rtdb","behavior":"Simulator's allow/deny decision matches the real RTDB rules engine for the same `{ rules, mockData, auth, operation, path, newData }` tuple, modulo the documented cross-path divergence on row #66","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb/rtdb-simulator-vs-prod-agreement.json` — 8 test rules × 29 (rule, op) tuples; 28 agreements, 1 disagreement at capture time (`r4-validate-structure`: the simulator did not evaluate `.validate` on writes). The `.validate` walk is now implemented (`src/rules/rtdb/simulation/handler.ts`, reached from all backend write sites; grammar array-literals + `hasChildren(keys)` fixed alongside), closing the recorded disagreement — replayed as prod-conforming denial in `oracle-conformance.test.ts`. The frozen capture documents the historical divergence","observation:rtdb-simulator-vs-prod-agreement"],"assurance":"eligible"}]},{"feature":"SingleRequestOptions","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"SingleRequestOptions is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:SingleRequestOptions","kind":"type-export","surface":"ai","behavior":"SingleRequestOptions is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"size","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"size is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"storage-rules#122","kind":"registry-row","surface":"storage-rules","behavior":"List/map literals, range-slice access `[i:j]` on lists and strings (out-of-range bounds ERROR, no JS clamp), and structural `==` on lists","status":"conforms","evidence":["NEW ROW, 2026-07-17: production capture proves slices evaluate on `split()` lists and on strings, that an out-of-range slice END errors and denies (production does NOT clamp to length the way JS `.slice()` does — same semantics the Firestore capture pinned in rules-firestore-range-slice-list-and-string), and that a slice compares equal to a list literal structurally. `oracle:rules-storage-list-map-literals-and-slice` matches production verdict-for-verdict on all 6 cases. Pre-fix the evaluator clamped bounds JS-style and compared lists by reference identity; both fixed and pinned by `unit:rules.test.ts` JS-semantics guards.","observation:rules-storage-list-map-literals-and-slice","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.method.size","kind":"rules-construct","surface":"storage-rules","behavior":"size is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"SlidingWindow","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"SlidingWindow is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:SlidingWindow","kind":"type-export","surface":"ai","behavior":"SlidingWindow is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"snapshot.child","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"snapshot.child is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.method.snapshot.child","kind":"rules-construct","surface":"rtdb-rules","behavior":"snapshot.child is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/rulesdatasnapshot#child"],"assurance":"qualified"}]},{"feature":"snapshot.exists","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"snapshot.exists is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.method.snapshot.exists","kind":"rules-construct","surface":"rtdb-rules","behavior":"snapshot.exists is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/rulesdatasnapshot#exists"],"assurance":"qualified"}]},{"feature":"snapshot.getPriority","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"snapshot.getPriority is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.method.snapshot.getPriority","kind":"rules-construct","surface":"rtdb-rules","behavior":"snapshot.getPriority is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/rulesdatasnapshot#getPriority"],"assurance":"qualified"}]},{"feature":"snapshot.hasChild","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"snapshot.hasChild is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.method.snapshot.hasChild","kind":"rules-construct","surface":"rtdb-rules","behavior":"snapshot.hasChild is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/rulesdatasnapshot#hasChild"],"assurance":"qualified"}]},{"feature":"snapshot.hasChildren","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"snapshot.hasChildren is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.method.snapshot.hasChildren","kind":"rules-construct","surface":"rtdb-rules","behavior":"snapshot.hasChildren is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/rulesdatasnapshot#hasChildren"],"assurance":"qualified"}]},{"feature":"snapshot.isBoolean","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"snapshot.isBoolean is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.method.snapshot.isBoolean","kind":"rules-construct","surface":"rtdb-rules","behavior":"snapshot.isBoolean is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/rulesdatasnapshot#isBoolean"],"assurance":"qualified"}]},{"feature":"snapshot.isNumber","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"snapshot.isNumber is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.method.snapshot.isNumber","kind":"rules-construct","surface":"rtdb-rules","behavior":"snapshot.isNumber is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/rulesdatasnapshot#isNumber"],"assurance":"qualified"}]},{"feature":"snapshot.isString","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"snapshot.isString is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.method.snapshot.isString","kind":"rules-construct","surface":"rtdb-rules","behavior":"snapshot.isString is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/rulesdatasnapshot#isString"],"assurance":"qualified"}]},{"feature":"snapshot.parent","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"snapshot.parent is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.method.snapshot.parent","kind":"rules-construct","surface":"rtdb-rules","behavior":"snapshot.parent is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/rulesdatasnapshot#parent"],"assurance":"qualified"}]},{"feature":"snapshot.val","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"snapshot.val is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.method.snapshot.val","kind":"rules-construct","surface":"rtdb-rules","behavior":"snapshot.val is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/rulesdatasnapshot#val"],"assurance":"qualified"}]},{"feature":"snapshotEqual","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"snapshotEqual is available, has diverged fidelity, and is qualified for assurance.","caveats":["`snapshotEqual(a, b)`. Prod: returns a boolean — true on identity, false even for two fetches of the same data. Sandbox: **throws** (`unrecognized reference`) for sandbox-target snapshots instead of returning a boolean","divergence, oracle-locked by `packages/conformance/observations/firestore/firestore-snapshotequal-structural.json` (`identity: true`, `twoFetchesSameData: false` — prod is identity-only, NOT structural; an earlier structural guess was corrected by the oracle). The sandbox routes both args through the ref-tagging path, which does not recognize sandbox `QuerySnapshot`s, so `snapshotEqual` throws rather than comparing. Both sides pinned in `oracle-conformance.test.ts`. Fix candidate: identity-compare sandbox snapshots before the ref-tagging dispatch."],"claims":[{"id":"firestore:runtime:snapshotEqual","kind":"runtime-export","surface":"firestore","behavior":"snapshotEqual is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#117","kind":"registry-row","surface":"firestore","behavior":"`snapshotEqual(a, b)`. Prod: returns a boolean — true on identity, false even for two fetches of the same data. Sandbox: **throws** (`unrecognized reference`) for sandbox-target snapshots instead of returning a boolean","status":"diverged-documented","evidence":["divergence, oracle-locked by `packages/conformance/observations/firestore/firestore-snapshotequal-structural.json` (`identity: true`, `twoFetchesSameData: false` — prod is identity-only, NOT structural; an earlier structural guess was corrected by the oracle). The sandbox routes both args through the ref-tagging path, which does not recognize sandbox `QuerySnapshot`s, so `snapshotEqual` throws rather than comparing. Both sides pinned in `oracle-conformance.test.ts`. Fix candidate: identity-compare sandbox snapshots before the ref-tagging dispatch.","observation:firestore-snapshotequal-structural","packages/pyric/test/firestore/oracle-conformance.test.ts"],"assurance":"qualified"}]},{"feature":"SnapshotListenOptions","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"SnapshotListenOptions is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"firestore:type:SnapshotListenOptions","kind":"type-export","surface":"firestore","behavior":"SnapshotListenOptions is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"SnapshotMetadata","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"SnapshotMetadata is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","Public type export is not mirrored."],"claims":[{"id":"firestore:runtime:SnapshotMetadata","kind":"runtime-export","surface":"firestore","behavior":"These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"},{"id":"firestore:type:SnapshotMetadata","kind":"type-export","surface":"firestore","behavior":"SnapshotMetadata is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"SnapshotOptions","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"SnapshotOptions is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:SnapshotOptions","kind":"type-export","surface":"firestore","behavior":"SnapshotOptions is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"snapshotState","surface":"rtdb","importPaths":[],"evidenceSlug":"database-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"snapshotState is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"rtdb-modular#M35","kind":"registry-row","surface":"rtdb-modular","behavior":"`sandbox.snapshotState(db)` dumps the full tree as a plain JSON object","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"sandbox.snapshotState dumps the full tree\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"SpeechConfig","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"SpeechConfig is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:SpeechConfig","kind":"type-export","surface":"ai","behavior":"SpeechConfig is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"startAfter","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"startAfter is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:startAfter","kind":"runtime-export","surface":"firestore","behavior":"startAfter is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#68","kind":"registry-row","surface":"firestore","behavior":"`startAfter(...values)` — exclusive value cursor","status":"conforms","evidence":["`unit:sandbox-target.test.ts`, oracle: `packages/conformance/observations/firestore/firestore-cursor-startafter-exclusive.json` (5 seeded docs at pos=[1..5]; `query(c, orderBy('pos'), startAfter(3))` returned exactly `[pos-4, pos-5]` — the cursor doc is EXCLUDED)","observation:firestore-cursor-startafter-exclusive","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#73","kind":"registry-row","surface":"firestore","behavior":"`startAfter + limit` — canonical pagination pattern","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"startAfter","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"startAfter is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"database:runtime:startAfter","kind":"runtime-export","surface":"database","behavior":"startAfter is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#148","kind":"registry-row","surface":"rtdb-modular","behavior":"`startAfter(v)` is **exclusive**","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-startafter-endbefore-exclusive.json` — `startAfter(2) + endBefore(5)` matched positions `[3,4]` (cursor `2` dropped).","observation:rtdb-modular-startafter-endbefore-exclusive"],"assurance":"eligible"},{"id":"rtdb-modular#M57","kind":"registry-row","surface":"rtdb-modular","behavior":"`startAfter(v)` and `endBefore(v)` are EXCLUSIVE — the boundary value is dropped from the result","status":"conforms","evidence":["Sandbox aligned: `unit:modular/queries.test.ts` (\"startAfter + endBefore drop the boundary values\"); matches oracle observation `packages/conformance/observations/rtdb-modular/rtdb-modular-startafter-endbefore-exclusive.json` (positions `[3,4]`, cursors 2 + 5 dropped).","observation:rtdb-modular-startafter-endbefore-exclusive","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M69","kind":"registry-row","surface":"rtdb-modular","behavior":"Conflicting query constraints throw synchronously at `query(...)` construction (NOT silent last-win): multiple `orderBy*`, a second `limitToFirst`/`limitToLast`, a second start (`startAt`/`startAfter`/`equalTo`) or end (`endAt`/`endBefore`/`equalTo`) (DB-B5)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/constraint-conflicts.test.ts` (5 cases); upstream `api/Reference_impl.ts:160-165,1824-1841,1888-1905,1945-1951,2193-2206`","packages/pyric/test/database/modular/constraint-conflicts.test.ts"],"assurance":"eligible"}]},{"feature":"startAt","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"startAt is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:startAt","kind":"runtime-export","surface":"firestore","behavior":"startAt is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#67","kind":"registry-row","surface":"firestore","behavior":"`startAt(...values)` — inclusive value cursor (one positional per `orderBy` clause)","status":"conforms","evidence":["`unit:sandbox-target.test.ts`, oracle: `packages/conformance/observations/firestore/firestore-cursor-startat-inclusive.json` (5 seeded docs at pos=[1..5]; `query(c, orderBy('pos'), startAt(3))` returned exactly `[pos-3, pos-4, pos-5]` — the cursor doc IS included)","observation:firestore-cursor-startat-inclusive","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#71","kind":"registry-row","surface":"firestore","behavior":"`startAt(snapshot)` overload — extracts orderBy field values from the snapshot, positioning against the NORMALIZED orderBy (implicit `__name__`), so it disambiguates equal-valued docs and is **legal without an explicit orderBy** (FS-B8). A VALUE cursor with more values than explicit orderBy clauses throws `invalid-argument` (\"Too many arguments\").","status":"conforms","evidence":["`unit:sandbox-target.test.ts`, `unit:admin-compat/implicit-order-name.test.ts` (snapshot cursor w/o orderBy), `unit:admin-compat/cursors.test.ts` (value-cursor too-many-args throws with `.code`)","observation:firestore-startat-snapshot-implicit-name","packages/pyric/test/firestore/sandbox-target.test.ts","packages/pyric/test/sandbox/firestore/admin-compat/cursors.test.ts","packages/pyric/test/sandbox/firestore/admin-compat/implicit-order-name.test.ts"],"assurance":"eligible"}]},{"feature":"startAt","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"startAt is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"database:runtime:startAt","kind":"runtime-export","surface":"database","behavior":"startAt is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#146","kind":"registry-row","surface":"rtdb-modular","behavior":"`startAt(v)` is **inclusive** (the child whose ordered value === v is included)","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-query-startat-inclusive.json` — seeded positions `[1,2,3,4]`, observed `matched: [2,3,4]` for `startAt(2)` (cursor doc included).","observation:rtdb-modular-orderbychild-window","observation:rtdb-modular-orderbykey-window","observation:rtdb-modular-query-startat-inclusive"],"assurance":"eligible"},{"id":"rtdb-modular#M49","kind":"registry-row","surface":"rtdb-modular","behavior":"`query(ref, orderByChild(p), startAt(v), endAt(w))` window is BOTH-INCLUSIVE — children whose ordered field === `v` or === `w` are included","status":"conforms","evidence":["`unit:upstream-rtdb-probes.test.ts` (deep orderByChild nested path) + `unit:modular/queries.test.ts` (\"returns children whose ordered child is within [startAt, endAt] inclusive\"); matches oracle `rtdb-modular-orderbychild-window.json`","observation:rtdb-modular-orderbychild-window","packages/pyric/test/database/upstream-rtdb-probes.test.ts","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M50","kind":"registry-row","surface":"rtdb-modular","behavior":"`orderByKey()` orders children by RTDB `nameCompare` — integer-looking keys sort numerically FIRST (so `['1','2','10']`, not the lexicographic `['1','10','2']`), then non-integer keys lexicographically; `startAt`/`endAt` cursors + the optional `key` tie-breaker use the same order (DB-B4)","status":"conforms","evidence":["`unit:upstream-rtdb-probes.test.ts` (INT32 overflow/underflow cursors) + `unit:modular/queries.test.ts` + `unit:modular/name-compare.test.ts`; matches oracle `rtdb-modular-orderbykey-window.json` and upstream `core/util/util.ts:253-276`","packages/pyric/test/database/upstream-rtdb-probes.test.ts","packages/pyric/test/database/modular/name-compare.test.ts","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M62","kind":"registry-row","surface":"rtdb-modular","behavior":"`startAt(value, key)` uses `key` as the tie-breaker when multiple children share the same ordered value — children before `key` are dropped, the row at `key` is included (inclusive cursor)","status":"conforms","evidence":["`unit:modular/queries.test.ts` (\"startAt with key tie-breaker drops earlier same-value children\")","packages/pyric/test/database/modular/queries.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M69","kind":"registry-row","surface":"rtdb-modular","behavior":"Conflicting query constraints throw synchronously at `query(...)` construction (NOT silent last-win): multiple `orderBy*`, a second `limitToFirst`/`limitToLast`, a second start (`startAt`/`startAfter`/`equalTo`) or end (`endAt`/`endBefore`/`equalTo`) (DB-B5)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/constraint-conflicts.test.ts` (5 cases); upstream `api/Reference_impl.ts:160-165,1824-1841,1888-1905,1945-1951,2193-2206`","packages/pyric/test/database/modular/constraint-conflicts.test.ts"],"assurance":"eligible"}]},{"feature":"startAudioConversation","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"startAudioConversation is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Deferred with the rest of the Live API family — the browser audio helper rides the Live session seam once that lands."],"claims":[{"id":"ai:runtime:startAudioConversation","kind":"runtime-export","surface":"ai","behavior":"Deferred with the rest of the Live API family — the browser audio helper rides the Live session seam once that lands.","status":"deferred","evidence":["disposition:ai.live-api"],"assurance":"not-applicable"}]},{"feature":"StartAudioConversationOptions","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"StartAudioConversationOptions is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:StartAudioConversationOptions","kind":"type-export","surface":"ai","behavior":"StartAudioConversationOptions is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"startChat","surface":"ai","importPaths":[],"evidenceSlug":"ai-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"startChat is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"ai#chat-startchat","kind":"registry-row","surface":"ai","behavior":"`startChat` returns a `ChatSession` seeded with `StartChatParams.history`","status":"conforms","evidence":["`unit:upstream-ai-probes.test.ts` (I1 validateChatHistory accept/reject via startChat) + `unit:chat-session.test.ts` test `ai#chat-startchat`","packages/pyric/test/ai/upstream-ai-probes.test.ts","packages/pyric/test/ai/chat-session.test.ts"],"assurance":"eligible"}]},{"feature":"StartChatParams","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"StartChatParams is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:StartChatParams","kind":"type-export","surface":"ai","behavior":"StartChatParams is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"StartTemplateChatParams","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"StartTemplateChatParams is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:StartTemplateChatParams","kind":"type-export","surface":"ai","behavior":"StartTemplateChatParams is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"StorageError","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"StorageError is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"storage:runtime:StorageError","kind":"runtime-export","surface":"storage","behavior":"StorageError is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"storage:type:StorageError","kind":"type-export","surface":"storage","behavior":"StorageError is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"StorageErrorCode","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"StorageErrorCode is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["StorageErrorCode and StringFormat are mirrored as TypeScript types but not as Firebase-compatible runtime enum objects, so value imports remain unavailable."],"claims":[{"id":"storage:runtime:StorageErrorCode","kind":"runtime-export","surface":"storage","behavior":"StorageErrorCode and StringFormat are mirrored as TypeScript types but not as Firebase-compatible runtime enum objects, so value imports remain unavailable.","status":"deferred","evidence":["upstream:firebase/storage"],"assurance":"not-applicable"},{"id":"storage:type:StorageErrorCode","kind":"type-export","surface":"storage","behavior":"StorageErrorCode is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"StorageObserver","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"StorageObserver is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"storage:type:StorageObserver","kind":"type-export","surface":"storage","behavior":"StorageObserver is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"StorageReference","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"StorageReference is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"storage:type:StorageReference","kind":"type-export","surface":"storage","behavior":"StorageReference is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"String","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"String is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#179","kind":"registry-row","surface":"firestore-rules","behavior":"`String.split()/lower()/upper()/trim()/replace()/size()`, `List.hasAll()/hasAny()/hasOnly()/join()`, and `Map.values()` in rules","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 4 cases (CSV-split membership, slug/title/code normalization). `oracle:rules-firestore-list-and-string-methods` — replayed by `unit:rules/oracle-conformance.test.ts`.","observation:rules-firestore-list-and-string-methods","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"string","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"string is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#180","kind":"registry-row","surface":"firestore-rules","behavior":"`request.time` Timestamp accessors (year/month/day/hours/minutes/seconds/nanos/dayOfWeek/dayOfYear/toMillis/date/time), `math.floor/round/sqrt/pow/isNaN`, `int()/float()/string()` casts, `request.method`, and `>=` / `*` operators in rules","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 3 cases (request.time pinned via requestTime for determinism). `oracle:rules-firestore-time-math-and-casts` — replayed by `unit:rules/oracle-conformance.test.ts`.","observation:rules-firestore-time-math-and-casts","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"String","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"String is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"rtdb-rules#11","kind":"registry-row","surface":"rtdb-rules","behavior":"String methods on a snapshot value — `beginsWith`, `contains`, `endsWith`, `matches` with a regex literal, `.length`, `toLowerCase`, `toUpperCase`, and replace-ALL `replace`","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves `String.replace` substitutes EVERY occurrence of the substring, not only the first — production ALLOWS the write whose rule is `newData.val().replace('_', '-') === 'a-b-c'` for the value `a_b_c`, which holds only under replace-all. The simulator delegated to JavaScript's `String.prototype.replace`, which given a string pattern substitutes only the first occurrence, and DENIED that write; the substitution now replaces every occurrence and the two-underscore case guards the regression. The same capture proves `toUpperCase` is a valid production rule method that the simulator's validator previously rejected outright as unknown. `oracle:rules-rtdb-r11-string-validation` matches production verdict-for-verdict on all 18 cases.","observation:rules-rtdb-r11-string-validation","packages/pyric/test/rules/rtdb/rules-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"string.beginsWith","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"string.beginsWith is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.method.string.beginsWith","kind":"rules-construct","surface":"rtdb-rules","behavior":"string.beginsWith is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/string#beginsWith"],"assurance":"qualified"}]},{"feature":"string.contains","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"string.contains is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.method.string.contains","kind":"rules-construct","surface":"rtdb-rules","behavior":"string.contains is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/string#contains"],"assurance":"qualified"}]},{"feature":"string.endsWith","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"string.endsWith is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.method.string.endsWith","kind":"rules-construct","surface":"rtdb-rules","behavior":"string.endsWith is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/string#endsWith"],"assurance":"qualified"}]},{"feature":"string.length","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"string.length is available, has unverified fidelity, and is qualified for assurance.","caveats":["Discrepancy: length is a String PROPERTY in the official language (`ref.val().length`, accessed as member, no call), but the validator lists it inside STRING_METHODS alongside the callable methods (rules/rtdb/grammar/validator.ts)."],"claims":[{"id":"rtdb.method.string.length","kind":"rules-construct","surface":"rtdb-rules","behavior":"Discrepancy: length is a String PROPERTY in the official language (`ref.val().length`, accessed as member, no call), but the validator lists it inside STRING_METHODS alongside the callable methods (rules/rtdb/grammar/validator.ts).","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/string#length"],"assurance":"qualified"}]},{"feature":"string.lower","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"string.lower is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.string.lower","kind":"rules-construct","surface":"firestore-rules","behavior":"string.lower is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.String#function_lower_"],"assurance":"eligible"}]},{"feature":"string.matches","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"string.matches is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.string.matches","kind":"rules-construct","surface":"firestore-rules","behavior":"string.matches is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.String#function_matches_"],"assurance":"eligible"}]},{"feature":"string.matches","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"string.matches is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.method.string.matches","kind":"rules-construct","surface":"rtdb-rules","behavior":"string.matches is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/string#matches"],"assurance":"qualified"}]},{"feature":"string.matches","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"string.matches is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage.method.string.matches","kind":"rules-construct","surface":"storage-rules","behavior":"string.matches is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/security/storage/string#matches"],"assurance":"eligible"}]},{"feature":"string.replace","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"string.replace is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.string.replace","kind":"rules-construct","surface":"firestore-rules","behavior":"string.replace is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.String#function_replace_"],"assurance":"eligible"}]},{"feature":"string.replace","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"string.replace is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.method.string.replace","kind":"rules-construct","surface":"rtdb-rules","behavior":"string.replace is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/string#replace"],"assurance":"qualified"}]},{"feature":"string.size","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"string.size is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.string.size","kind":"rules-construct","surface":"firestore-rules","behavior":"string.size is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.String#function_size_"],"assurance":"eligible"}]},{"feature":"string.split","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"string.split is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.string.split","kind":"rules-construct","surface":"firestore-rules","behavior":"string.split is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.String#function_split_"],"assurance":"eligible"}]},{"feature":"string.split","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"string.split is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"storage-rules#122","kind":"registry-row","surface":"storage-rules","behavior":"List/map literals, range-slice access `[i:j]` on lists and strings (out-of-range bounds ERROR, no JS clamp), and structural `==` on lists","status":"conforms","evidence":["NEW ROW, 2026-07-17: production capture proves slices evaluate on `split()` lists and on strings, that an out-of-range slice END errors and denies (production does NOT clamp to length the way JS `.slice()` does — same semantics the Firestore capture pinned in rules-firestore-range-slice-list-and-string), and that a slice compares equal to a list literal structurally. `oracle:rules-storage-list-map-literals-and-slice` matches production verdict-for-verdict on all 6 cases. Pre-fix the evaluator clamped bounds JS-style and compared lists by reference identity; both fixed and pinned by `unit:rules.test.ts` JS-semantics guards.","observation:rules-storage-list-map-literals-and-slice","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.method.string.split","kind":"rules-construct","surface":"storage-rules","behavior":"string.split is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/storage/security/rules-conditions"],"assurance":"qualified"}]},{"feature":"string.toLowerCase","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"string.toLowerCase is available, has unverified fidelity, and is qualified for assurance.","caveats":[],"claims":[{"id":"rtdb.method.string.toLowerCase","kind":"rules-construct","surface":"rtdb-rules","behavior":"string.toLowerCase is enumerated in the rtdb rules-language inventory","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/string#toLowerCase"],"assurance":"qualified"}]},{"feature":"string.toUpperCase","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"string.toUpperCase is available, has unverified fidelity, and is qualified for assurance.","caveats":["Discrepancy: toUpperCase() is in the official RTDB String method set, but the parser validator's ALL_KNOWN_METHODS (rules/rtdb/grammar/validator.ts) lists toLowerCase without toUpperCase — the parser would reject it as UNKNOWN_METHOD."],"claims":[{"id":"rtdb.method.string.toUpperCase","kind":"rules-construct","surface":"rtdb-rules","behavior":"Discrepancy: toUpperCase() is in the official RTDB String method set, but the parser validator's ALL_KNOWN_METHODS (rules/rtdb/grammar/validator.ts) lists toLowerCase without toUpperCase — the parser would reject it as UNKNOWN_METHOD.","status":"unprobed","evidence":["https://firebase.google.com/docs/reference/security/database/string#toUpperCase"],"assurance":"qualified"}]},{"feature":"string.toUtf8","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"string.toUtf8 is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["`Bytes`, `String.toUtf8()`, and `hashing.{md5,sha256,crc32,crc32c}()` (Item 5.3) in rules","`oracle:rules-firestore-bytes-toutf8-and-hashing` — production Firestore Rules Test API verdicts for corpus scenario \"bytes-toutf8-and-hashing\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator's toUtf8/md5/sha256/crc32/crc32c byte-encoding and reference-hash implementations diverge from production on all 5 scenario cases, so a rule that should DENY on hash mismatch ALLOWs locally — pinned KNOWN_DIVERGENCE"],"claims":[{"id":"firestore-rules#161","kind":"registry-row","surface":"firestore-rules","behavior":"`Bytes`, `String.toUtf8()`, and `hashing.{md5,sha256,crc32,crc32c}()` (Item 5.3) in rules","status":"diverged-documented","evidence":["`oracle:rules-firestore-bytes-toutf8-and-hashing` — production Firestore Rules Test API verdicts for corpus scenario \"bytes-toutf8-and-hashing\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`. simulator's toUtf8/md5/sha256/crc32/crc32c byte-encoding and reference-hash implementations diverge from production on all 5 scenario cases, so a rule that should DENY on hash mismatch ALLOWs locally — pinned KNOWN_DIVERGENCE","observation:rules-firestore-bytes-toutf8-and-hashing","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"ineligible"},{"id":"firestore.method.string.toUtf8","kind":"rules-construct","surface":"firestore-rules","behavior":"string.toUtf8 is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.String#function_toUtf8_"],"assurance":"ineligible"}]},{"feature":"string.trim","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"string.trim is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.string.trim","kind":"rules-construct","surface":"firestore-rules","behavior":"string.trim is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.String#function_trim_"],"assurance":"eligible"}]},{"feature":"string.upper","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"string.upper is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.string.upper","kind":"rules-construct","surface":"firestore-rules","behavior":"string.upper is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.String#function_upper_"],"assurance":"eligible"}]},{"feature":"stringEscapes","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"stringEscapes is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#175","kind":"registry-row","surface":"firestore-rules","behavior":"String-literal escape handling feeding `matches()` (Class B) in rules — `\\\\.` is unescaped before RE2 compilation, not forwarded raw to a JS `RegExp`","status":"conforms","evidence":["`oracle:rules-firestore-string-literals-and-regex` — production Firestore Rules Test API verdicts for corpus scenario \"string-literals-and-regex\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`; all cases match production.","observation:rules-firestore-string-literals-and-regex","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"StringFormat","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"StringFormat is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["StorageErrorCode and StringFormat are mirrored as TypeScript types but not as Firebase-compatible runtime enum objects, so value imports remain unavailable."],"claims":[{"id":"storage:runtime:StringFormat","kind":"runtime-export","surface":"storage","behavior":"StorageErrorCode and StringFormat are mirrored as TypeScript types but not as Firebase-compatible runtime enum objects, so value imports remain unavailable.","status":"deferred","evidence":["upstream:firebase/storage"],"assurance":"not-applicable"},{"id":"storage:type:StringFormat","kind":"type-export","surface":"storage","behavior":"StringFormat is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"StringSchema","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"StringSchema is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:StringSchema","kind":"runtime-export","surface":"ai","behavior":"StringSchema is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:StringSchema","kind":"type-export","surface":"ai","behavior":"StringSchema is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"subscribeToTopic","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"subscribeToTopic is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#7","kind":"registry-row","surface":"messaging-admin","behavior":"Subscribes one or many registration tokens to a topic; resolves a `MessagingTopicManagementResponse`.","status":"conforms","evidence":["Upstream typings/JSDoc (firebase-admin 13.10.0 `messaging`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"sum","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"sum is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:sum","kind":"runtime-export","surface":"firestore","behavior":"sum is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#77","kind":"registry-row","surface":"firestore","behavior":"`count()` / `sum(field)` / `average(field)` compose under one spec — `field` may be a dotted nested path","status":"conforms","evidence":["`unit:sandbox-target.test.ts`; nested `sum('metadata.pages')`: `unit:upstream-write-aggregate-probes.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts","packages/pyric/test/firestore/upstream-write-aggregate-probes.test.ts"],"assurance":"eligible"}]},{"feature":"takeAuthMail","surface":"auth","importPaths":[],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"takeAuthMail is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth#158","kind":"registry-row","surface":"auth","behavior":"The sandbox IS the mail server. Every send posts a real message (operation, recipient, single-use code, and the full action link) to an outbox; `sandbox.takeAuthMail` reads it — the program's substitute for a human opening an inbox. The mailed link round-trips through the public `isSignInWithEmailLink` / `parseActionCodeURL` unchanged, and its code is the code the redeemer accepts, so the round trip production cannot complete without a human closes in-process. An installed `AuthMailResolver` is additionally notified per message; a resolver that THROWS does not fail the send that produced it.","status":"conforms","evidence":["`unit:sandbox-email-link.test.ts` — sandbox-only driver (no `firebase/auth` counterpart; this is the seam that makes the family testable at all).","packages/pyric/test/auth/sandbox-email-link.test.ts"],"assurance":"eligible"}]},{"feature":"TaskEvent","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"TaskEvent is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"storage:type:TaskEvent","kind":"type-export","surface":"storage","behavior":"TaskEvent is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"TaskState","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"TaskState is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:TaskState","kind":"type-export","surface":"firestore","behavior":"TaskState is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"TaskState","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"TaskState is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"storage:type:TaskState","kind":"type-export","surface":"storage","behavior":"TaskState is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"TemplateChatSession","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"TemplateChatSession is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:TemplateChatSession","kind":"type-export","surface":"ai","behavior":"TemplateChatSession is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"TemplateFunctionDeclaration","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"TemplateFunctionDeclaration is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:TemplateFunctionDeclaration","kind":"type-export","surface":"ai","behavior":"TemplateFunctionDeclaration is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"TemplateFunctionDeclarationsTool","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"TemplateFunctionDeclarationsTool is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:TemplateFunctionDeclarationsTool","kind":"type-export","surface":"ai","behavior":"TemplateFunctionDeclarationsTool is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"TemplateGenerativeModel","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"TemplateGenerativeModel is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Server-side templates are deferred, not out of scope — hosting template state is exactly the kind of server infrastructure the sandbox exists to model; the template store has not been built yet.","Public type export is not mirrored."],"claims":[{"id":"ai:runtime:TemplateGenerativeModel","kind":"runtime-export","surface":"ai","behavior":"Server-side templates are deferred, not out of scope — hosting template state is exactly the kind of server infrastructure the sandbox exists to model; the template store has not been built yet.","status":"deferred","evidence":["upstream:firebase/ai"],"assurance":"not-applicable"},{"id":"ai:type:TemplateGenerativeModel","kind":"type-export","surface":"ai","behavior":"TemplateGenerativeModel is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"TemplateImagenModel","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"out-of-scope","fidelity":"not-applicable","assurance":"not-applicable","summary":"TemplateImagenModel is out-of-scope; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Template-served Imagen models retire with the rest of Imagen (deprecated upstream, June 2026 shutdown); the template transport does not outlive the model family it serves.","Public type export is not mirrored."],"claims":[{"id":"ai:runtime:TemplateImagenModel","kind":"runtime-export","surface":"ai","behavior":"Template-served Imagen models retire with the rest of Imagen (deprecated upstream, June 2026 shutdown); the template transport does not outlive the model family it serves.","status":"out-of-scope","evidence":["upstream:firebase/ai@2.11.0"],"assurance":"not-applicable"},{"id":"ai:type:TemplateImagenModel","kind":"type-export","surface":"ai","behavior":"TemplateImagenModel is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"TemplateTool","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"TemplateTool is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:TemplateTool","kind":"type-export","surface":"ai","behavior":"TemplateTool is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"TemplateToolConfig","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"TemplateToolConfig is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:TemplateToolConfig","kind":"type-export","surface":"ai","behavior":"TemplateToolConfig is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"terminate","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"terminate is available, has diverged fidelity, and is qualified for assurance.","caveats":["Genuinely tears the sandbox target down by calling `Sandbox.dispose()`, which tears down listener registries on the sandbox's environment (idempotent, doesn't touch data). This differs from the real SDK in scope: `dispose()` operates on the whole `Sandbox`, not a Firestore-only slice, so if `pyric/database`/`pyric/storage` share the same `Sandbox` their listener registries are torn down too","`unit:firestore/terminate.test.ts`"],"claims":[{"id":"firestore:runtime:terminate","kind":"runtime-export","surface":"firestore","behavior":"terminate is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#152","kind":"registry-row","surface":"firestore","behavior":"Genuinely tears the sandbox target down by calling `Sandbox.dispose()`, which tears down listener registries on the sandbox's environment (idempotent, doesn't touch data). This differs from the real SDK in scope: `dispose()` operates on the whole `Sandbox`, not a Firestore-only slice, so if `pyric/database`/`pyric/storage` share the same `Sandbox` their listener registries are torn down too","status":"diverged-documented","evidence":["`unit:firestore/terminate.test.ts`","packages/pyric/test/firestore/terminate.test.ts"],"assurance":"qualified"}]},{"feature":"ternary","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"ternary is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#182","kind":"registry-row","surface":"firestore-rules","behavior":"User-defined `function`/`let`, granular `allow get/list/update/write` verbs, the ternary operator, and a recursive `{document=**}` match in rules","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator matches the production Firestore Rules Test API verdict-for-verdict on all 7 cases (role-gated docs + public recursive subtree). `oracle:rules-firestore-functions-verbs-and-recursive` — replayed by `unit:rules/oracle-conformance.test.ts`.","observation:rules-firestore-functions-verbs-and-recursive","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"ternary","surface":"rtdb-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"ternary is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"rtdb-rules#9","kind":"registry-row","surface":"rtdb-rules","behavior":"Arithmetic and comparison operators in quota rules — `+` `-` `*` `/` `%`, `>` `>=` `<` `<=`, `!==`, loose `==`, `||`, the ternary, and unary minus","status":"conforms","evidence":["NEW ROW, 2026-07-12: production capture proves the simulator evaluates every arithmetic and ordering operator as production does, across increment-only counters, doubling and halving deltas, a parity check, inclusive and exclusive range caps, a negative sentinel, loose equality against zero, a disjunction, and a ternary tier bound. `oracle:rules-rtdb-r9-quota-arithmetic` matches production verdict-for-verdict on all 23 cases.","observation:rules-rtdb-r9-quota-arithmetic","packages/pyric/test/rules/rtdb/rules-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"text","surface":"ai","importPaths":[],"evidenceSlug":"ai-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"text is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"ai#helper-text","kind":"registry-row","surface":"ai","behavior":"`text()` concatenates the text parts of the first candidate","status":"conforms","evidence":["`unit:upstream-ai-probes.test.ts` (I3 text() across mixed parts) + `unit:helpers-schema.test.ts` test `ai#helper-text`","packages/pyric/test/ai/upstream-ai-probes.test.ts","packages/pyric/test/ai/helpers-schema.test.ts"],"assurance":"eligible"},{"id":"ai#helper-text-throws","kind":"registry-row","surface":"ai","behavior":"`text()` throws on bad finish reasons such as `SAFETY` and on a blocked prompt","status":"conforms","evidence":["`unit:helpers-schema.test.ts` test `ai#helper-text-throws` (exercised with a scripted SAFETY envelope)","packages/pyric/test/ai/helpers-schema.test.ts"],"assurance":"eligible"},{"id":"ai#helper-tolerates-missing-decor","kind":"registry-row","surface":"ai","behavior":"Helpers tolerate omitted decoration: an envelope without `usageMetadata`, `finishReason`, or `safetyRatings` still serves `text()` without throwing","status":"conforms","evidence":["`unit:helpers-schema.test.ts` test `ai#helper-tolerates-missing-decor` (exercised with a scripted bare envelope)","packages/pyric/test/ai/helpers-schema.test.ts"],"assurance":"eligible"}]},{"feature":"TextPart","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"TextPart is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:TextPart","kind":"type-export","surface":"ai","behavior":"TextPart is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ThenableReference","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"ThenableReference is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"database:type:ThenableReference","kind":"type-export","surface":"database","behavior":"ThenableReference is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ThinkingConfig","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"ThinkingConfig is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:ThinkingConfig","kind":"type-export","surface":"ai","behavior":"ThinkingConfig is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ThinkingLevel","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"ThinkingLevel is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:ThinkingLevel","kind":"runtime-export","surface":"ai","behavior":"ThinkingLevel is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:ThinkingLevel","kind":"type-export","surface":"ai","behavior":"ThinkingLevel is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"thoughtSummary","surface":"ai","importPaths":[],"evidenceSlug":"ai-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"thoughtSummary is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"ai#helper-thoughtsummary","kind":"registry-row","surface":"ai","behavior":"`thoughtSummary()` returns undefined when no part is flagged `thought: true`, the captured lite-model case","status":"conforms","evidence":["`unit:upstream-ai-probes.test.ts` (I3 thoughtSummary from thought parts) + Capture ai-thinking-thought-parts replayed by `unit:helpers-schema.test.ts` test `ai#helper-thoughtsummary`","observation:ai-thinking-thought-parts","packages/pyric/test/ai/upstream-ai-probes.test.ts","packages/pyric/test/ai/helpers-schema.test.ts"],"assurance":"eligible"}]},{"feature":"Timestamp","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"Timestamp is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:Timestamp","kind":"runtime-export","surface":"firestore","behavior":"Timestamp is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore:type:Timestamp","kind":"type-export","surface":"firestore","behavior":"Timestamp is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#104","kind":"registry-row","surface":"firestore","behavior":"`Timestamp` shape (`{seconds, nanoseconds}`) is identical between prod and sandbox — round-trips cleanly","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#104a","kind":"registry-row","surface":"firestore","behavior":"**Unified Timestamp storage (FS-B4)** — a `Timestamp` written directly via the modular SDK (`setDoc({createdAt: Timestamp.now()})`) is stored as the same rules-internal `Timestamp` that `serverTimestamp()`/`Date` resolve to. Pre-FS-B4 a user-written `Timestamp` was the compat class only (not a `RulesValue`), so `request.resource.data.createdAt is timestamp` returned **false** for it while a `serverTimestamp()` write passed the same rule, and the two paths stored two different classes. A write-boundary converter now normalizes both.","status":"conforms","evidence":["`unit:firestore/sandbox-converters/user-timestamp.test.ts` (`is timestamp` passes for a user Timestamp; unified storage class; range-filter regression guard — verified failing pre-fix by removing the converter registration)","packages/pyric/test/firestore/sandbox-converters/user-timestamp.test.ts"],"assurance":"eligible"},{"id":"firestore#104b","kind":"registry-row","surface":"firestore","behavior":"**`Timestamp` nanos normalization + value API (FS-B12)** — `fromMillis`/`fromDate`/`now` derive `nanoseconds` as `floor((ms - seconds*1000) * 1e6)` so it is always non-negative; `fromMillis(-500).toMillis()` round-trips to -500 (was -1500). The class ships `isEqual` / `toString` / `toJSON` / `valueOf`, mirroring `clones/.../lite-api/timestamp.ts`.","status":"conforms","evidence":["`unit:admin-compat/timestamp-api.test.ts` (negative-millis round-trip + value API; pre-fix lacked the methods and mis-normalized)","packages/pyric/test/sandbox/firestore/admin-compat/timestamp-api.test.ts"],"assurance":"eligible"},{"id":"firestore#99","kind":"registry-row","surface":"firestore","behavior":"`serverTimestamp()` resolves to a `Timestamp` after the write commits","status":"conforms","evidence":["`unit:sandbox-target.test.ts`, `playground:firestore-sentinels` (bundled) + `playground:firestore-row-99-servertimestamp-resolves` (one-claim), oracle: `packages/conformance/observations/firestore/firestore-row-99-servertimestamp-resolves-to-timestamp.json` — `setDoc({at: serverTimestamp()})` then `getDoc` yields `at instanceof Timestamp === true`, `constructor.name === 'Timestamp'`, with both `.seconds` (number) and `.nanoseconds` (number) present.","observation:firestore-row-99-servertimestamp-resolves-to-timestamp","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"timestamp","surface":"firestore-rules","importPaths":["pyric/rules"],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"timestamp is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#160","kind":"registry-row","surface":"firestore-rules","behavior":"CEL builtins `math.*`/`timestamp.*`/`duration.*` (FM3) — arithmetic, date, and duration comparisons in rules","status":"conforms","evidence":["`oracle:rules-firestore-builtins-time-and-math` — production Firestore Rules Test API verdicts for corpus scenario \"builtins-time-and-math\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`; all cases match production.","observation:rules-firestore-builtins-time-and-math","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"Timestamp","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"Timestamp is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#162","kind":"registry-row","surface":"firestore-rules","behavior":"Typed cross-type operator overloads for `Timestamp`/`Duration` (Item 2) in rules — no silent numeric coercion / type-identity loss","status":"conforms","evidence":["`oracle:rules-firestore-cross-type-operator-overloads` — production Firestore Rules Test API verdicts for corpus scenario \"cross-type-operator-overloads\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`; all cases match production.","observation:rules-firestore-cross-type-operator-overloads","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"timestamp.date","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"timestamp.date is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.function.timestamp.date","kind":"rules-construct","surface":"firestore-rules","behavior":"timestamp.date is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.timestamp#function_date_"],"assurance":"eligible"},{"id":"firestore.method.timestamp.date","kind":"rules-construct","surface":"firestore-rules","behavior":"timestamp.date is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.Timestamp#function_date_"],"assurance":"eligible"}]},{"feature":"timestamp.date","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"timestamp.date is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#112","kind":"registry-row","surface":"storage-rules","behavior":"`request.time` compared against `timestamp.date(y,m,d)` and `timestamp.value(ms)` constructors","status":"conforms","evidence":["NEW ROW, 2026-07-10: production capture proves the evaluator supports `request.time` comparisons against both timestamp constructors. `oracle:rules-storage-request-time-timestamp` matches production verdict-for-verdict on all 4 cases (deadline-before/after via `timestamp.date()`, epoch-bound before/after via `timestamp.value()`).","observation:rules-storage-request-time-timestamp","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.function.timestamp.date","kind":"rules-construct","surface":"storage-rules","behavior":"timestamp.date is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/security/storage/timestamp#date"],"assurance":"eligible"}]},{"feature":"timestamp.day","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"timestamp.day is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.timestamp.day","kind":"rules-construct","surface":"firestore-rules","behavior":"timestamp.day is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.Timestamp#function_day_"],"assurance":"eligible"}]},{"feature":"timestamp.dayOfWeek","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"timestamp.dayOfWeek is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.timestamp.dayOfWeek","kind":"rules-construct","surface":"firestore-rules","behavior":"timestamp.dayOfWeek is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.Timestamp#function_dayOfWeek_"],"assurance":"eligible"}]},{"feature":"timestamp.dayOfYear","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"timestamp.dayOfYear is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.timestamp.dayOfYear","kind":"rules-construct","surface":"firestore-rules","behavior":"timestamp.dayOfYear is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.Timestamp#function_dayOfYear_"],"assurance":"eligible"}]},{"feature":"timestamp.hours","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"timestamp.hours is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.timestamp.hours","kind":"rules-construct","surface":"firestore-rules","behavior":"timestamp.hours is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.Timestamp#function_hours_"],"assurance":"eligible"}]},{"feature":"timestamp.minutes","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"timestamp.minutes is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.timestamp.minutes","kind":"rules-construct","surface":"firestore-rules","behavior":"timestamp.minutes is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.Timestamp#function_minutes_"],"assurance":"eligible"}]},{"feature":"timestamp.month","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"timestamp.month is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.timestamp.month","kind":"rules-construct","surface":"firestore-rules","behavior":"timestamp.month is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.Timestamp#function_month_"],"assurance":"eligible"}]},{"feature":"timestamp.nanos","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"timestamp.nanos is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.timestamp.nanos","kind":"rules-construct","surface":"firestore-rules","behavior":"timestamp.nanos is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.Timestamp#function_nanos_"],"assurance":"eligible"}]},{"feature":"timestamp.seconds","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"timestamp.seconds is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.timestamp.seconds","kind":"rules-construct","surface":"firestore-rules","behavior":"timestamp.seconds is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.Timestamp#function_seconds_"],"assurance":"eligible"}]},{"feature":"timestamp.time","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"timestamp.time is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.timestamp.time","kind":"rules-construct","surface":"firestore-rules","behavior":"timestamp.time is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.Timestamp#function_time_"],"assurance":"eligible"}]},{"feature":"timestamp.toMillis","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"timestamp.toMillis is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.timestamp.toMillis","kind":"rules-construct","surface":"firestore-rules","behavior":"timestamp.toMillis is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.Timestamp#function_toMillis_"],"assurance":"eligible"}]},{"feature":"timestamp.value","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"timestamp.value is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.function.timestamp.value","kind":"rules-construct","surface":"firestore-rules","behavior":"timestamp.value is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.timestamp#function_value_"],"assurance":"eligible"}]},{"feature":"timestamp.value","surface":"storage-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"timestamp.value is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage-rules#112","kind":"registry-row","surface":"storage-rules","behavior":"`request.time` compared against `timestamp.date(y,m,d)` and `timestamp.value(ms)` constructors","status":"conforms","evidence":["NEW ROW, 2026-07-10: production capture proves the evaluator supports `request.time` comparisons against both timestamp constructors. `oracle:rules-storage-request-time-timestamp` matches production verdict-for-verdict on all 4 cases (deadline-before/after via `timestamp.date()`, epoch-bound before/after via `timestamp.value()`).","observation:rules-storage-request-time-timestamp","packages/pyric/test/storage/rules-oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"storage.function.timestamp.value","kind":"rules-construct","surface":"storage-rules","behavior":"timestamp.value is enumerated in the storage rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/security/storage/timestamp#value"],"assurance":"eligible"}]},{"feature":"timestamp.year","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"timestamp.year is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore.method.timestamp.year","kind":"rules-construct","surface":"firestore-rules","behavior":"timestamp.year is enumerated in the firestore rules-language inventory","status":"accepted","evidence":["https://firebase.google.com/docs/reference/rules/rules.Timestamp#function_year_"],"assurance":"eligible"}]},{"feature":"TokenMessage","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"TokenMessage is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#10","kind":"registry-row","surface":"messaging-admin","behavior":"A send payload carrying exactly one of token, topic, or condition.","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `messaging-api`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"messaging-admin#12","kind":"registry-row","surface":"messaging-admin","behavior":"A device-token target. A syntactically invalid token is rejected with HTTP 400 INVALID_ARGUMENT whose fieldViolations name `message.token`.","status":"conforms","evidence":["oracle: `messaging-send-invalid-token-error-envelope.json` (fieldViolations names message.token). Replayed by the conformance suite.","observation:messaging-send-invalid-token-error-envelope","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"Tool","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"Tool is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:Tool","kind":"type-export","surface":"ai","behavior":"Tool is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"ToolConfig","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"ToolConfig is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:ToolConfig","kind":"type-export","surface":"ai","behavior":"ToolConfig is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"TopicMessage","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"TopicMessage is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#10","kind":"registry-row","surface":"messaging-admin","behavior":"A send payload carrying exactly one of token, topic, or condition.","status":"conforms","evidence":["Upstream typings (firebase-admin 13.10.0 `messaging-api`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"},{"id":"messaging-admin#13","kind":"registry-row","surface":"messaging-admin","behavior":"A topic target. A well-formed topic send is accepted and returns the standard resource name (no subscribers required); a topic name containing characters outside the documented `[a-zA-Z0-9-_.~%]` set is rejected with an INVALID_ARGUMENT error envelope.","status":"conforms","evidence":["oracle: `messaging-send-topic-accepted.json` (accepted) + `messaging-send-invalid-topic-name-error-envelope.json` (bad name rejected). Replayed by the conformance suite.","observation:messaging-send-topic-accepted","observation:messaging-send-invalid-topic-name-error-envelope","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"toSet","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"toSet is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#168","kind":"registry-row","surface":"firestore-rules","behavior":"`List.concat()`/`removeAll()`/`toSet()` (Item 5.2) in rules","status":"conforms","evidence":["`oracle:rules-firestore-list-methods-concat-removeall-toset` — production Firestore Rules Test API verdicts for corpus scenario \"list-methods-concat-removeall-toset\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`; all cases match production.","observation:rules-firestore-list-methods-concat-removeall-toset","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"TotpMultiFactorAssertion","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"TotpMultiFactorAssertion is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:TotpMultiFactorAssertion","kind":"type-export","surface":"auth","behavior":"TotpMultiFactorAssertion is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"TotpMultiFactorGenerator","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"TotpMultiFactorGenerator is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["MFA / phone / reCAPTCHA is deferred, not out of scope — reCAPTCHA/SMS are external infrastructure Pyric can mock with the OAuth resolver pattern, and TOTP is pure algorithm work.","Public type export is not mirrored."],"claims":[{"id":"auth:runtime:TotpMultiFactorGenerator","kind":"runtime-export","surface":"auth","behavior":"MFA / phone / reCAPTCHA is deferred, not out of scope — reCAPTCHA/SMS are external infrastructure Pyric can mock with the OAuth resolver pattern, and TOTP is pure algorithm work.","status":"deferred","evidence":["registry:auth#180"],"assurance":"not-applicable"},{"id":"auth:type:TotpMultiFactorGenerator","kind":"type-export","surface":"auth","behavior":"TotpMultiFactorGenerator is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"TotpMultiFactorInfo","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"TotpMultiFactorInfo is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:TotpMultiFactorInfo","kind":"type-export","surface":"auth","behavior":"TotpMultiFactorInfo is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"TotpSecret","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"TotpSecret is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["MFA / phone / reCAPTCHA is deferred, not out of scope — reCAPTCHA/SMS are external infrastructure Pyric can mock with the OAuth resolver pattern, and TOTP is pure algorithm work.","Public type export is not mirrored."],"claims":[{"id":"auth:runtime:TotpSecret","kind":"runtime-export","surface":"auth","behavior":"MFA / phone / reCAPTCHA is deferred, not out of scope — reCAPTCHA/SMS are external infrastructure Pyric can mock with the OAuth resolver pattern, and TOTP is pure algorithm work.","status":"deferred","evidence":["registry:auth#180"],"assurance":"not-applicable"},{"id":"auth:type:TotpSecret","kind":"type-export","surface":"auth","behavior":"TotpSecret is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"Transaction","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"Transaction is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors."],"claims":[{"id":"firestore:runtime:Transaction","kind":"runtime-export","surface":"firestore","behavior":"These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"},{"id":"firestore:type:Transaction","kind":"type-export","surface":"firestore","behavior":"Transaction is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"TransactionOptions","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"TransactionOptions is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:TransactionOptions","kind":"type-export","surface":"firestore","behavior":"TransactionOptions is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"TransactionOptions","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"TransactionOptions is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"database:type:TransactionOptions","kind":"type-export","surface":"database","behavior":"TransactionOptions is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"TransactionResult","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"TransactionResult is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["These Firebase classes are mirrored structurally in Pyric's type surface but are not exported as runtime constructor values; runtime identity remains unbuilt."],"claims":[{"id":"database:runtime:TransactionResult","kind":"runtime-export","surface":"database","behavior":"These Firebase classes are mirrored structurally in Pyric's type surface but are not exported as runtime constructor values; runtime identity remains unbuilt.","status":"deferred","evidence":["upstream:firebase/database"],"assurance":"not-applicable"},{"id":"database:type:TransactionResult","kind":"type-export","surface":"database","behavior":"TransactionResult is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"Transcription","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"Transcription is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:Transcription","kind":"type-export","surface":"ai","behavior":"Transcription is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"TwitterAuthProvider","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"TwitterAuthProvider is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:TwitterAuthProvider","kind":"runtime-export","surface":"auth","behavior":"TwitterAuthProvider is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth:type:TwitterAuthProvider","kind":"type-export","surface":"auth","behavior":"TwitterAuthProvider is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#181","kind":"registry-row","surface":"auth","behavior":"Provider marker classes. `TwitterAuthProvider.credential(token, secret)` takes a token AND a secret — Twitter is the one OAuth 1.0a provider in the set, where the OAuth 2.0 providers take a single access token. `SAMLAuthProvider`'s constructor ENFORCES the `saml.` providerId prefix (throwing `auth/argument-error` otherwise), because that id is what routes an assertion to the right configured IdP and a typo there would silently target nothing. SAML has no client-constructible credential, so the class has no `credential()` factory.","status":"conforms","evidence":["`unit:types.test.ts` — construction, PROVIDER_ID values, and the SAML prefix guard.","packages/pyric/test/auth/types.test.ts"],"assurance":"eligible"}]},{"feature":"TypedSchema","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"TypedSchema is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:TypedSchema","kind":"type-export","surface":"ai","behavior":"TypedSchema is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"union","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"union is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#174","kind":"registry-row","surface":"firestore-rules","behavior":"`Set.difference()`/`union()`/`intersection()` (Item 5.1) in rules","status":"conforms","evidence":["`oracle:rules-firestore-set-algebra-difference-union-intersection` — production Firestore Rules Test API verdicts for corpus scenario \"set-algebra-difference-union-intersection\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`; all cases match production.","observation:rules-firestore-set-algebra-difference-union-intersection","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"UnionToIntersection","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"UnionToIntersection is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:UnionToIntersection","kind":"type-export","surface":"firestore","behavior":"UnionToIntersection is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"unlink","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"unlink is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:unlink","kind":"runtime-export","surface":"auth","behavior":"unlink is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#162","kind":"registry-row","surface":"auth","behavior":"Detaches a provider and returns the updated user with a SHRUNKEN `providerData`. Unlinking a provider that was never linked throws `auth/no-such-provider`. Unlinking `'password'` takes the password with it, so `signInWithEmailAndPassword` for that account stops working. Unlinking the LAST provider does NOT re-anonymize the account — `isAnonymous` describes how an identity was born, not what it currently carries.","status":"conforms","evidence":["ORACLE-BACKED on the reject path — the ONE linking fact the oracle could reach, because it needs no email credential: `auth-unlink-provider` captured `noSuchProviderCode: auth/no-such-provider` against prod on an anonymous user. Replayed in `unit:oracle-conformance.test.ts`. The detach path is unit-backed (`unit:sandbox-linking-reauth.test.ts`).","observation:auth-unlink-provider","packages/pyric/test/auth/oracle-conformance.test.ts","packages/pyric/test/auth/sandbox-linking-reauth.test.ts"],"assurance":"eligible"}]},{"feature":"Unsubscribe","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"Unsubscribe is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"auth:type:Unsubscribe","kind":"type-export","surface":"auth","behavior":"Unsubscribe is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"Unsubscribe","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"Unsubscribe is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"firestore:type:Unsubscribe","kind":"type-export","surface":"firestore","behavior":"Unsubscribe is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"Unsubscribe","surface":"messaging","importPaths":["pyric/messaging","pyric/messaging/sw"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"Unsubscribe is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"messaging-sw:type:Unsubscribe","kind":"type-export","surface":"messaging-sw","behavior":"Unsubscribe is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"messaging:type:Unsubscribe","kind":"type-export","surface":"messaging","behavior":"Unsubscribe is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"Unsubscribe","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"Unsubscribe is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"database:type:Unsubscribe","kind":"type-export","surface":"database","behavior":"Unsubscribe is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"unsubscribeFromTopic","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"unsubscribeFromTopic is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#8","kind":"registry-row","surface":"messaging-admin","behavior":"Unsubscribes one or many registration tokens from a topic; resolves a `MessagingTopicManagementResponse`.","status":"conforms","evidence":["Upstream typings/JSDoc (firebase-admin 13.10.0 `messaging`); no observation yet.","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"unsupportedBuiltins","surface":"firestore-rules","importPaths":[],"evidenceSlug":"rules-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"unsupportedBuiltins is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore-rules#177","kind":"registry-row","surface":"firestore-rules","behavior":"Explicit `UNSUPPORTED` reporting for unimplemented built-ins (Item 0.A) in rules — an unimplemented built-in abstains rather than silently DENYing","status":"conforms","evidence":["`oracle:rules-firestore-unsupported-feature-witness` — production Firestore Rules Test API verdicts for corpus scenario \"unsupported-feature-witness\", replayed verdict-for-verdict against the local rules simulator by `unit:rules/oracle-conformance.test.ts`; all cases match production.","observation:rules-firestore-unsupported-feature-witness","packages/pyric/test/rules/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"update","surface":"rtdb","importPaths":["pyric/database"],"evidenceSlug":"database-compat","availability":"available","fidelity":"unverified","assurance":"qualified","summary":"update is available, has unverified fidelity, and is qualified for assurance.","caveats":["Update path validation — overlapping paths (e.g. `'/a'` and `'/a/x'` in the same call) throws synchronously before any write","upstream contract — needs targeted probe"],"claims":[{"id":"database:runtime:update","kind":"runtime-export","surface":"database","behavior":"update is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"rtdb-modular#116","kind":"registry-row","surface":"rtdb-modular","behavior":"`update(ref, {a: 1, b: 2})` merges top-level keys at the ref; unspecified keys preserved (in contrast to `set`'s replacement)","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-update-merges-keys.json` — after `set({a:1,b:2})` then `update({a:10})`, observed `final: {a:10, b:2}`.","observation:rtdb-modular-update-merges-keys"],"assurance":"eligible"},{"id":"rtdb-modular#117","kind":"registry-row","surface":"rtdb-modular","behavior":"Multi-path update — `update(parentRef, { 'a/x': 1, 'b/y': 2 })` lands BOTH writes atomically at distinct subtrees (RTDB's most distinctive feature; this is the \"fan-out\" pattern)","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-update-multipath-atomic.json` — observed `aX: 1, bY: 2` both readable after a single update call.","observation:rtdb-modular-update-multipath-atomic"],"assurance":"eligible"},{"id":"rtdb-modular#118","kind":"registry-row","surface":"rtdb-modular","behavior":"Multi-path update is atomic: if any path is denied by rules, the entire update rejects and no path is written","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-update-multipath-rules-denial.json` — observed `threw: true, code: 'PERMISSION_DENIED'` AND `okPathWrittenDespiteDenial: false` (the otherwise-permitted path also rolled back).","observation:rtdb-modular-update-multipath-rules-denial"],"assurance":"eligible"},{"id":"rtdb-modular#119","kind":"registry-row","surface":"rtdb-modular","behavior":"Setting a key to `null` inside `update` removes that key — same equivalence as `set(ref, null)`","status":"conforms","evidence":["oracle: `packages/conformance/observations/rtdb-modular/rtdb-modular-update-null-removes-key.json` — after `set({a:1,b:2})` then `update({a:null})`, observed `final: {b:2}` with `a` absent.","observation:rtdb-modular-update-null-removes-key"],"assurance":"eligible"},{"id":"rtdb-modular#120","kind":"registry-row","surface":"rtdb-modular","behavior":"Update path validation — overlapping paths (e.g. `'/a'` and `'/a/x'` in the same call) throws synchronously before any write","status":"unverified","evidence":["upstream contract — needs targeted probe"],"assurance":"qualified"},{"id":"rtdb-modular#M13","kind":"registry-row","surface":"rtdb-modular","behavior":"`update(ref, patch)` shallow-merges top-level keys at the ref's path","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"shallow-merges top-level keys\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M14","kind":"registry-row","surface":"rtdb-modular","behavior":"`null` value in a shallow update deletes that key","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"null values in a shallow update delete the key\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M15","kind":"registry-row","surface":"rtdb-modular","behavior":"`update(rootRef, { '/a/x': v1, '/b/y': v2 })` is a multi-path atomic write — all paths land or none do","status":"conforms","evidence":["`unit:upstream-rtdb-probes.test.ts` (\"one update nulls, mutates, and displaces within a limitToFirst window\") + `unit:modular/sandbox-target.test.ts` (atomic multipath + rules denial); matches the matrix #23 prod contract","packages/pyric/test/database/upstream-rtdb-probes.test.ts","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M16","kind":"registry-row","surface":"rtdb-modular","behavior":"Overlapping multi-path updates (one path is a descendant of another) reject before any path is written","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"rejects overlapping paths\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M22","kind":"registry-row","surface":"rtdb-modular","behavior":"`serverTimestamp()` sentinels resolve when nested inside multi-path update payloads","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` (\"resolves sentinels nested deep inside an update payload\")","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M37","kind":"registry-row","surface":"rtdb-modular","behavior":"`runTransaction(ref, fn, options?)` resolves to `{ committed: boolean, snapshot: DataSnapshot }` for the happy path — the update fn return value is written, committed is `true`, and `snapshot.val()` reflects the committed value","status":"conforms","evidence":["Sandbox aligned: `unit:modular/transaction.test.ts` (\"resolves to { committed: boolean, snapshot } with the committed value\"); matches oracle observations `packages/conformance/observations/rtdb-modular/rtdb-modular-runtransaction-success.json` + `rtdb-modular-runtransaction-returns-committed-snapshot.json` (against blockingfun, fb-js-sdk 12.13.0)","observation:rtdb-modular-runtransaction-success","observation:rtdb-modular-runtransaction-warm-client-speculation","packages/pyric/test/database/modular/transaction.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M37a","kind":"registry-row","surface":"rtdb-modular","behavior":"Returning `undefined` from the update fn ABORTS the transaction — resolves `{ committed: false, snapshot }`; no write performed, no listener fan-out","status":"conforms","evidence":["Sandbox aligned: `unit:modular/transaction.test.ts` (\"returning undefined aborts — committed: false, no write\" + \"aborted transaction does NOT fan out to listeners\"); matches oracle observation `packages/conformance/observations/rtdb-modular/rtdb-modular-runtransaction-abort-undefined.json` — known divergence: prod's `result.snapshot.val()` reflects the CLIENT's pre-fetch (often `null` even when the server has a value because the speculative invocation runs before the server snap arrives); the sandbox returns the actual pre-transaction value at the path (more useful in single-client harness). The agreed-upon contract callers should rely on is `committed === false` and unchanged server-side data, NOT the snapshot's `.val()` on the abort path.","observation:rtdb-modular-runtransaction-abort-undefined","packages/pyric/test/database/modular/transaction.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M37b","kind":"registry-row","surface":"rtdb-modular","behavior":"The update fn receives the CURRENT value at the ref's path; for an absent path the argument is `null` (NOT `undefined`)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/transaction.test.ts` (\"update fn receives null for an absent path\" + \"update fn receives the existing value for a seeded path\"); matches oracle observation `packages/conformance/observations/rtdb-modular/rtdb-modular-runtransaction-current-value-arg.json` (prod observation showed `missingArgs[0].isNull === true`) — note divergence: prod ALSO speculatively calls the fn with `null` for a seeded path before the server-snap arrives, the sandbox skips that speculative call (single invocation with the real current value)","observation:rtdb-modular-runtransaction-current-value-arg","packages/pyric/test/database/modular/transaction.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M37c","kind":"registry-row","surface":"rtdb-modular","behavior":"The update fn arg is a defensive deep clone — mutating it does NOT corrupt the stored tree (matters for code that does `current.count++; return undefined` and expects abort to preserve state)","status":"conforms","evidence":["`unit:modular/transaction.test.ts` (\"mutating the update-fn arg does NOT corrupt the stored tree\") — no separate oracle row (defensive contract; prod behavior is identical because the SDK clones on the wire boundary)","packages/pyric/test/database/modular/transaction.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M68","kind":"registry-row","surface":"rtdb-modular","behavior":"Write validation: an `undefined` payload, a non-finite number (`NaN`/`±Infinity`), or a key containing a forbidden char (`.`, `#`, `$`, `/`, `[`, `]`, control chars) is rejected with a plain `Error` (DB-B1)","status":"conforms","evidence":["Sandbox aligned: `unit:modular/normalization.test.ts` (\"rejects an undefined payload\" + \"rejects an invalid key\" + \"rejects a non-finite number\"); upstream `core/util/validation.ts:45,58,112-199`","packages/pyric/test/database/modular/normalization.test.ts"],"assurance":"eligible"},{"id":"rtdb-modular#M76","kind":"registry-row","surface":"rtdb-modular","behavior":"`.validate` rules are enforced on modular sandbox writes through `set`, atomic `update`, and `runTransaction`; a descendant validation failure rejects the operation without changing state.","status":"conforms","evidence":["`unit:modular/sandbox-target.test.ts` executes all three write paths against a required-child `.validate` rule and proves each rejects without committing state. The shared `SimulateHandler` behavior is production-locked by RTDB rules corpus rows #4 and #15.","packages/pyric/test/database/modular/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"updateCurrentUser","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"updateCurrentUser is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:updateCurrentUser","kind":"runtime-export","surface":"auth","behavior":"updateCurrentUser is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#87","kind":"registry-row","surface":"auth","behavior":"Sets the sandbox's current user (pass `null` to sign out), firing `onAuthStateChanged` — `auth.currentUser` reflects the passed user afterward","status":"conforms","evidence":["`unit:fruit-aliases.test.ts` — `auth.currentUser` becomes the passed user; `null` signs out","packages/pyric/test/auth/fruit-aliases.test.ts"],"assurance":"eligible"}]},{"feature":"UpdateData","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"UpdateData is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:UpdateData","kind":"type-export","surface":"firestore","behavior":"UpdateData is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"updateDoc","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"updateDoc is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:updateDoc","kind":"runtime-export","surface":"firestore","behavior":"updateDoc is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#33","kind":"registry-row","surface":"firestore","behavior":"Merges `data` into the existing doc; missing fields preserved. **Top-level keys are dot-separated FieldPaths** (FS-B5): `updateDoc({'a.b': 2})` sets the nested leaf `a.b` (preserving `a.c`), not a literal `\"a.b\"` key; a single-segment map value replaces that field wholesale; `deleteField()` at a dotted path removes the nested leaf.","status":"conforms","evidence":["`unit:sandbox-target.test.ts`, `unit:admin-compat/field-path-merge.test.ts` (FS-B5 dot-path nested write + delete; verified failing pre-fix)","observation:firestore-updatedoc-dotpath-fieldpath","packages/pyric/test/firestore/sandbox-target.test.ts","packages/pyric/test/sandbox/firestore/admin-compat/field-path-merge.test.ts"],"assurance":"eligible"},{"id":"firestore#34","kind":"registry-row","surface":"firestore","behavior":"Throws `not-found` (sandbox) / `FirebaseError('not-found')` (prod) on missing doc","status":"conforms","evidence":["`unit:sandbox-target.test.ts` (implicit in writes-fail-on-missing tests), oracle: `packages/conformance/observations/firestore/firestore-updatedoc-missing-error.json` (prod throws `FirebaseError` with `code: 'not-found'`, message `\"5 NOT_FOUND: No document to update: …\"`)","observation:firestore-updatedoc-missing-error","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#35","kind":"registry-row","surface":"firestore","behavior":"Does NOT run a converter — partial updates don't have a typed home (matches JS SDK)","status":"conforms","evidence":["(documented in `withConverter` block)"],"assurance":"eligible"},{"id":"firestore#36","kind":"registry-row","surface":"firestore","behavior":"Sentinels resolve mid-update (`increment(1)` against an existing numeric field, etc.)","status":"conforms","evidence":["`unit:sandbox-target.test.ts`, `playground:firestore-sentinels`, oracle: `packages/conformance/observations/firestore/firestore-row-36-sentinels-in-updatedoc.json` — after `setDoc({count: 5, tags: ['a'], oldField: 'keep-then-remove'})` then `updateDoc({count: increment(3), tags: arrayUnion('b'), oldField: deleteField()})`, the follow-up `getDoc` returns `count: 8`, `tags: ['a', 'b']`, and `oldField` absent from the doc (the deleteField sentinel actually removes the key). All three sentinels apply in one mid-update commit.","observation:firestore-row-36-sentinels-in-updatedoc","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#37","kind":"registry-row","surface":"firestore","behavior":"Sandbox-live: each call re-evaluates auth (alice → bob between writes uses bob's auth)","status":"conforms","evidence":["`unit:sandbox-live-identity.test.ts` (\"updateDoc re-evaluates auth per call\")","packages/pyric/test/firestore/sandbox-live-identity.test.ts"],"assurance":"eligible"}]},{"feature":"updateEmail","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"updateEmail is available, has diverged fidelity, and is qualified for assurance.","caveats":["Changes the stored email (via the same path as `sandbox.updateUser`, rejecting `auth/email-already-in-use` / `auth/invalid-email`) and mutates the held `user` in place, so the next sign-in resolves against the new email. Leniency vs prod: the sandbox does NOT enforce `auth/requires-recent-login` and is not routed through `verifyBeforeUpdateEmail` (which the real SDK requires when email-enumeration protection is on)","`unit:fruit-aliases.test.ts` — stored email changes; re-sign-in works with the new email, fails with the old","In production the POINT of re-authentication is the `auth/requires-recent-login` gate: `updateEmail` / `updatePassword` / `deleteUser` refuse to run on a session whose sign-in is older than a few minutes, and re-auth is how you clear it. The sandbox does NOT enforce that gate — those three mutations already run on a session of any age (a pre-existing documented divergence), so there is no gate here for re-auth to clear. What re-auth DOES do here is real but narrower: it genuinely re-verifies the credential, mints a fresh token, and returns `operationType: 'reauthenticate'`. Code that calls it runs unchanged against prod, where it also clears the gate.","Declared divergence, not a bug: inventing a recent-login gate would break every existing sandbox flow (which never re-authenticates) while proving nothing. `unit:sandbox-linking-reauth.test.ts` pins the behavior that IS provided (real credential re-verification + a fresh token)."],"claims":[{"id":"auth:runtime:updateEmail","kind":"runtime-export","surface":"auth","behavior":"updateEmail is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#176","kind":"registry-row","surface":"auth","behavior":"In production the POINT of re-authentication is the `auth/requires-recent-login` gate: `updateEmail` / `updatePassword` / `deleteUser` refuse to run on a session whose sign-in is older than a few minutes, and re-auth is how you clear it. The sandbox does NOT enforce that gate — those three mutations already run on a session of any age (a pre-existing documented divergence), so there is no gate here for re-auth to clear. What re-auth DOES do here is real but narrower: it genuinely re-verifies the credential, mints a fresh token, and returns `operationType: 'reauthenticate'`. Code that calls it runs unchanged against prod, where it also clears the gate.","status":"diverged-documented","evidence":["Declared divergence, not a bug: inventing a recent-login gate would break every existing sandbox flow (which never re-authenticates) while proving nothing. `unit:sandbox-linking-reauth.test.ts` pins the behavior that IS provided (real credential re-verification + a fresh token).","packages/pyric/test/auth/sandbox-linking-reauth.test.ts"],"assurance":"qualified"},{"id":"auth#84","kind":"registry-row","surface":"auth","behavior":"Changes the stored email (via the same path as `sandbox.updateUser`, rejecting `auth/email-already-in-use` / `auth/invalid-email`) and mutates the held `user` in place, so the next sign-in resolves against the new email. Leniency vs prod: the sandbox does NOT enforce `auth/requires-recent-login` and is not routed through `verifyBeforeUpdateEmail` (which the real SDK requires when email-enumeration protection is on)","status":"diverged-documented","evidence":["`unit:fruit-aliases.test.ts` — stored email changes; re-sign-in works with the new email, fails with the old","packages/pyric/test/auth/fruit-aliases.test.ts"],"assurance":"qualified"}]},{"feature":"updateMetadata","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"updateMetadata is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["`updateMetadata` with `undefined` field values preserves the prior value (does NOT clear it)","divergence: prod accepts `null` to explicitly clear a field. Sandbox doesn't model `null`-clear (per `metadata.ts` doc comment). Documented; not probe-locked.","`FullMetadata.md5Hash` populated on uploads","divergence: sandbox does NOT compute `md5Hash`. Oracle-locked: `packages/conformance/observations/storage/storage-upload-then-getmetadata.json` confirms prod sets `md5Hash` (`hasMd5Hash: true` after a vanilla `uploadBytes`). Both sides pinned in `oracle-conformance.test.ts`. Aligning the sandbox is a one-spot fix in `upload.ts`'s `buildStoredMetadata`.","`FullMetadata.ref` lazy population (prod populates lazily)","not modeled in `pyric/storage` — `metadata.ts` explicitly omits `ref` from `FullMetadata`"],"claims":[{"id":"storage:runtime:updateMetadata","kind":"runtime-export","surface":"storage","behavior":"updateMetadata is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"storage#82","kind":"registry-row","surface":"storage","behavior":"`updateMetadata(ref, patch)` replaces the listed client-settable fields wholesale (per Firebase semantics)","status":"conforms","evidence":["`unit:metadata.test.ts` (\"replaces settable fields, bumps metageneration, refreshes updated\")","packages/pyric/test/storage/metadata.test.ts"],"assurance":"eligible"},{"id":"storage#83","kind":"registry-row","surface":"storage","behavior":"`updateMetadata` bumps `metageneration` by 1 on each call","status":"conforms","evidence":["`unit:metadata.test.ts`","packages/pyric/test/storage/metadata.test.ts"],"assurance":"eligible"},{"id":"storage#84","kind":"registry-row","surface":"storage","behavior":"`updateMetadata` refreshes `updated` to the call moment; `timeCreated` and `generation` stay pinned","status":"conforms","evidence":["`unit:metadata.test.ts`","packages/pyric/test/storage/metadata.test.ts"],"assurance":"eligible"},{"id":"storage#85","kind":"registry-row","surface":"storage","behavior":"`updateMetadata` preserves the blob bytes (only metadata changes)","status":"conforms","evidence":["`unit:metadata.test.ts` (\"leaves the blob content untouched\")","packages/pyric/test/storage/metadata.test.ts"],"assurance":"eligible"},{"id":"storage#86","kind":"registry-row","surface":"storage","behavior":"`updateMetadata` with `undefined` field values preserves the prior value (does NOT clear it)","status":"diverged-documented","evidence":["divergence: prod accepts `null` to explicitly clear a field. Sandbox doesn't model `null`-clear (per `metadata.ts` doc comment). Documented; not probe-locked."],"assurance":"qualified"},{"id":"storage#87","kind":"registry-row","surface":"storage","behavior":"`updateMetadata` throws `storage/object-not-found` for missing paths","status":"conforms","evidence":["`unit:metadata.test.ts` (\"throws object-not-found when the path is missing\")","packages/pyric/test/storage/metadata.test.ts"],"assurance":"eligible"},{"id":"storage#88","kind":"registry-row","surface":"storage","behavior":"`updateMetadata` throws `storage/invalid-root-operation` on the root","status":"conforms","evidence":["`unit:metadata.test.ts` (\"throws invalid-root-operation on the root reference\")","packages/pyric/test/storage/metadata.test.ts"],"assurance":"eligible"},{"id":"storage#90","kind":"registry-row","surface":"storage","behavior":"Prod: `updateMetadata({customMetadata: {...}})` round-trips through a follow-up `getMetadata`","status":"conforms","evidence":["oracle: `packages/conformance/observations/storage/storage-update-metadata-roundtrip.json` (against blockingfun, fb-js-sdk 12.13.0: post-update `getMetadata` returns the exact `customMetadata` object, `metageneration` bumps `'1'` → `'2'`, `customSurvived: true`, `metagenerationBumped: true`)","observation:storage-update-metadata-roundtrip"],"assurance":"eligible"},{"id":"storage#91","kind":"registry-row","surface":"storage","behavior":"`FullMetadata.md5Hash` populated on uploads","status":"diverged-documented","evidence":["divergence: sandbox does NOT compute `md5Hash`. Oracle-locked: `packages/conformance/observations/storage/storage-upload-then-getmetadata.json` confirms prod sets `md5Hash` (`hasMd5Hash: true` after a vanilla `uploadBytes`). Both sides pinned in `oracle-conformance.test.ts`. Aligning the sandbox is a one-spot fix in `upload.ts`'s `buildStoredMetadata`.","observation:storage-upload-then-getmetadata","packages/pyric/test/storage/oracle-conformance.test.ts"],"assurance":"qualified"},{"id":"storage#92","kind":"registry-row","surface":"storage","behavior":"`FullMetadata.ref` lazy population (prod populates lazily)","status":"unsupported","evidence":["not modeled in `pyric/storage` — `metadata.ts` explicitly omits `ref` from `FullMetadata`"],"assurance":"ineligible"}]},{"feature":"updatePassword","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"updatePassword is available, has diverged fidelity, and is qualified for assurance.","caveats":["Sets the stored password (validated for strength). The sandbox DOES store and verify passwords, so this is a real mutation: a subsequent `signInWithEmailAndPassword` with the new password succeeds and the old one throws `auth/wrong-password`. Leniency vs prod: no `auth/requires-recent-login` enforcement","`unit:fruit-aliases.test.ts` — new password signs in, old password throws `auth/wrong-password`","In production the POINT of re-authentication is the `auth/requires-recent-login` gate: `updateEmail` / `updatePassword` / `deleteUser` refuse to run on a session whose sign-in is older than a few minutes, and re-auth is how you clear it. The sandbox does NOT enforce that gate — those three mutations already run on a session of any age (a pre-existing documented divergence), so there is no gate here for re-auth to clear. What re-auth DOES do here is real but narrower: it genuinely re-verifies the credential, mints a fresh token, and returns `operationType: 'reauthenticate'`. Code that calls it runs unchanged against prod, where it also clears the gate.","Declared divergence, not a bug: inventing a recent-login gate would break every existing sandbox flow (which never re-authenticates) while proving nothing. `unit:sandbox-linking-reauth.test.ts` pins the behavior that IS provided (real credential re-verification + a fresh token)."],"claims":[{"id":"auth:runtime:updatePassword","kind":"runtime-export","surface":"auth","behavior":"updatePassword is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#176","kind":"registry-row","surface":"auth","behavior":"In production the POINT of re-authentication is the `auth/requires-recent-login` gate: `updateEmail` / `updatePassword` / `deleteUser` refuse to run on a session whose sign-in is older than a few minutes, and re-auth is how you clear it. The sandbox does NOT enforce that gate — those three mutations already run on a session of any age (a pre-existing documented divergence), so there is no gate here for re-auth to clear. What re-auth DOES do here is real but narrower: it genuinely re-verifies the credential, mints a fresh token, and returns `operationType: 'reauthenticate'`. Code that calls it runs unchanged against prod, where it also clears the gate.","status":"diverged-documented","evidence":["Declared divergence, not a bug: inventing a recent-login gate would break every existing sandbox flow (which never re-authenticates) while proving nothing. `unit:sandbox-linking-reauth.test.ts` pins the behavior that IS provided (real credential re-verification + a fresh token).","packages/pyric/test/auth/sandbox-linking-reauth.test.ts"],"assurance":"qualified"},{"id":"auth#85","kind":"registry-row","surface":"auth","behavior":"Sets the stored password (validated for strength). The sandbox DOES store and verify passwords, so this is a real mutation: a subsequent `signInWithEmailAndPassword` with the new password succeeds and the old one throws `auth/wrong-password`. Leniency vs prod: no `auth/requires-recent-login` enforcement","status":"diverged-documented","evidence":["`unit:fruit-aliases.test.ts` — new password signs in, old password throws `auth/wrong-password`","packages/pyric/test/auth/fruit-aliases.test.ts"],"assurance":"qualified"}]},{"feature":"updatePhoneNumber","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"updatePhoneNumber is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Phone number mutation is deferred alongside the rest of the phone-auth family — buildable via a mocked SMS/verification-code resolver, the same shape as the OAuth resolver."],"claims":[{"id":"auth:runtime:updatePhoneNumber","kind":"runtime-export","surface":"auth","behavior":"Phone number mutation is deferred alongside the rest of the phone-auth family — buildable via a mocked SMS/verification-code resolver, the same shape as the OAuth resolver.","status":"deferred","evidence":["registry:auth#181"],"assurance":"not-applicable"}]},{"feature":"updateProfile","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"updateProfile is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:updateProfile","kind":"runtime-export","surface":"auth","behavior":"updateProfile is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#62","kind":"registry-row","surface":"auth","behavior":"`updateProfile(user, {displayName, photoURL})` mutates the held user + stored record in place (null clears a field; omitted fields untouched) without an extra `onAuthStateChanged` fire. Profile survives `signOut` → `signInWithEmailAndPassword`.","status":"conforms","evidence":["`unit:sandbox-update-profile.test.ts` (in-place mutation, listUsers persist, null clear, no extra listener); re-sign-in persistence: `unit:upstream-auth-probes.test.ts`","packages/pyric/test/auth/sandbox-update-profile.test.ts","packages/pyric/test/auth/upstream-auth-probes.test.ts"],"assurance":"eligible"}]},{"feature":"uploadBytes","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"uploadBytes is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"storage:runtime:uploadBytes","kind":"runtime-export","surface":"storage","behavior":"uploadBytes is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"storage#24","kind":"registry-row","surface":"storage","behavior":"Accepts `Blob` payload; returns `UploadResult` with populated `metadata`","status":"conforms","evidence":["`unit:reference.test.ts` (\"accepts a Blob and round-trips through getBlob\")","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#25","kind":"registry-row","surface":"storage","behavior":"Accepts `Uint8Array` payload","status":"conforms","evidence":["`unit:reference.test.ts` (\"accepts a Uint8Array\")","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#26","kind":"registry-row","surface":"storage","behavior":"Accepts `ArrayBuffer` payload","status":"conforms","evidence":["`unit:reference.test.ts` (\"accepts an ArrayBuffer\")","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#27","kind":"registry-row","surface":"storage","behavior":"ContentType precedence: caller's `metadata.contentType` > `Blob.type` > `application/octet-stream`","status":"conforms","evidence":["`unit:reference.test.ts` (\"metadata.contentType overrides the Blob's intrinsic type\" + \"falls back to application/octet-stream when no type is supplied\")","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#28","kind":"registry-row","surface":"storage","behavior":"`Blob.type === ''` (no intrinsic type) falls through to `application/octet-stream`, NOT to `''`","status":"conforms","evidence":["`unit:reference.test.ts` (\"falls back to application/octet-stream when no type is supplied\")","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#29","kind":"registry-row","surface":"storage","behavior":"`customMetadata` round-trips through the upload pipeline","status":"conforms","evidence":["`unit:reference.test.ts` (\"round-trips customMetadata\") + `unit:metadata.test.ts`","packages/pyric/test/storage/metadata.test.ts","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#30","kind":"registry-row","surface":"storage","behavior":"Empty `Blob.type` rewrap: when caller hint differs from `Blob.type`, the blob is re-wrapped with the caller's type (same bytes)","status":"conforms","evidence":["implicit in `unit:reference.test.ts` (\"metadata.contentType overrides the Blob's intrinsic type\")","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#31","kind":"registry-row","surface":"storage","behavior":"Throws `storage/invalid-root-operation` when called on the root reference","status":"conforms","evidence":["`unit:reference.test.ts` (\"throws on root reference\")","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#32","kind":"registry-row","surface":"storage","behavior":"Returned `metadata.fullPath` matches the ref's `fullPath`","status":"conforms","evidence":["`unit:reference.test.ts`","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#33","kind":"registry-row","surface":"storage","behavior":"Returned `metadata.size` matches the input blob's byte length","status":"conforms","evidence":["`unit:reference.test.ts`","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#34","kind":"registry-row","surface":"storage","behavior":"Returned `metadata.bucket` matches the storage handle's bucket","status":"conforms","evidence":["`unit:reference.test.ts`","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#35","kind":"registry-row","surface":"storage","behavior":"Replaces any existing object at the path (overwrite, not append)","status":"conforms","evidence":["`unit:upstream-storage-probes.test.ts` (\"second uploadBytes at the same path replaces bytes and metadata\")","packages/pyric/test/storage/upstream-storage-probes.test.ts"],"assurance":"eligible"},{"id":"storage#36","kind":"registry-row","surface":"storage","behavior":"Prod: round-trips uploaded bytes through `getDownloadURL` + fetch (byte-for-byte equality)","status":"conforms","evidence":["oracle: `packages/conformance/observations/storage/storage-upload-bytes-roundtrip.json` (against blockingfun, fb-js-sdk 12.13.0: 6-byte payload → uploadBytes → getDownloadURL → HTTPS fetch → `bytesMatch: true`, `urlIsHttps: true`, `bodyLen === payloadLen === 6`). This row records the production answer key; row #51 compares the sandbox's page-local URL behavior against it.","observation:storage-upload-bytes-roundtrip"],"assurance":"eligible"},{"id":"storage#37","kind":"registry-row","surface":"storage","behavior":"Returned `metadata.contentType` matches what the caller hinted (when set)","status":"conforms","evidence":["`unit:reference.test.ts` + oracle: `packages/conformance/observations/storage/storage-upload-then-getmetadata.json` (`contentType: 'application/octet-stream'` round-trip against blockingfun, fb-js-sdk 12.13.0; `contentTypeMatches: true`)","observation:storage-upload-then-getmetadata","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#38","kind":"registry-row","surface":"storage","behavior":"Returned `metadata.generation` / `metageneration` are stringified counters (`'1'` after fresh upload)","status":"conforms","evidence":["`unit:metadata.test.ts`","packages/pyric/test/storage/metadata.test.ts"],"assurance":"eligible"}]},{"feature":"uploadBytesResumable","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"uploadBytesResumable is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["The UploadTask and observer surface is deferred — v1 shipped the one-shot uploadBytes driver first; the resumable/observable variant is unbuilt, not unbuildable.","Exported by `firebase/storage`; returns an `UploadTask` with `pause()` / `resume()` / `cancel()`","No `pyric/storage` implementation or behavioral probe exists; availability is classified by the owning surface contract.","`task.on('state_changed', next, error, complete)` fires `next` with `{bytesTransferred, totalBytes, state}` snapshots","not implemented","`task.pause()` flips `state` to `'paused'`; `task.resume()` continues","`task.cancel()` rejects the upload with `storage/canceled`"],"claims":[{"id":"storage:runtime:uploadBytesResumable","kind":"runtime-export","surface":"storage","behavior":"The UploadTask and observer surface is deferred — v1 shipped the one-shot uploadBytes driver first; the resumable/observable variant is unbuilt, not unbuildable.","status":"deferred","evidence":["registry:storage#47"],"assurance":"not-applicable"},{"id":"storage#47","kind":"registry-row","surface":"storage","behavior":"Exported by `firebase/storage`; returns an `UploadTask` with `pause()` / `resume()` / `cancel()`","status":"unsupported","evidence":["No `pyric/storage` implementation or behavioral probe exists; availability is classified by the owning surface contract."],"assurance":"ineligible"},{"id":"storage#48","kind":"registry-row","surface":"storage","behavior":"`task.on('state_changed', next, error, complete)` fires `next` with `{bytesTransferred, totalBytes, state}` snapshots","status":"unsupported","evidence":["not implemented"],"assurance":"ineligible"},{"id":"storage#49","kind":"registry-row","surface":"storage","behavior":"`task.pause()` flips `state` to `'paused'`; `task.resume()` continues","status":"unsupported","evidence":["not implemented"],"assurance":"ineligible"},{"id":"storage#50","kind":"registry-row","surface":"storage","behavior":"`task.cancel()` rejects the upload with `storage/canceled`","status":"unsupported","evidence":["not implemented"],"assurance":"ineligible"}]},{"feature":"UploadMetadata","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"UploadMetadata is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"storage:type:UploadMetadata","kind":"type-export","surface":"storage","behavior":"UploadMetadata is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"UploadResult","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"UploadResult is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"storage:type:UploadResult","kind":"type-export","surface":"storage","behavior":"UploadResult is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"uploadString","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"uploadString is available, has diverged fidelity, and is qualified for assurance.","caveats":["Sandbox: `format='base64url'` (or any unknown format) rejected with `storage/invalid-format` naming the bad format. Prod: `base64url` is ACCEPTED (upload succeeds); a genuinely-unrecognized format throws `storage/unknown`","divergence, both halves oracle-locked by `packages/conformance/observations/storage/storage-uploadstring-unknown-format.json`: prod accepts `base64url` (`base64urlOk: true`) and throws `storage/unknown` for an unrecognized format — not `storage/invalid-format`. The v1 sandbox ships only `raw`/`base64`/`data_url` (matches `StringFormat`) and throws `storage/invalid-format` for anything else (ST-B3 replaced the old mis-parse-as-data_url behavior). Both sides pinned in `oracle-conformance.test.ts`; sandbox code path documented in `upload.ts`'s `decodeString`. Implementing base64url decoding is still one line in `decodeString`."],"claims":[{"id":"storage:runtime:uploadString","kind":"runtime-export","surface":"storage","behavior":"uploadString is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"storage#39","kind":"registry-row","surface":"storage","behavior":"`format='raw'` (default): UTF-8 encodes the string; `contentType` defaults to `text/plain;charset=utf-8`","status":"conforms","evidence":["`unit:reference.test.ts` (\"raw format encodes UTF-8 and defaults contentType to text/plain\")","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#40","kind":"registry-row","surface":"storage","behavior":"`format='base64'`: decodes payload bytes from standard base64","status":"conforms","evidence":["`unit:reference.test.ts` (\"base64 format decodes payload bytes\")","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#41","kind":"registry-row","surface":"storage","behavior":"Sandbox: `format='base64url'` (or any unknown format) rejected with `storage/invalid-format` naming the bad format. Prod: `base64url` is ACCEPTED (upload succeeds); a genuinely-unrecognized format throws `storage/unknown`","status":"diverged-documented","evidence":["divergence, both halves oracle-locked by `packages/conformance/observations/storage/storage-uploadstring-unknown-format.json`: prod accepts `base64url` (`base64urlOk: true`) and throws `storage/unknown` for an unrecognized format — not `storage/invalid-format`. The v1 sandbox ships only `raw`/`base64`/`data_url` (matches `StringFormat`) and throws `storage/invalid-format` for anything else (ST-B3 replaced the old mis-parse-as-data_url behavior). Both sides pinned in `oracle-conformance.test.ts`; sandbox code path documented in `upload.ts`'s `decodeString`. Implementing base64url decoding is still one line in `decodeString`.","observation:storage-uploadstring-unknown-format","packages/pyric/test/storage/error-codes.test.ts","packages/pyric/test/storage/oracle-conformance.test.ts"],"assurance":"qualified"},{"id":"storage#42","kind":"registry-row","surface":"storage","behavior":"`format='data_url'`: parses `data:<mime>;base64,<payload>`, infers `contentType` from prefix","status":"conforms","evidence":["`unit:reference.test.ts` (\"data_url format infers contentType from the prefix\")","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#43","kind":"registry-row","surface":"storage","behavior":"`format='data_url'` with non-base64 payload: percent-decodes the body","status":"conforms","evidence":["`unit:upstream-storage-probes.test.ts` (\"non-base64 data_url percent-decodes the body\"; malformed `%%0` → `storage/invalid-format`)","packages/pyric/test/storage/upstream-storage-probes.test.ts"],"assurance":"eligible"},{"id":"storage#44","kind":"registry-row","surface":"storage","behavior":"Caller's `metadata.contentType` beats data_url inference","status":"conforms","evidence":["`unit:reference.test.ts` (\"caller metadata.contentType beats data_url inference\")","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#45","kind":"registry-row","surface":"storage","behavior":"Malformed `data_url` (no comma / doesn't start with `data:`) throws `TypeError` with \"data_url format\" message","status":"conforms","evidence":["`unit:reference.test.ts` (\"throws on malformed data_url\")","packages/pyric/test/storage/reference.test.ts"],"assurance":"eligible"},{"id":"storage#46","kind":"registry-row","surface":"storage","behavior":"Prod: `uploadString(ref, value, 'base64')` round-trips via `getDownloadURL` + fetch","status":"conforms","evidence":["oracle: `packages/conformance/observations/storage/storage-uploadstring-base64-roundtrip.json` (`'aGVsbG8='` → `'hello'` against blockingfun, fb-js-sdk 12.13.0; `textMatches: true`)","observation:storage-uploadstring-base64-roundtrip"],"assurance":"eligible"}]},{"feature":"UploadTask","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"UploadTask is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"storage:type:UploadTask","kind":"type-export","surface":"storage","behavior":"UploadTask is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"UploadTaskSnapshot","surface":"storage","importPaths":["pyric/storage"],"evidenceSlug":"storage-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"UploadTaskSnapshot is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"storage:type:UploadTaskSnapshot","kind":"type-export","surface":"storage","behavior":"UploadTaskSnapshot is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"URLContext","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"URLContext is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:URLContext","kind":"type-export","surface":"ai","behavior":"URLContext is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"URLContextMetadata","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"URLContextMetadata is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:URLContextMetadata","kind":"type-export","surface":"ai","behavior":"URLContextMetadata is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"URLContextTool","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"URLContextTool is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:URLContextTool","kind":"type-export","surface":"ai","behavior":"URLContextTool is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"URLMetadata","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"URLMetadata is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:URLMetadata","kind":"type-export","surface":"ai","behavior":"URLMetadata is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"URLRetrievalStatus","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"URLRetrievalStatus is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:runtime:URLRetrievalStatus","kind":"runtime-export","surface":"ai","behavior":"URLRetrievalStatus is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:URLRetrievalStatus","kind":"type-export","surface":"ai","behavior":"URLRetrievalStatus is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"UsageMetadata","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"UsageMetadata is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:UsageMetadata","kind":"type-export","surface":"ai","behavior":"UsageMetadata is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"useDeviceLanguage","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"useDeviceLanguage is available, has diverged fidelity, and is qualified for assurance.","caveats":["Accepted no-op — the sandbox has no device locale to read, so there is no language to set; accepted so init code that calls it compiles + runs","`unit:fruit-aliases.test.ts` — resolves/returns without error"],"claims":[{"id":"auth:runtime:useDeviceLanguage","kind":"runtime-export","surface":"auth","behavior":"useDeviceLanguage is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#88","kind":"registry-row","surface":"auth","behavior":"Accepted no-op — the sandbox has no device locale to read, so there is no language to set; accepted so init code that calls it compiles + runs","status":"diverged-documented","evidence":["`unit:fruit-aliases.test.ts` — resolves/returns without error","packages/pyric/test/auth/fruit-aliases.test.ts"],"assurance":"qualified"}]},{"feature":"User","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"unsupported","assurance":"ineligible","summary":"User is available, has unsupported fidelity, and is ineligible for assurance.","caveats":["`user.metadata.creationTime` / `lastSignInTime`","client `User.metadata` not exposed (AUTH-GAP); the admin record carries `createdAt`/`lastLoginAt` (ISO)","`user.reload()` / `user.delete()` / `user.toJSON()` / `user.refreshToken` / `user.tenantId`","not modeled by the sandbox; retained as an explicit unsupported behavior row rather than synthesized (AUTH-GAP)"],"claims":[{"id":"auth:type:User","kind":"type-export","surface":"auth","behavior":"User is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#54","kind":"registry-row","surface":"auth","behavior":"`user.getIdToken()` returns a stable opaque token in sandbox (`sandbox-id-token-…`)","status":"conforms","evidence":["`unit:sandbox-anonymous.test.ts`","packages/pyric/test/auth/sandbox-anonymous.test.ts"],"assurance":"eligible"},{"id":"auth#55","kind":"registry-row","surface":"auth","behavior":"`user.getIdToken(true)` (forceRefresh) returns a NEW token; subsequent `getIdToken(false)` returns the cached new token","status":"conforms","evidence":["`unit:sandbox-token-refresh.test.ts` — was ⚠ (documented divergence); aligned to prod in commit — sandbox now mints a fresh token on forceRefresh and fires `onIdTokenChanged`. Oracle: `packages/conformance/observations/auth/auth-getidtoken-force-refresh.json` defines the target shape (`forceRefreshReturnedDifferentString: true`, `token1EqualsToken2: true` against blockingfun — the refreshed token is cached, so a subsequent non-forced read returns it, not yet another fresh one). Sandbox tokens stay `sandbox-id-token-<uid>-<hash>` strings; prod's are real JWTs.","observation:auth-getidtoken-force-refresh","packages/pyric/test/auth/sandbox-token-refresh.test.ts"],"assurance":"eligible"},{"id":"auth#56","kind":"registry-row","surface":"auth","behavior":"`user.getIdTokenResult()` returns claims","status":"conforms","evidence":["`unit:sandbox-providers.test.ts` (custom-claims path)","packages/pyric/test/auth/sandbox-providers.test.ts"],"assurance":"eligible"},{"id":"auth#57","kind":"registry-row","surface":"auth","behavior":"`user.uid`, `user.email`, `user.displayName`, `user.isAnonymous` reflect the source","status":"conforms","evidence":["`playground:auth-anonymous`, `playground:auth-email-password`"],"assurance":"eligible"},{"id":"auth#58","kind":"registry-row","surface":"auth","behavior":"`user.emailVerified` — present on every sandbox-minted `User` (default `false`; sandbox has no verification flow). Prod passes the real value through (no longer stripped). The admin record (`sandbox.listUsers`) carries it too","status":"conforms","evidence":["`unit:auth-gap-surface.test.ts` (locks AUTH-GAP)","packages/pyric/test/auth/auth-gap-surface.test.ts"],"assurance":"eligible"},{"id":"auth#58a","kind":"registry-row","surface":"auth","behavior":"`user.photoURL` / `user.phoneNumber` — present (sandbox default `null`; prod passes through, no longer stripped)","status":"conforms","evidence":["`unit:auth-gap-surface.test.ts`","packages/pyric/test/auth/auth-gap-surface.test.ts"],"assurance":"eligible"},{"id":"auth#58b","kind":"registry-row","surface":"auth","behavior":"`user.providerId` (aggregate, `'firebase'`) + `user.providerData: UserInfo[]` — sandbox synthesizes one provider entry for non-anonymous users, empty for anonymous; prod passes the real array through (no longer stripped). The admin record carries the emulator-shaped `providerUserInfo`","status":"conforms","evidence":["`unit:auth-gap-surface.test.ts`","packages/pyric/test/auth/auth-gap-surface.test.ts"],"assurance":"eligible"},{"id":"auth#59","kind":"registry-row","surface":"auth","behavior":"`user.metadata.creationTime` / `lastSignInTime`","status":"unsupported","evidence":["client `User.metadata` not exposed (AUTH-GAP); the admin record carries `createdAt`/`lastLoginAt` (ISO)"],"assurance":"ineligible"},{"id":"auth#61","kind":"registry-row","surface":"auth","behavior":"`user.reload()` / `user.delete()` / `user.toJSON()` / `user.refreshToken` / `user.tenantId`","status":"unsupported","evidence":["not modeled by the sandbox; retained as an explicit unsupported behavior row rather than synthesized (AUTH-GAP)"],"assurance":"ineligible"},{"id":"auth#68","kind":"registry-row","surface":"auth","behavior":"`IdTokenResult.signInProvider` reflects the session's provider per flow (`'anonymous'` / `'password'` / `'google.com'` / …); claims include the reserved `firebase.sign_in_provider` (custom claims can't shadow it)","status":"conforms","evidence":["`unit:sandbox-user-admin.test.ts` (\"IdTokenResult.signInProvider\") — prod shape is documented SDK behavior; no oracle capture yet","observation:auth-signinprovider-per-flow","packages/pyric/test/auth/sandbox-user-admin.test.ts"],"assurance":"eligible"},{"id":"auth#75","kind":"registry-row","surface":"auth","behavior":"Custom-claims changes (`sandbox.updateUser` / re-seed) reach an active session on the next FORCED token refresh, not immediately — claims are read live from the user DB at mint time (prod's refresh-propagation story; AUTH-B10)","status":"conforms","evidence":["`unit:sandbox-user-admin.test.ts`, `unit:sandbox-cluster-b9-b12.test.ts`","observation:auth-claims-forced-refresh-propagation","packages/pyric/test/auth/sandbox-cluster-b9-b12.test.ts","packages/pyric/test/auth/sandbox-user-admin.test.ts"],"assurance":"eligible"}]},{"feature":"UserCredential","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"UserCredential is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"auth:type:UserCredential","kind":"type-export","surface":"auth","behavior":"UserCredential is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"UserInfo","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"UserInfo is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"auth:type:UserInfo","kind":"type-export","surface":"auth","behavior":"UserInfo is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"UserMetadata","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"UserMetadata is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:UserMetadata","kind":"type-export","surface":"auth","behavior":"UserMetadata is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"UserProfile","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"UserProfile is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"auth:type:UserProfile","kind":"type-export","surface":"auth","behavior":"UserProfile is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"validatePassword","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"validatePassword is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:validatePassword","kind":"runtime-export","surface":"auth","behavior":"validatePassword is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#174","kind":"registry-row","surface":"auth","behavior":"Returns a `PasswordValidationStatus` against the project's password policy, WITHOUT attempting a sign-up (so a UI can show live strength feedback). The sandbox's policy is `minPasswordLength: 6`, `maxPasswordLength: 4096`, `enforcementState: 'ENFORCE'`, with every character-class requirement UNSET — so a password this function calls valid is exactly one `createUserWithEmailAndPassword` will accept. The character-class fields are `undefined`, not `false`: upstream distinguishes 'not required' from 'required and unmet', and reporting `false` would claim the password failed a rule the project never had.","status":"conforms","evidence":["ORACLE-BACKED: `auth-validatepassword-status-shape` captured prod's live policy (minPasswordLength 6, maxPasswordLength 4096, ENFORCE, character classes unset) and the status shape for a weak and a strong password. Replayed in `unit:oracle-conformance.test.ts`. The 6-char minimum agrees with the separately oracle-pinned `auth/weak-password` threshold on the create path, so the two surfaces draw the same line here exactly as they do in prod.","observation:auth-validatepassword-status-shape","packages/pyric/test/auth/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"vector","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"vector is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:vector","kind":"runtime-export","surface":"firestore","behavior":"vector is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#111","kind":"registry-row","surface":"firestore","behavior":"Vector value type (`vector()` + `VectorValue`) round-trip: a vector written via `setDoc` reads back as a `VectorValue` with the same components","status":"conforms","evidence":["`unit:sandbox-target.test.ts` (\"Bytes + GeoPoint + VectorValue round-trip\", top-level + nested). The locally owned `vector()` / `VectorValue` preserve Firebase's observable value shape; the sandbox converter stores the rules `Vector` wrapper and `pyric/firestore` finalizes reads back to `VectorValue`. Oracle observation to follow (cf. #109/#110). **CLIENT surface only:** the web SDK exposes `vector()` + `VectorValue` (read/write) but has NO `findNearest` and NO `FieldValue.vector`; vector SEARCH is admin/server-only (`firebase-admin` `Query`/`CollectionReference.findNearest` + `FieldValue.vector()`), out of scope for this client matrix; the admin surface is tracked in the design rationale.","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"VectorValue","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"VectorValue is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:VectorValue","kind":"runtime-export","surface":"firestore","behavior":"VectorValue is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore:type:VectorValue","kind":"type-export","surface":"firestore","behavior":"VectorValue is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#111","kind":"registry-row","surface":"firestore","behavior":"Vector value type (`vector()` + `VectorValue`) round-trip: a vector written via `setDoc` reads back as a `VectorValue` with the same components","status":"conforms","evidence":["`unit:sandbox-target.test.ts` (\"Bytes + GeoPoint + VectorValue round-trip\", top-level + nested). The locally owned `vector()` / `VectorValue` preserve Firebase's observable value shape; the sandbox converter stores the rules `Vector` wrapper and `pyric/firestore` finalizes reads back to `VectorValue`. Oracle observation to follow (cf. #109/#110). **CLIENT surface only:** the web SDK exposes `vector()` + `VectorValue` (read/write) but has NO `findNearest` and NO `FieldValue.vector`; vector SEARCH is admin/server-only (`firebase-admin` `Query`/`CollectionReference.findNearest` + `FieldValue.vector()`), out of scope for this client matrix; the admin surface is tracked in the design rationale.","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"verifyBeforeUpdateEmail","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"verifyBeforeUpdateEmail is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:verifyBeforeUpdateEmail","kind":"runtime-export","surface":"auth","behavior":"verifyBeforeUpdateEmail is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#157","kind":"registry-row","surface":"auth","behavior":"Mails a code to the NEW address and returns. The account's email does NOT change until that code is redeemed — the single guarantee separating this API from a bare `updateEmail`: the user must prove control of the new address before it becomes theirs. On redemption the account moves and the new address arrives `emailVerified: true`. `checkActionCode` on the code reports `data.email` = the new address and `data.previousEmail` = the old one.","status":"conforms","evidence":["UNIT-BACKED, not oracle-backed, and the reason is recorded rather than hidden: the probe (`auth-verifybeforeupdateemail-shape`) ran against the real project and came back `auth/operation-not-allowed` on every arm, because the oracle project has the Email/Password provider DISABLED and the probe could not even create the user whose email it would change. The capture is committed showing exactly that. Behavior is proven end to end against the sandbox in `unit:sandbox-email-link.test.ts`.","observation:auth-verifybeforeupdateemail-shape","packages/pyric/test/auth/sandbox-email-link.test.ts","packages/pyric/test/auth/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"verifyPasswordResetCode","surface":"auth","importPaths":["pyric/auth"],"evidenceSlug":"auth-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"verifyPasswordResetCode is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"auth:runtime:verifyPasswordResetCode","kind":"runtime-export","surface":"auth","behavior":"verifyPasswordResetCode is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"auth#159","kind":"registry-row","surface":"auth","behavior":"`checkActionCode` and `verifyPasswordResetCode` INSPECT a code without burning it — a check must not destroy the code the subsequent apply needs. `confirmPasswordReset` redeems it and sets the password, running the same strength check `createUserWithEmailAndPassword` runs; a weak new password throws `auth/weak-password` and does NOT burn the code (a typo must not destroy the user's one reset link). A code staged as expired throws `auth/expired-action-code`.","status":"conforms","evidence":["UNIT-BACKED, stated honestly: these three endpoints answered `auth/operation-not-allowed` in the oracle run (`auth-action-code-invalid`) because the oracle project's disabled password provider replies before the invalid-code contract can. That is a fact about the project's configuration, not about the API, so it is NOT asserted as evidence. The error codes used here are matched to the oracle-CAPTURED `AuthErrorCodes` map (`INVALID_OOB_CODE = auth/invalid-action-code`, `EXPIRED_OOB_CODE = auth/expired-action-code` — see auth#172). Behavior proven in `unit:sandbox-email-link.test.ts`.","packages/pyric/test/auth/sandbox-email-link.test.ts"],"assurance":"eligible"}]},{"feature":"VertexAIBackend","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"VertexAIBackend is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"ai:runtime:VertexAIBackend","kind":"runtime-export","surface":"ai","behavior":"VertexAIBackend is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai:type:VertexAIBackend","kind":"type-export","surface":"ai","behavior":"VertexAIBackend is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"ai#backend-vertex","kind":"registry-row","surface":"ai","behavior":"`VertexAIBackend` carries `backendType` `VERTEX_AI`; its location and the resulting AI handle location default to `us-central1`","status":"conforms","evidence":["`unit:instances.test.ts` test `ai#backend-vertex` (matches upstream constructor default)","packages/pyric/test/ai/instances.test.ts"],"assurance":"eligible"}]},{"feature":"VideoMetadata","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"VideoMetadata is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:VideoMetadata","kind":"type-export","surface":"ai","behavior":"VideoMetadata is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"VoiceConfig","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"VoiceConfig is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:VoiceConfig","kind":"type-export","surface":"ai","behavior":"VoiceConfig is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"waitForPendingWrites","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"diverged","assurance":"qualified","summary":"waitForPendingWrites is available, has diverged fidelity, and is qualified for assurance.","caveats":["Resolves immediately in the sandbox mirror — every accepted write is already committed locally by the time its own promise resolves, so there are never writes still pending a server round-trip","`unit:firestore/persistence-network.test.ts`"],"claims":[{"id":"firestore:runtime:waitForPendingWrites","kind":"runtime-export","surface":"firestore","behavior":"waitForPendingWrites is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#144","kind":"registry-row","surface":"firestore","behavior":"Resolves immediately in the sandbox mirror — every accepted write is already committed locally by the time its own promise resolves, so there are never writes still pending a server round-trip","status":"diverged-documented","evidence":["`unit:firestore/persistence-network.test.ts`","packages/pyric/test/firestore/persistence-network.test.ts"],"assurance":"qualified"}]},{"feature":"WebAttribution","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"WebAttribution is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"ai:type:WebAttribution","kind":"type-export","surface":"ai","behavior":"WebAttribution is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"WebGroundingChunk","surface":"ai","importPaths":["pyric/ai"],"evidenceSlug":"ai-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"WebGroundingChunk is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"ai:type:WebGroundingChunk","kind":"type-export","surface":"ai","behavior":"WebGroundingChunk is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"WebpushConfig","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"WebpushConfig is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#18","kind":"registry-row","surface":"messaging-admin","behavior":"Webpush overrides. Production accepts a webpush config carrying `headers.TTL` and `fcmOptions.link`; a non-numeric `headers.TTL` is rejected with an error envelope.","status":"conforms","evidence":["oracle: `messaging-send-webpush-config-accepted.json` (accepted) + `messaging-send-webpush-invalid-ttl-error-envelope.json` (bad TTL rejected). Replayed by the conformance suite.","observation:messaging-send-webpush-config-accepted","observation:messaging-send-webpush-invalid-ttl-error-envelope","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"WebpushFcmOptions","surface":"messaging-admin","importPaths":["pyric-admin/messaging"],"evidenceSlug":"messaging-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"WebpushFcmOptions is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"messaging-admin#19","kind":"registry-row","surface":"messaging-admin","behavior":"Webpush FCM options (`link`, HTTPS required). Production accepts `fcmOptions.link` on a webpush send.","status":"conforms","evidence":["oracle: `messaging-send-webpush-config-accepted.json` (link accepted). Replayed by the conformance suite.","observation:messaging-send-webpush-config-accepted","packages/pyric-admin/test/messaging/oracle-conformance.test.ts"],"assurance":"eligible"}]},{"feature":"where","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"where is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:where","kind":"runtime-export","surface":"firestore","behavior":"where is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#54","kind":"registry-row","surface":"firestore","behavior":"`query(coll, where(…), orderBy(…), limit(…))` composes constraints in order","status":"conforms","evidence":["`unit:sandbox-target.test.ts`, `playground:firestore-query`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#55","kind":"registry-row","surface":"firestore","behavior":"`where(field, op, value)` — all 10 ops: `<`, `<=`, `==`, `>=`, `>`, `!=`, `in`, `not-in`, `array-contains`, `array-contains-any`","status":"conforms","evidence":["`unit:sandbox-target.test.ts` (canonical query test); membership ops + OR/`in`/`array-contains` composites: `unit:upstream-query-probes.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts","packages/pyric/test/firestore/upstream-query-probes.test.ts"],"assurance":"eligible"},{"id":"firestore#59c","kind":"registry-row","surface":"firestore","behavior":"**Implicit orderBy + `__name__` tiebreak (FS-B8)** — the query's sort is normalized to: explicit orderBy clauses, then an implicit order on each inequality-filtered field, then a final document-key (`__name__`) clause. Equal-valued docs sort deterministically by key; a `where('x','>',v)` with no explicit orderBy returns docs ordered by `x`. Mirrors `clones/.../core/query.ts:queryNormalizedOrderBy`. Pre-FS-B8 equal-valued docs were nondeterministic and inequality results came back in insertion order.","status":"conforms","evidence":["`unit:admin-compat/implicit-order-name.test.ts` (key tiebreak, snapshot-cursor disambiguation, implicit inequality order; verified failing pre-fix)","packages/pyric/test/sandbox/firestore/admin-compat/implicit-order-name.test.ts"],"assurance":"eligible"},{"id":"firestore#65","kind":"registry-row","surface":"firestore","behavior":"Chained queries re-tag for further constraints (`query(query(coll, where), orderBy)`)","status":"conforms","evidence":["`unit:sandbox-target.test.ts` (\"chained queries are taggable\")","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"}]},{"feature":"WhereFilterOp","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"not-applicable","assurance":"not-applicable","summary":"WhereFilterOp is available, has no applicable behavior claim, and has no assurance classification.","caveats":[],"claims":[{"id":"firestore:type:WhereFilterOp","kind":"type-export","surface":"firestore","behavior":"WhereFilterOp is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"withConverter","surface":"firestore","importPaths":[],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"withConverter is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore#46","kind":"registry-row","surface":"firestore","behavior":"`withConverter(docRef, converter)` returns a shell that runs `toFirestore` on writes, `fromFirestore` on reads","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#47","kind":"registry-row","surface":"firestore","behavior":"`withConverter(collRef, converter)` propagates onto `doc(typedColl, id)`","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#48","kind":"registry-row","surface":"firestore","behavior":"`withConverter(collRef, converter)` propagates through `query(typedColl, …)` + `getDocs()`","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#49","kind":"registry-row","surface":"firestore","behavior":"`withConverter(ref, null)` strips the converter, returns the underlying untyped view","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#50","kind":"registry-row","surface":"firestore","behavior":"Original untyped ref keeps its identity after `withConverter(ref, c)` (two views, one path)","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#51","kind":"registry-row","surface":"firestore","behavior":"`setDoc` through a converted ref invokes `toFirestore(data)`","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#52","kind":"registry-row","surface":"firestore","behavior":"`getDoc` through a converted ref invokes `fromFirestore(snapshot)`; `.data()` returns the typed model","status":"conforms","evidence":["`unit:sandbox-target.test.ts`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#53","kind":"registry-row","surface":"firestore","behavior":"`updateDoc` through a converted ref does NOT invoke the converter","status":"conforms","evidence":["(documented constraint; matches JS SDK)"],"assurance":"eligible"}]},{"feature":"WithFieldValue","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"unavailable","fidelity":"not-applicable","assurance":"not-applicable","summary":"WithFieldValue is unavailable; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["Public type export is not mirrored."],"claims":[{"id":"firestore:type:WithFieldValue","kind":"type-export","surface":"firestore","behavior":"WithFieldValue is missing from the Pyric type namespace","status":"unmapped","evidence":[],"assurance":"not-applicable"}]},{"feature":"writeBatch","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"available","fidelity":"conforms","assurance":"eligible","summary":"writeBatch is available, has conforms fidelity, and is eligible for assurance.","caveats":[],"claims":[{"id":"firestore:runtime:writeBatch","kind":"runtime-export","surface":"firestore","behavior":"writeBatch is exported by the Pyric mirror","status":"mapped","evidence":[],"assurance":"not-applicable"},{"id":"firestore#95","kind":"registry-row","surface":"firestore","behavior":"`batch.set` / `batch.update` / `batch.delete` queue mutations","status":"conforms","evidence":["`unit:sandbox-target.test.ts`, `playground:firestore-batch`","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#96","kind":"registry-row","surface":"firestore","behavior":"`batch.commit()` applies all queued writes atomically — success path commits all queued mutations together; failure path (one write violating rules) rejects the **whole** batch with no partial application","status":"conforms","evidence":["`unit:sandbox-target.test.ts`, oracle: `packages/conformance/observations/firestore/firestore-row-96-batch-commit-atomic.json` — success path: a batch with `set` (fresh doc), `update` (existing doc), and `delete` (existing doc) all land in a single commit (`allApplied: true`). Failure path: a batch with one write targeting a path **outside** `pyric_oracle/*` rejects with `code: 'permission-denied'` and leaves the would-have-set doc absent and the would-have-updated doc at its original value (`noPartialApply: true`) — atomicity verified end-to-end.","observation:firestore-row-96-batch-commit-atomic","packages/pyric/test/firestore/sandbox-target.test.ts"],"assurance":"eligible"},{"id":"firestore#97","kind":"registry-row","surface":"firestore","behavior":"Batch is tagged on construction and remains bound to the sandbox owner that created it","status":"conforms","evidence":["(implementation invariant; cross-sandbox ownership is not directly probed)"],"assurance":"eligible"},{"id":"firestore#98","kind":"registry-row","surface":"firestore","behavior":"Batch identity is frozen at construction (per current implementation)","status":"conforms","evidence":["(documented invariant)"],"assurance":"eligible"}]},{"feature":"WriteBatch","surface":"firestore","importPaths":["pyric/firestore"],"evidenceSlug":"firestore-compat","availability":"deferred","fidelity":"not-applicable","assurance":"not-applicable","summary":"WriteBatch is deferred; behavior fidelity and assurance are not applicable until the surface exists.","caveats":["These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors."],"claims":[{"id":"firestore:runtime:WriteBatch","kind":"runtime-export","surface":"firestore","behavior":"These Firebase classes and constraint objects are present in Pyric's type surface but are not exported as runtime constructor values. Runtime identity and instanceof-compatible tokens remain unbuilt and cannot be credited by type-only mirrors.","status":"deferred","evidence":["upstream:firebase/firestore"],"assurance":"not-applicable"},{"id":"firestore:type:WriteBatch","kind":"type-export","surface":"firestore","behavior":"WriteBatch is exported in the Pyric type namespace","status":"mapped","evidence":[],"assurance":"not-applicable"}]}];
13
+ export const CONFORMANCE_IMPORT_EVIDENCE: readonly ImportEvidence[] = [{"importPath":"pyric-admin/messaging","surface":"messaging-admin","evidenceSlug":"messaging-compat"},{"importPath":"pyric/ai","surface":"ai","evidenceSlug":"ai-compat"},{"importPath":"pyric/app","surface":"app","evidenceSlug":"app-compat"},{"importPath":"pyric/auth","surface":"auth","evidenceSlug":"auth-compat"},{"importPath":"pyric/database","surface":"rtdb","evidenceSlug":"database-compat"},{"importPath":"pyric/firestore","surface":"firestore","evidenceSlug":"firestore-compat"},{"importPath":"pyric/messaging","surface":"messaging","evidenceSlug":"messaging-compat"},{"importPath":"pyric/messaging/sw","surface":"messaging","evidenceSlug":"messaging-compat"},{"importPath":"pyric/rules","surface":"firestore-rules","evidenceSlug":"rules-compat"},{"importPath":"pyric/storage","surface":"storage","evidenceSlug":"storage-compat"}];
14
+
15
+ export interface QueryableFeatureSupport {
16
+ feature: string;
17
+ surface: string;
18
+ importPaths?: readonly string[];
19
+ }
20
+
21
+ export type CanIUseMatch = 'exact' | 'ambiguous' | 'suggestions' | 'none';
22
+
23
+ export interface CanIUseResult<T extends QueryableFeatureSupport> {
24
+ query: string;
25
+ match: CanIUseMatch;
26
+ supports: readonly T[];
27
+ }
28
+
29
+ export interface CanIUseOptions {
30
+ /** Restrict the answer to features exposed through this published import. */
31
+ importPath?: string;
32
+ }
33
+
34
+ export interface QueryableImportEvidence {
35
+ importPath: string;
36
+ }
37
+
38
+ /** Resolve the canonical compatibility-page association for a published
39
+ * import. An exact lookup prevents docs generators from maintaining a second
40
+ * import-to-evidence map. */
41
+ export function resolveImportEvidence<T extends QueryableImportEvidence>(
42
+ evidence: readonly T[],
43
+ importPath: string,
44
+ ): T | undefined {
45
+ return evidence.find((entry) => entry.importPath === importPath);
46
+ }
47
+
48
+ export function normalizeFeature(value: string): string {
49
+ return value.trim().replace(/\(.*\)$/, '').replace(/[\s_-]+/g, '').toLowerCase();
50
+ }
51
+
52
+ function normalizeSurface(value: string): string {
53
+ return value.trim().replace(/[\s_-]+/g, '-').toLowerCase();
54
+ }
55
+
56
+ function levenshtein(left: string, right: string): number {
57
+ const row = Array.from({ length: right.length + 1 }, (_, index) => index);
58
+ for (let i = 1; i <= left.length; i++) {
59
+ let diagonal = row[0]!;
60
+ row[0] = i;
61
+ for (let j = 1; j <= right.length; j++) {
62
+ const prior = row[j]!;
63
+ row[j] = Math.min(row[j]! + 1, row[j - 1]! + 1, diagonal + (left[i - 1] === right[j - 1] ? 0 : 1));
64
+ diagonal = prior;
65
+ }
66
+ }
67
+ return row[right.length]!;
68
+ }
69
+
70
+ /** The one authored feature-query implementation. Canonical model consumers
71
+ * call it directly; the CLI build copies this source into its ignored data
72
+ * projection so the published package has no private workspace dependency. */
73
+ export function resolveCanIUse<T extends QueryableFeatureSupport>(
74
+ supports: readonly T[],
75
+ query: string,
76
+ options: CanIUseOptions = {},
77
+ ): CanIUseResult<T> {
78
+ const importPath = options.importPath;
79
+ const scopedSupports = importPath !== undefined
80
+ ? supports.filter((support) => support.importPaths?.includes(importPath))
81
+ : supports;
82
+ const slash = query.indexOf('/');
83
+ const colon = query.indexOf(':');
84
+ const separator = slash > 0 ? slash : colon > 0 ? colon : -1;
85
+ const delimiter = separator > 0 ? query[separator] : undefined;
86
+ const requestedSurfaceIdentity = separator > 0 ? query.slice(0, separator) : undefined;
87
+ const requestedSurface = requestedSurfaceIdentity ? normalizeSurface(requestedSurfaceIdentity) : undefined;
88
+ const requestedFeature = separator > 0 ? query.slice(separator + 1) : query;
89
+ const normalized = normalizeFeature(requestedFeature);
90
+ if (!normalized) return { query, match: 'none', supports: [] };
91
+ const candidates = scopedSupports.filter((support) =>
92
+ (!requestedSurface || normalizeSurface(support.surface) === requestedSurface) && normalizeFeature(support.feature) === normalized,
93
+ );
94
+ const exactCandidates = candidates.filter((support) =>
95
+ support.feature === requestedFeature
96
+ && (!requestedSurfaceIdentity || (delimiter === '/' && support.surface === requestedSurfaceIdentity)),
97
+ );
98
+ if (exactCandidates.length > 0) {
99
+ return { query, match: exactCandidates.length === 1 ? 'exact' : 'ambiguous', supports: exactCandidates };
100
+ }
101
+ if (candidates.length > 0) {
102
+ return { query, match: 'suggestions', supports: candidates };
103
+ }
104
+
105
+ const suggestions = scopedSupports
106
+ .filter((support) => !requestedSurface || normalizeSurface(support.surface) === requestedSurface)
107
+ .map((support) => {
108
+ const name = normalizeFeature(support.feature);
109
+ const score = name.startsWith(normalized) ? 0 : name.includes(normalized) ? 1 : 2 + levenshtein(normalized, name);
110
+ return { support, score };
111
+ })
112
+ .filter(({ score }) => score <= Math.max(4, Math.ceil(normalized.length / 3) + 2))
113
+ .sort((a, b) => a.score - b.score || a.support.feature.localeCompare(b.support.feature) || a.support.surface.localeCompare(b.support.surface))
114
+ .slice(0, 8)
115
+ .map(({ support }) => support);
116
+ return { query, match: suggestions.length > 0 ? 'suggestions' : 'none', supports: suggestions };
117
+ }