{"_id":"@coderifts/prove","_rev":"14-3e23ff493f00231a0f9eb5d8c0a62c64","name":"@coderifts/prove","dist-tags":{"latest":"0.1.13"},"versions":{"0.1.0":{"name":"@coderifts/prove","version":"0.1.0","license":"MIT","_id":"@coderifts/prove@0.1.0","maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"bin":{"coderifts-prove":"bin/prove-all.js"},"dist":{"shasum":"cac931d39aaf8e8e57cd94f1f1478f057f3d4683","tarball":"https://registry.npmjs.org/@coderifts/prove/-/prove-0.1.0.tgz","fileCount":45,"integrity":"sha512-2LNVQBcAsF0MwuqMxxoPb25bau9F4W15+8Mq30lpan+3ib+Osr8xa46/d7SjkSk4V+lM2guuByjODBkFO1pb8A==","signatures":[{"sig":"MEQCIGw0nCGlajl9VawX+8IeFqKKfeLmeqSTFAeBhbAlCYjQAiAg3fBit7Z7aeIeoBCRyRTOKTHisH2+V5DfUhIRFjv53g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":532175},"engines":{"node":">=20"},"gitHead":"a7151d16dfc74385205141edce1b3fd59376a86f","private":false,"scripts":{"test":"node --test \"packages/middleware/test/*.test.js\"","prove":"node demo/prove.js","test:pg":"node --test --test-concurrency=1 \"demo/test/*.test.js\"","test:all":"npm test && npm run test:pg","prove:all":"node bin/prove-all.js","prove:check":"node bin/prove-all.js --check"},"_npmUser":{"name":"zsobpeter","email":"zsobpeter@gmail.com"},"workspaces":["packages/middleware","demo"],"_npmVersion":"11.6.2","description":"Reference offline enforcement for cr.exec.v1 execution grants + a demo API where mutation without a grant is 403.","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/prove_0.1.0_1788518464669_0.9973086242497684","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@coderifts/prove","version":"0.1.1","license":"MIT","_id":"@coderifts/prove@0.1.1","maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"bin":{"coderifts-prove":"bin/prove-all.js"},"dist":{"shasum":"78d010a39d45517576ad44d38467da3f94eaf145","tarball":"https://registry.npmjs.org/@coderifts/prove/-/prove-0.1.1.tgz","fileCount":45,"integrity":"sha512-DH6v6LN6x/uJIZ1nACR1dtNbt/8PJbeB08tTnhoB6IS2C4gQ7DdLSYiV/ZF8sLhpU833e/qxWZNUMDVOOsBbqg==","signatures":[{"sig":"MEUCIQD8MTyrzjxe0MN739NM4PDlSADsvaSz1QdCsb+hy4FwBAIgFZ274Ttv+G6qk+YssF0JC3xvr7K++IRU0ql5rnajZ38=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":535634},"engines":{"node":">=20"},"gitHead":"188479a15ecb2f4ef57f437d0cec67d94e3598fd","private":false,"scripts":{"test":"node --test \"packages/middleware/test/*.test.js\"","prove":"node demo/prove.js","test:pg":"node --test --test-concurrency=1 \"demo/test/*.test.js\"","test:all":"npm test && npm run test:pg","prove:all":"node bin/prove-all.js","prove:check":"node bin/prove-all.js --check"},"_npmUser":{"name":"zsobpeter","email":"zsobpeter@gmail.com"},"workspaces":["packages/middleware","demo"],"_npmVersion":"11.6.2","description":"Reference offline enforcement for cr.exec.v1 execution grants + a demo API where mutation without a grant is 403.","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/prove_0.1.1_1788540873604_0.10774398588953527","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@coderifts/prove","version":"0.1.2","license":"MIT","_id":"@coderifts/prove@0.1.2","maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"bin":{"coderifts-prove":"bin/prove-all.js"},"dist":{"shasum":"735040706d9a4e79dfc3ac19ebfec6d947afd74a","tarball":"https://registry.npmjs.org/@coderifts/prove/-/prove-0.1.2.tgz","fileCount":46,"integrity":"sha512-Jr/Q8ayXuRXp3E8myld5RiIq8jO0RvsLHrKwR3OzIpKH4pxeMRfM8r7Rmi0agro83TTLw8TBYSbN9m7fLp2wRw==","signatures":[{"sig":"MEYCIQCvAhapPT4A3wifl5QMjPQWdhacoQIgjy00X/QC9QDrBAIhAIvb6bFuo2KkXJFy80kaV+d/e29NxWHFtmqTYkiHvSO0","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":550606},"engines":{"node":">=20"},"gitHead":"1edab51ffe488915024c9083f0332adcbae7e881","private":false,"scripts":{"test":"node --test \"packages/middleware/test/*.test.js\"","prove":"node demo/prove.js","test:pg":"node --test --test-concurrency=1 \"demo/test/*.test.js\"","test:all":"npm test && npm run test:pg","prove:all":"node bin/prove-all.js","prove:check":"node bin/prove-all.js --check"},"_npmUser":{"name":"zsobpeter","email":"zsobpeter@gmail.com"},"workspaces":["packages/middleware","demo"],"_npmVersion":"11.6.2","description":"Reference offline enforcement for cr.exec.v1 execution grants + a demo API where mutation without a grant is 403.","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/prove_0.1.2_1788605023587_0.6276917895781637","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"name":"@coderifts/prove","version":"0.1.3","license":"MIT","_id":"@coderifts/prove@0.1.3","maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"bin":{"coderifts-prove":"bin/prove-all.js"},"dist":{"shasum":"f16ce7944d5b98c505f7f0b24065e0b84e25643a","tarball":"https://registry.npmjs.org/@coderifts/prove/-/prove-0.1.3.tgz","fileCount":50,"integrity":"sha512-st0Zr1jFQSUumMTrs6oj2Q3xo6D8nhtJPNCTFx7X2ppMcb6+bL4LBl8qFyXBAo+Oeyte6LJfVP+FXDEgZltI3Q==","signatures":[{"sig":"MEUCIQDs1YndQ0CeONnGQDJItnawpAJE3Zg9VMg8Zr4JZrSdCwIgJTqc0yOFpg4YVlZIY95jZd9jZ3PaSVZkiRPpKjNNrD0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":571566},"engines":{"node":">=20"},"gitHead":"7d5399e49401733bb318b1e1feffb519af2d6965","private":false,"scripts":{"test":"node --test \"packages/middleware/test/*.test.js\"","prove":"node demo/prove.js","test:pg":"node --test --test-concurrency=1 \"demo/test/*.test.js\"","test:all":"npm test && npm run test:pg","prove:all":"node bin/prove-all.js","prove:check":"node bin/prove-all.js --check"},"_npmUser":{"name":"zsobpeter","email":"zsobpeter@gmail.com"},"workspaces":["packages/middleware","demo"],"_npmVersion":"11.6.2","description":"Reference offline enforcement for cr.exec.v1 execution grants + a demo API where mutation without a grant is 403.","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/prove_0.1.3_1788635221409_0.9194895461069184","host":"s3://npm-registry-packages-npm-production"}},"0.1.4":{"name":"@coderifts/prove","version":"0.1.4","license":"MIT","_id":"@coderifts/prove@0.1.4","maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"bin":{"coderifts-prove":"bin/prove-all.js"},"dist":{"shasum":"3db974a27136346bd9f54dac8c6af6c01a142885","tarball":"https://registry.npmjs.org/@coderifts/prove/-/prove-0.1.4.tgz","fileCount":54,"integrity":"sha512-0NnKpcTN5G6vgzAMCFMsMTlPW7EcCelUPjHaLc0l/K4Db0YfqiTuGh8eiWZxCgp0P+hGLSPTw2iTU2ODXbuFjw==","signatures":[{"sig":"MEQCIERN7q0t5/RfNJp9n3zZp8gI4ygPxhuUfUGmh0o7SaKCAiBli/Pos7g4PPs39Pu07mklb+vT9vDunOLO8nAfAiUwzg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":642714},"engines":{"node":">=20"},"gitHead":"46c034fffc862d1808b4cba30d11b9f9c4b8c23b","private":false,"scripts":{"test":"node --test \"packages/middleware/test/*.test.js\"","prove":"node demo/prove.js","test:pg":"node --test --test-concurrency=1 \"demo/test/*.test.js\"","test:all":"npm test && npm run test:pg","prove:all":"node bin/prove-all.js","prove:check":"node bin/prove-all.js --check"},"_npmUser":{"name":"zsobpeter","email":"zsobpeter@gmail.com"},"workspaces":["packages/middleware","demo"],"_npmVersion":"11.6.2","description":"Reference offline enforcement for cr.exec.v1 execution grants + a demo API where mutation without a grant is 403.","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/prove_0.1.4_1788690033474_0.9049382639176284","host":"s3://npm-registry-packages-npm-production"}},"0.1.5":{"name":"@coderifts/prove","version":"0.1.5","license":"MIT","_id":"@coderifts/prove@0.1.5","maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"bin":{"coderifts-prove":"bin/prove-all.js"},"dist":{"shasum":"d373a36c94ad3994598e3a8b6de0d86c56a0ae99","tarball":"https://registry.npmjs.org/@coderifts/prove/-/prove-0.1.5.tgz","fileCount":55,"integrity":"sha512-v2WYIJmGfRY+4X1BZZDzpxS2FPvDU7meUaAd/GlpdUPxYqK2aIV7+YGFbFvAazY/QwPi5B+YrGS06/JP94vYAA==","signatures":[{"sig":"MEUCICpDLGzIZFuDlnfrhNOTW/xnfehetAUFfdZaWnAOEeR2AiEA7ycFCThlZvuY8Pbb898F4o1QcR340FtliHeuRp7vDvM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":651368},"engines":{"node":">=20"},"gitHead":"9a34ea1c274655af14622003559adf8daed4c15c","private":false,"scripts":{"test":"node --test \"packages/middleware/test/*.test.js\"","prove":"node demo/prove.js","test:pg":"node --test --test-concurrency=1 \"demo/test/*.test.js\"","test:all":"npm test && npm run test:pg","prove:all":"node bin/prove-all.js","prove:check":"node bin/prove-all.js --check","check:packed":"node scripts/check-packed-sample.js","prepublishOnly":"node scripts/check-packed-sample.js"},"_npmUser":{"name":"zsobpeter","email":"zsobpeter@gmail.com"},"workspaces":["packages/middleware","demo"],"_npmVersion":"11.6.2","description":"Reference offline enforcement for cr.exec.v1 execution grants + a demo API where mutation without a grant is 403.","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/prove_0.1.5_1788700991590_0.945958778314826","host":"s3://npm-registry-packages-npm-production"}},"0.1.6":{"name":"@coderifts/prove","version":"0.1.6","license":"MIT","_id":"@coderifts/prove@0.1.6","maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"bin":{"coderifts-prove":"bin/prove-all.js"},"dist":{"shasum":"c4ba685984ea7873306b0b2bdcf934c6fe60ec94","tarball":"https://registry.npmjs.org/@coderifts/prove/-/prove-0.1.6.tgz","fileCount":58,"integrity":"sha512-MLr9V9DmfMWsUQ5nKDok10uka9n3zeS82aWCg/tcptB2ByaHA7a6u5PPYIn/17MDPGZ2IbkfuzT9oJ9mdyW9lw==","signatures":[{"sig":"MEUCIQCwiGnUOoBVNcwTUa6BK5C5BIbz5rBRlbmUze1LZ5cHtgIgRSLPFFSJX8xu8e4oEMsQGAXsYj2oBm9btk0holh0hv4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":689985},"engines":{"node":">=20"},"gitHead":"a2fc1968ab9af7baf0769ca7a6fa29b26342fa25","private":false,"scripts":{"test":"node --test \"packages/middleware/test/*.test.js\"","prove":"node demo/prove.js","test:pg":"node --test --test-concurrency=1 \"demo/test/*.test.js\"","test:all":"npm test && npm run test:pg","prove:all":"node bin/prove-all.js","prove:check":"node bin/prove-all.js --check","check:packed":"node scripts/check-packed-sample.js","prepublishOnly":"node scripts/check-packed-sample.js"},"_npmUser":{"name":"zsobpeter","email":"zsobpeter@gmail.com"},"workspaces":["packages/middleware","demo"],"_npmVersion":"11.6.2","description":"Reference offline enforcement for cr.exec.v1 execution grants + a demo API where mutation without a grant is 403.","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/prove_0.1.6_1788718954256_0.5919534750987743","host":"s3://npm-registry-packages-npm-production"}},"0.1.7":{"name":"@coderifts/prove","version":"0.1.7","license":"MIT","_id":"@coderifts/prove@0.1.7","maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"bin":{"coderifts-prove":"bin/prove-all.js"},"dist":{"shasum":"ed07b61c251591682d44513d756e68b572e8c29a","tarball":"https://registry.npmjs.org/@coderifts/prove/-/prove-0.1.7.tgz","fileCount":59,"integrity":"sha512-3tl9k3AJ5sS/EWCvPXC546t2/J/FgnGOJ9nw8aBMnsCXeiL7J8pNQCh3C5JKv2V04kvm0C/F1c2bY5/5ln0mTw==","signatures":[{"sig":"MEUCIDec+u7x3kf01imiw/Qyf/PGYtaqLBY++iPd/QYAv2EJAiEA8yjUlo6jj5uBmpDsoIYQ33AsC5sE5pjIfQAHbTfFs4c=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":718212},"engines":{"node":">=20"},"gitHead":"03cc15f2d1c92a9a30e4ce362a70b7f2200ef2bd","private":false,"scripts":{"test":"node --test \"packages/middleware/test/*.test.js\"","prove":"node demo/prove.js","test:pg":"node --test --test-concurrency=1 \"demo/test/*.test.js\"","test:all":"npm test && npm run test:pg","prove:all":"node bin/prove-all.js","prove:check":"node bin/prove-all.js --check","check:packed":"node scripts/check-packed-sample.js","prepublishOnly":"npm run test:all && node scripts/check-packed-sample.js"},"_npmUser":{"name":"zsobpeter","email":"zsobpeter@gmail.com"},"workspaces":["packages/middleware","demo"],"_npmVersion":"11.6.2","description":"Reference offline enforcement for cr.exec.v1 execution grants + a demo API where mutation without a grant is 403.","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/prove_0.1.7_1788772041242_0.02347697112505731","host":"s3://npm-registry-packages-npm-production"}},"0.1.8":{"name":"@coderifts/prove","version":"0.1.8","license":"MIT","_id":"@coderifts/prove@0.1.8","maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"bin":{"coderifts-prove":"bin/prove-all.js"},"dist":{"shasum":"f6f92f0be4ba8f3b5298a3a2dc16b2de6e54151b","tarball":"https://registry.npmjs.org/@coderifts/prove/-/prove-0.1.8.tgz","fileCount":62,"integrity":"sha512-DpQe3uWAVkZrsn3uD4jDQYWS07sIsnLPUze7u+wp1CKtESCzR7xmt2c7Eii8q1YdRnSQ5W5vBU4/zPOQ8ZcJxQ==","signatures":[{"sig":"MEYCIQCOd+x8g9dib6MugcpmSSvTOxS6McfYKml8vyXHnMvODwIhAKDQfuoAHNHaaPej/67JqCgWWPb+PrQBsAgh10nOhVeI","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":771694},"engines":{"node":">=20"},"gitHead":"48deb3ef23574fa34f623442bb899b260ba300c6","private":false,"scripts":{"test":"node --test \"packages/middleware/test/*.test.js\"","prove":"node demo/prove.js","fixture":"node scripts/make-conformance-fixture.js","test:pg":"node --test --test-concurrency=1 \"demo/test/*.test.js\"","test:all":"npm test && npm run test:pg","prove:all":"node bin/prove-all.js","prove:check":"node bin/prove-all.js --check","check:packed":"node scripts/check-packed-sample.js","prepublishOnly":"npm run test:all && node scripts/check-packed-sample.js"},"_npmUser":{"name":"zsobpeter","email":"zsobpeter@gmail.com"},"workspaces":["packages/middleware","demo"],"_npmVersion":"11.6.2","description":"Reference offline enforcement for cr.exec.v1 execution grants + a demo API where mutation without a grant is 403.","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/prove_0.1.8_1788808395751_0.5347603748129772","host":"s3://npm-registry-packages-npm-production"}},"0.1.9":{"name":"@coderifts/prove","version":"0.1.9","license":"MIT","_id":"@coderifts/prove@0.1.9","maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"bin":{"coderifts-prove":"bin/prove-all.js"},"dist":{"shasum":"dd2bebddd080842589309bf2b0601c9ecbeb7d76","tarball":"https://registry.npmjs.org/@coderifts/prove/-/prove-0.1.9.tgz","fileCount":62,"integrity":"sha512-P8m+0k0jJB/l0mAMXzKBl0xQ6XKQscvbyeePzvcgGCAFVcnSIKxoXeoUOtpLn1RjBABcFM+hDRwkSxk3qYsdww==","signatures":[{"sig":"MEUCIQCng/NvUr1AZgB0m+fTXHLinb3taVlcGrt8T4ARg35buAIgbcu5XnqM1NsfVlUsldQ9pC2sYH8aqcvMtrQRy9YH2QM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":808447},"engines":{"node":">=20"},"gitHead":"2b780512630f2edd365556b0f60ceb5fff846e81","private":false,"scripts":{"test":"node --test \"packages/middleware/test/*.test.js\"","prove":"node demo/prove.js","fixture":"node scripts/make-conformance-fixture.js","test:pg":"node --test --test-concurrency=1 \"demo/test/*.test.js\"","test:all":"npm test && npm run test:pg","prove:all":"node bin/prove-all.js","prove:check":"node bin/prove-all.js --check","check:packed":"node scripts/check-packed-sample.js","prepublishOnly":"npm run test:all && node scripts/check-packed-sample.js"},"_npmUser":{"name":"zsobpeter","email":"zsobpeter@gmail.com"},"workspaces":["packages/middleware","demo"],"_npmVersion":"11.6.2","description":"Reference offline enforcement for cr.exec.v1 execution grants + a demo API where mutation without a grant is 403.","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/prove_0.1.9_1788865247471_0.4719379637680017","host":"s3://npm-registry-packages-npm-production"}},"0.1.10":{"name":"@coderifts/prove","version":"0.1.10","license":"MIT","_id":"@coderifts/prove@0.1.10","maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"bin":{"coderifts-prove":"bin/prove-all.js"},"dist":{"shasum":"53dc8c88a7517e0b0185c980ddf17c048bb7ee06","tarball":"https://registry.npmjs.org/@coderifts/prove/-/prove-0.1.10.tgz","fileCount":64,"integrity":"sha512-UB9R7PeVr7W1Yx5viojlP1cMc9JQgDXpfreqVG3XcHrkle15Oue301TPwyKTrw+appr0rtHJlVNKd0ER650xQA==","signatures":[{"sig":"MEUCIAOulDo5yWF7O2LEEkHLWx2Q/k11clmFw1iZ5xAQ7RG6AiEAlwBNdgGqeI/2bjh8yaOhyEx7WIWMB92/j8Lek5GUguo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":832767},"engines":{"node":">=20"},"gitHead":"682cc950a777513cbeda1f5fa08e32475499b471","private":false,"scripts":{"test":"node --test \"packages/middleware/test/*.test.js\"","prove":"node demo/prove.js","fixture":"node scripts/make-conformance-fixture.js","test:pg":"node --test --test-concurrency=1 \"demo/test/*.test.js\"","test:all":"npm test && npm run test:pg","prove:all":"node bin/prove-all.js","prove:check":"node bin/prove-all.js --check","check:packed":"node scripts/check-packed-sample.js","prepublishOnly":"npm run test:all && node scripts/check-packed-sample.js"},"_npmUser":{"name":"zsobpeter","email":"zsobpeter@gmail.com"},"workspaces":["packages/middleware","demo"],"_npmVersion":"11.6.2","description":"Reference offline enforcement for cr.exec.v1 execution grants + a demo API where mutation without a grant is 403.","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/prove_0.1.10_1788976198144_0.898646510821357","host":"s3://npm-registry-packages-npm-production"}},"0.1.11":{"name":"@coderifts/prove","version":"0.1.11","license":"MIT","_id":"@coderifts/prove@0.1.11","maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"bin":{"coderifts-prove":"bin/prove-all.js"},"dist":{"shasum":"1c73452284cb09d873f3843d1275a28980ab6879","tarball":"https://registry.npmjs.org/@coderifts/prove/-/prove-0.1.11.tgz","fileCount":64,"integrity":"sha512-jAioHwhjDinm8dDqlcJtgusjHTsMEN7oVJp9k3bDhpgMad57Jt4sCaJk+nT9XIpSRya3Rt8R+EOCK5brJD2T5w==","signatures":[{"sig":"MEUCICbK3n9XQvkKp1JEwXz+tIvBC/rwxhAuKz5T8IIHte/ZAiEAw2DG8A0Fbw9pQAiO6GrMQCkz+XEq4aM9wlcGXviQyzI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":834560},"engines":{"node":">=20"},"gitHead":"f3b47bf39c6fa3840f89a6eb9f39d39d3ac8035a","private":false,"scripts":{"test":"node --test \"packages/middleware/test/*.test.js\"","prove":"node demo/prove.js","fixture":"node scripts/make-conformance-fixture.js","test:pg":"node --test --test-concurrency=1 \"demo/test/*.test.js\"","test:all":"npm test && npm run test:pg","prove:all":"node bin/prove-all.js","prove:check":"node bin/prove-all.js --check","check:packed":"node scripts/check-packed-sample.js","prepublishOnly":"npm run test:all && node scripts/check-packed-sample.js"},"_npmUser":{"name":"zsobpeter","email":"zsobpeter@gmail.com"},"workspaces":["packages/middleware","demo"],"_npmVersion":"11.6.2","description":"Reference offline enforcement for cr.exec.v1 execution grants + a demo API where mutation without a grant is 403.","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/prove_0.1.11_1789023860338_0.38728643954355557","host":"s3://npm-registry-packages-npm-production"}},"0.1.12":{"name":"@coderifts/prove","version":"0.1.12","license":"MIT","_id":"@coderifts/prove@0.1.12","maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"bin":{"coderifts-prove":"bin/prove-all.js"},"dist":{"shasum":"495c918d6f7ff4aabb3ee610eb2af16cb25a82bd","tarball":"https://registry.npmjs.org/@coderifts/prove/-/prove-0.1.12.tgz","fileCount":65,"integrity":"sha512-Km0kIhuLzLwSd8UaJQLnLiF7/fpVKfEuvR6AaZLZDgLccuxgIS2hB2scq47edPsKLVdUROp+Pce+CBFEW4ajWw==","signatures":[{"sig":"MEUCIQDyXcBLE32/KmhB3ZBS/Zama0Spi3wTABRJcPrr1r0JKgIgVCSngj6Bugj4il6LwIYuaQBLzn5dgI9HLARYniT8aoI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQD7/NPhGSLJDRxZeaRcAbO09ITp+5aKs6nrRhwS9RD24AIgeJ3Q7jeUotrumYIMb5xWeKJb5UmEDk12AKsAmsknfek=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":836080},"engines":{"node":">=20"},"gitHead":"75a09d8b74f1161d40415fb98c2537f116d9ffdc","private":false,"scripts":{"test":"node --test \"packages/middleware/test/*.test.js\"","prove":"node demo/prove.js","fixture":"node scripts/make-conformance-fixture.js","test:pg":"node --test --test-concurrency=1 \"demo/test/*.test.js\"","test:all":"npm test && npm run test:pg","prove:all":"node bin/prove-all.js","prove:check":"node bin/prove-all.js --check","check:packed":"node scripts/check-packed-sample.js","prepublishOnly":"npm run test:all && node scripts/check-packed-sample.js"},"_npmUser":{"name":"zsobpeter","email":"zsobpeter@gmail.com"},"workspaces":["packages/middleware","demo"],"_npmVersion":"11.6.2","description":"Reference offline enforcement for cr.exec.v1 execution grants + a demo API where mutation without a grant is 403.","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/prove_0.1.12_1789213841054_0.13798761833669237","host":"s3://npm-registry-packages-npm-production"}},"0.1.13":{"_id":"@coderifts/prove@0.1.13","bin":{"coderifts-prove":"bin/prove-all.js"},"dist":{"shasum":"59d3c4c5904ef9a1ba4ca15e5092e8331b0a2ba3","tarball":"https://registry.npmjs.org/@coderifts/prove/-/prove-0.1.13.tgz","fileCount":66,"integrity":"sha512-34fcu078HNl0GbnXXJiJTa4myFyDOFT7HDKKy7PzZ1/w6fHPZhYFagriPtIPjHNdxJCb1kj8uDGk/kq61Rss0g==","signatures":[{"sig":"MEYCIQCu8W03iqlrJTO3LTCix7T5yTqL7z7yL4teEPkvfTGMmwIhAMUPGsb3iLHXMi99lhjWLcM8qUn5S9h3tkof564qlbyi","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIDZxXXsTjzYaKd2SwqzkZGRve4e+sMwtMgDFFLIIOSA6AiB4UDHYAOgeDVr5BSi82XHlNzEeT3o2zaK6JsT4tvkiPA=="}],"unpackedSize":840576},"name":"@coderifts/prove","engines":{"node":">=20"},"gitHead":"465bf67873c8f8246e138fb707f3b84fd5a4fcee","license":"MIT","private":false,"scripts":{"test":"node --test \"packages/middleware/test/*.test.js\" \"test/*.test.js\"","prove":"node demo/prove.js","fixture":"node scripts/make-conformance-fixture.js","test:pg":"node --test --test-concurrency=1 \"demo/test/*.test.js\"","test:all":"npm test && npm run test:pg","prove:all":"node bin/prove-all.js","prove:check":"node bin/prove-all.js --check","test:packed":"node --test test/packed-install.test.js","check:packed":"node scripts/check-packed-sample.js","prepublishOnly":"npm run test:all && node scripts/check-packed-sample.js && npm run test:packed"},"version":"0.1.13","_npmUser":{"name":"zsobpeter","email":"zsobpeter@gmail.com"},"workspaces":["packages/middleware","demo"],"_npmVersion":"11.6.2","description":"Reference offline enforcement for cr.exec.v1 execution grants + a demo API where mutation without a grant is 403.","directories":{},"maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/prove_0.1.13_1789910633227_0.13211214218733236"}}},"time":{"created":"2026-09-04T10:41:04.475Z","modified":"2026-09-20T13:23:53.506Z","0.1.0":"2026-09-04T10:41:04.799Z","0.1.1":"2026-09-04T16:54:33.810Z","0.1.2":"2026-09-05T10:43:43.726Z","0.1.3":"2026-09-05T19:07:01.552Z","0.1.4":"2026-09-06T10:20:33.617Z","0.1.5":"2026-09-06T13:23:11.747Z","0.1.6":"2026-09-06T18:22:34.420Z","0.1.7":"2026-09-07T09:07:21.415Z","0.1.8":"2026-09-07T19:13:15.921Z","0.1.9":"2026-09-08T11:00:47.630Z","0.1.10":"2026-09-09T17:49:58.303Z","0.1.11":"2026-09-10T07:04:20.481Z","0.1.12":"2026-09-12T11:50:41.139Z","0.1.13":"2026-09-20T13:23:53.321Z"},"license":"MIT","description":"Reference offline enforcement for cr.exec.v1 execution grants + a demo API where mutation without a grant is 403.","maintainers":[{"name":"zsobpeter","email":"zsobpeter@gmail.com"}],"readme":"# capability-demo — the atomic execution reference\n\n**What this repo is now:** the reference implementation of *what happens after a decision* — a\nsigned execution grant carried to an executor, consumed exactly once, and the mutation sealed\ninside the transaction that made it. Every hop is asserted, and every limit is written down beside\nthe claim it bounds.\n\nIt began as an Express middleware demo, and that middleware is still here. It is no longer the\npoint. The 403 that middleware returns is *this process refusing itself* — useful evidence about\nrouting, not a capability boundary — and the sections below say so at length. What the repo is for\nnow is the part that is hard to fake: a grant that the database itself will not let you spend\ntwice, and a seal that verifies with the network unplugged.\n\n## Run it — three paths, lightest first\n\n**1 · No database, no key, no network — about 30 seconds**\n\n```bash\nnode examples/atomic-v2/run.js\n```\n\nRe-verify a committed sample in CI (no database, no network) — copy `.github/workflows/prove.yml`:\n\n```bash\nnode bin/prove-all.js --check examples/sample-transcript/transcript.json \\\n  --keys examples/sample-transcript/executor-keys.json\n```\n\nTwo public E2E samples, distinct profiles — do not mix them:\n\n| Profile | Path | What POINT 8 is |\n| --- | --- | --- |\n| `prove-db-provider-readback` | `examples/sample-transcript/` (this package) | `PROVEN` on an unsigned provider-readback / DB executor. **Not** a merge, **not** PATH B, **not** Conformance 7/7. |\n| `conformance-end-to-end-7-7` | `@coderifts/conformance` `fixtures/recorded/end-to-end/` (pointer: `examples/conformance-e2e-7-7/`) | `TARGET_STATE_TRANSITION_PROVEN`. Replay: `npx @coderifts/conformance --assurance END_TO_END`. |\n\nThe packed-check (`scripts/check-packed-sample.js`) asserts the shipped sample is the DB/provider-readback profile and **refuses** to call that POINT 8 a merge or the 7/7 canonical.\n\nAuthorized vs blocked on one screen: `node examples/currently-authorized/run.js`.\n\nFour hops asserted end to end: authorize request shape, grant issuance, one-use consumption, seal\nverification — plus a control that a forged signature over identical bytes is refused. Nothing is\nnarrated; every line is a check. Start here.\n\n**2 · The full proof, and an artifact you can hand to someone — docker, about two minutes**\n\n```bash\nnode bin/prove-all.js\n```\n\nBoots a throwaway Postgres, runs the six panel proofs and the ten chain points in one process on\none clock, and writes `transcript.json` and `TRANSCRIPT.md` into the current directory. The tenth\npoint re-verifies the transcript this run just produced with the network trapped, so the artifact's\ncentral claim — that it checks offline — is demonstrated rather than asserted.\n\nSet `DATABASE_URL` to use a scratch database of your own instead; it refuses hosts that look like\nmanaged production, and it refuses to start at all if there is neither docker nor a URL rather than\nreporting a proof it did not run. Re-check any transcript, including someone else's, with no\ndatabase and no network:\n\n```bash\nnode bin/prove-all.js --check transcript.json\n```\n\n**3 · The suites and the ten scenes — docker compose**\n\n```bash\ncd demo && docker compose up -d --build\ncd .. && ./demo/run-demo.sh\nnpm run test:all\n```\n\n**Before citing the 403 as evidence:** the demo API returns `403` for a mutation through the\nguarded route without a valid grant. That refusal is issued by the same process that owns the data.\nRead *What the 403 is, and what it is not* below before quoting it — it is evidence about routing,\nnot a capability boundary.\n\n---\n\n## What this is, and why\n\nCodeRifts issues decisions. A decision that nothing checks is advice. The strategic goal\nthis repo serves is to **build a mutation environment in which acting without CodeRifts\nauthorization does not succeed** — not a linter that complains after the fact, but a\nboundary an unauthorized call cannot cross. `docs/cr-exec-v1.md` is candid that owning the\nformat and the verifier \"is not the same as a mutation gateway checking grants.\" This repo\nis the gateway half: a small Express middleware that treats a signed, scope-bound grant as\nthe only way through.\n\n### What the 403 is, and what it is not\n\n**The 403 is this process refusing itself.** `requireExecutionGrant()` is Express middleware running\ninside the demo API, and `demo/src/atomic.js` returns its own `403`s from the same process. There is\nno row-level security anywhere in this repo. STEP 1 split the former single `demo` role:\n`cr_host` has **zero DML on `articles`** (raw INSERT is SQLSTATE 42501, not a Node 403);\n`cr_executor` has EXECUTE on `cr_execute_grant` and `cap_seal` only (no table DML); `cr_owner` (NOLOGIN) owns\nthe tables and the SECURITY DEFINER functions. The bootstrap `demo` superuser can still write\n(scene 9). STEP 3: the executor PROCESS signs the gate preimage out of the DB with a local key and `cap_seal` binds that signature before COMMIT.\n\nThat makes `raw → 403` evidence about **routing**, not about capability. It shows that requests\ntravelling the guarded path without a valid grant are refused, which is the thing this reference is\nfor. It is *not* a capability boundary, and a 403 produced by the same program that owns the data is\nnot independent enforcement. Do not cite it as one.\n\n**Two Postgres facts, neither of which is the 403.** The `consumed_grants.jti` **PRIMARY KEY**\nis enforced by PostgreSQL: two concurrent requests presenting the same grant both reach the\n`INSERT`, exactly one wins, and the loser takes SQLSTATE 23505 which rolls back its whole\ntransaction including the mutation. That constrains **one-use**. STEP 1 adds **who may write\n`articles`**: `cr_host` has no INSERT/UPDATE/DELETE, so a raw host query fails with SQLSTATE\n42501 — not a Node 403. The bootstrap `demo` role can still write (scene 9). STEP 2\nnarrowed `cr_executor` to EXECUTE-only on the gate. `cr_execute_grant` consumes and mutates and does not sign; the process signs, `cap_seal` binds.\n\n**Consequence for the sidecar reference (roadmap 1091).** `cr_host` has no write on\n`articles` (42501). `cr_executor` has no table DML either — only EXECUTE on\n`cr_execute_grant` and `cap_seal` (SECURITY DEFINER, owned by `cr_owner`). The bootstrap `demo`\nsuperuser can still write (scene 9). Middleware that refuses itself can always be\nrouted around; the 403 is not this proof. A deferred constraint trigger forbids COMMIT of a consumed-unsigned ledger row.\n\nThe second idea is that the check must be **offline**. A boundary that phones home to\nauthorize is a boundary that fails open when the network does, and one whose latency and\navailability are someone else's problem. `requireExecutionGrant()` verifies an Ed25519\nsignature against a public key pinned at startup and performs **no network I/O at request\ntime** — no key fetch, no CodeRifts call, no registry lookup. The demo compose file\ndeliberately contains no CodeRifts service, and scene 5 re-runs verification in a container\nwith `--network none`. Unplugging the network does not change a single verdict.\n\n## Quickstart\n\n```bash\ncd demo && docker compose up -d --build   # 1. start Postgres + the API (generates DEMO keypairs)\ncd .. && ./demo/run-demo.sh               # 2. run the ten scenes\nnpm run test:all                          # 3. unit + live Postgres integration tests\n```\n\n`npm test` alone runs the unit tests with no network and no Docker. The integration\ntests need the `db` service (`cd demo && docker compose up -d db`); without it they **skip\nloudly with the reason**, never silently pass.\n\n<details>\n<summary>Expected output of <code>./demo/run-demo.sh</code></summary>\n\n```text\n═══ cr.exec.v1 reference enforcement — offline capability demo ═══\nAPI: http://localhost:3000\nClaim under test: a non-admin caller inside this boundary cannot mutate without a grant.\n\n─── SCENE 0 — the open route still works (the guard is scoped, not a blanket 403)\n    GET /health -> 200 {\"status\":\"ok\",\"guard\":\"offline-grant-verification\"}\n    ✅ VERDICT: unguarded route is unaffected\n\n─── SCENE 1 — raw mutation, no grant → 403\n    POST /articles (no header) -> 403 {\"error\":\"execution_grant_required\",\"status\":\"MALFORMED\",\"reason\":\"missing_grant_header\"}\n    ✅ VERDICT: the raw path fails\n\n─── SCENE 2 — BEARER grant (no state_nonce) → 403 BEARER_NOT_PERMITTED\n    issued BEARER grant (no state_nonce): eyJ2IjoiY3IuZXhlYy52MSIsImtpZCI6IkRFTU8tS0VZ…\n    POST /articles (BEARER grant) -> 403 {\"error\":\"execution_refused\",\"profile\":\"BEARER\",\"status\":\"BEARER_NOT_PERMITTED\",\"reason\":\"execution_grant_bearer_unsupported\"}\n    ✅ VERDICT: BEARER does not mutate\n    ✅ VERDICT: status is BEARER_NOT_PERMITTED\n\n─── SCENE 3 — same grant, ONE byte changed in the body → 403 GRANT_SCOPE_MISMATCH\n    original: {\"title\":\"Ship it\",\"body\":\"governed mutation\"}\n    tampered: {\"title\":\"Ship it\",\"body\":\"governed mutatioN\"}\n    POST /articles (tampered) -> 403 {\"error\":\"execution_grant_required\",\"status\":\"GRANT_SCOPE_MISMATCH\",\"reason\":\"scope_hash_mismatch\"}\n    ✅ VERDICT: grant does not travel to a different payload\n    ✅ VERDICT: status is GRANT_SCOPE_MISMATCH\n\n─── SCENE 4 — expired grant → 403 GRANT_EXPIRED\n    POST /articles (expired grant) -> 403 {\"error\":\"execution_grant_required\",\"status\":\"GRANT_EXPIRED\",\"reason\":\"expired\"}\n    ✅ VERDICT: expiry is enforced\n    ✅ VERDICT: status is GRANT_EXPIRED (30s skew leeway applied)\n\n─── SCENE 5 — NO NETWORK AT ALL → verification unchanged\n    The compose file has no CodeRifts service; verification uses a pinned key.\n    Proof: run the same issue+verify in a container with NO network interface.\n    `docker run --network none` is stronger than an iptables DROP: there is no\n    interface to drop from. (`docker compose run` has no --network flag; build\n    the image and use `docker run` directly.)\n    ⚠️  Docker daemon not reachable — running the SAME check on the host instead.\n       This still shows verification needs no CodeRifts call, but it does NOT\n       prove network isolation. For the airtight version, start Docker and run:\n         docker build -t capability-demo-offline:local -f demo/Dockerfile .\n         docker run --rm --network none capability-demo-offline:local node /app/demo/offline-check.js\n    network interfaces (excl. loopback-only count): 0\n    offline verification status: GRANT_CURRENT (valid=true)\n    ✅ VERDICT: offline verify returns GRANT_CURRENT (host run — isolation NOT proven here)\n\n═══ ALL SCENES AS EXPECTED ═══\n```\n</details>\n\n## The binding rule\n\n**The raw request body IS the after-payload.**\n\nThe grant's `scope_hash` is, per `docs/cr-exec-v1.md` § Derivation:\n\n```\npreimage    = operation \\x1f target_id \\x1f after_payload\nscope_hash  = \"sha256:\" + sha256hex(preimage)\n```\n\nThis middleware recomputes that hash on every guarded request from:\n\n| Component | Source in the request |\n|---|---|\n| `operation` | `operationMap[\"<METHOD> <route pattern>\"]` — an unmapped route is **refused**, never allowed |\n| `target_id` | the `targetId(req)` resolver; default `req.params.id ?? ''` |\n| `after_payload` | `req.rawBody` — the bytes exactly as received, captured before any JSON round-trip |\n\nIf the recomputed hash differs from the signed one, the answer is `403` with\n`status: \"GRANT_SCOPE_MISMATCH\"`.\n\nBecause it binds **bytes, not meaning**, all of these fail against a grant issued for\n`{\"title\":\"Ship it\",\"body\":\"governed mutation\"}`:\n\n- one character changed (`mutation` → `mutatioN`) — scene 3\n- one space added after a comma\n- the same two JSON keys in the other order\n\nThat is the intended strictness: the grant authorizes *one exact payload* at *one target*\nfor *one operation*. It is not a session token.\n\n## Middleware API\n\n```js\nconst { requireExecutionGrant, captureRawBody } = require('@coderifts/capability-express');\n\napp.post('/articles',\n  captureRawBody(),                     // MUST precede the guard — it hashes the raw bytes\n  requireExecutionGrant({\n    keysFile: '/path/coderifts-keys.json',   // or publicKeyPem: '-----BEGIN PUBLIC KEY-----…'\n    kid: 'DEMO-KEY-DO-NOT-USE',               // optional: require this exact kid\n    audience: '',                             // '' = unbound (not checked)\n    operationMap: { 'POST /articles': 'publish' },\n    targetId: (req) => req.params.id ?? '',   // default\n    header: 'CodeRifts-Execution-Grant',      // default\n  }),\n  handler);\n```\n\nFailure → `403` with `{ error: \"execution_grant_required\", status, reason }`, where `status`\nand `reason` are verbatim from the verifier family. Success → `next()` with\n`req.coderifts = { payload }`.\n\n**Header name.** `docs/cr-exec-v1.md` specifies the token and the algorithm but is **silent\non HTTP transport**. `CodeRifts-Execution-Grant` is defined *here* as the reference\nconvention for cr.exec.v1 over HTTP — established by this package, not measured from the\nspec. Override with `header`.\n\n### Statuses\n\nStraight from the spec's 10-step algorithm; this repo introduces none of its own.\n\n| Status | Cause |\n|---|---|\n| `MALFORMED` | structure, JSON, missing field, reserved key (`cnf`/`nbf`/`max_uses`), bad timestamp, missing header |\n| `INVALID_SIGNATURE` | signature mismatch, or `\\|` in a signed field |\n| `UNKNOWN_KEY` | `kid` is not the pinned key — or the pinned key is `retired` |\n| `GRANT_EXPIRED` | `exp + 30s < now`, or `iat` more than 30s in the future |\n| `GRANT_UNBOUND` | `receipt_digest` absent/malformed, or mismatched against a supplied receipt |\n| `GRANT_WRONG_AUDIENCE` | intended audience ≠ signed audience |\n| `GRANT_SCOPE_MISMATCH` | operation, target, or `scope_hash` differs — **and** unmapped routes |\n| `GRANT_CURRENT` | the only status that calls `next()` |\n\nClock-skew leeway is 30 s, matching ID104 receipt verification.\n\n## Where the grants come from\n\nPOINT 1 of the flagship transcript is a **server authorize**, not a local mint.\n`demo/src/authorize-issue.js` POSTs `preflight_mode=authorize` +\n`include_execution_grant: true` to `https://app.coderifts.com/api/v1/preflight` when\n`CODERIFTS_API_KEY` is set (labelled `[ISSUANCE]`, outside the 21-trap). Without a\nkey it verifies a **recorded** server-signed grant (kid `2026-07-k1`, captured\n2026-09-05) offline against the pinned well-known keyring, `now=iat`. That grant is\nnot `DEMO-KEY-DO-NOT-USE`.\n\n`demo/issue-grant.js` still signs **data-plane** grants locally with the DEMO key\nso the local executor can consume them (replay, CAS, authorized write). Those\npanels prove Postgres enforcement; they are not the authorize verdict.\n\nThe real authorize flow:\n\n```\nPOST /api/v1/preflight\n  { preflight_mode: \"authorize\",\n    context: { operation: \"publish\", ... },\n    artifacts: [ ... ],\n    include_execution_grant: true }        <- opt-in (docs/cr-exec-v1.md § Issuance)\n       |\n       v\n200 { decision, execution_action, chain_receipt, execution_grant }\n                                 ^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^\n                                 durable audit   short-lived bearer\n                                 artifact        the boundary checks\n```\n\nAnalyze mode never mints a grant; STOP / REQUEST_APPROVAL never mint one either.\n\n⚠️ **The demo keypair is DEMO MATERIAL.** It is generated at build time by\n`demo/gen-keys.js` (kid `DEMO-KEY-DO-NOT-USE`), is gitignored, and has no relationship to\nany CodeRifts key. The demo grant also binds a labelled stand-in receipt digest rather than\na real receipt token.\n\n### `deployment_id` on the demo's v1 grant is conscious design (1130-F1)\n\nThe demo deliberately issues **v1** grants — a simpler, teachable reference for the\ndata-plane gateway. Every such grant carries a `deployment_id`. That field is **this\nrepo's data-plane atomicity concept**, not part of the public grant format:\n\n- it is half of the `consumed_grants (deployment_id, jti)` PRIMARY KEY\n- it is inside the signed gate preimage (`cr.gate.preimage.v1|{jti}|{deployment_id}|sha256:mutation|{target}`)\n- the attestation binds it (`ATTEST_UNBOUND` / `deployment_id_mismatch` on mismatch)\n- the reconciler's CONFIRMED path enforces it\n\nThe public grant format does **not** carry it. Public v1 `SIGNED_FIELDS` and v2\n`V2_REQUIRED_STRINGS` neither list `deployment_id`. The public v1-verifier therefore\nrejects the demo's default grant as `unknown_field` — and that is **correctly\nstrict**, not a gap. `issue-grant.js` calls the slot \"optional-additive\"; the data\nplane here makes it **mandatory**. Those are two different jobs.\n\n**Two purposes, two verifiers.** The demo grant verifies with **this** repo's verifier\nbecause the demo is teaching consume + mutate + seal. It is **not** publicly\nverifiable against the product v1-verifier, by design. The real product\n(`execution-grant-v2.js`) uses **v2**, which binds the deployment via\n`tenant_id` + `target_uri` instead of stuffing `deployment_id` into a v1 grant.\n\nDo not paper this over by loosening the public verifier, and do not cite a demo\ngrant as a publicly verifiable `cr.exec.v1` token.\n\n## Two profiles: BEARER is refused; ATOMIC is the write path\n\nThe grant format still carries an optional `state_nonce` (the verifier classifies\ntokens that way). **This executor does not mutate on BEARER.** A grant with no\n`state_nonce` is `403 BEARER_NOT_PERMITTED` — it never takes a DB client. Round-1\n\"BEARER still writes\" was a second, unguarded data plane; scene 2 now demonstrates\nthe close. ATOMIC (`state_nonce` present) is the only mutation path.\n\n| | **BEARER** (no `state_nonce`) | **ATOMIC** (`state_nonce` present) |\n|---|---|---|\n| This executor | **refused** (`BEARER_NOT_PERMITTED`) — no write, no ledger | **one-use**, enforced by a Postgres PRIMARY KEY |\n| State binding | n/a (never reaches the write) | CAS against the state the issuer saw |\n| Attestation | none | `cr.exec.attest.v1` returned on commit |\n\n`state_nonce` is a **separate signed field** and is deliberately **not** folded into\n`scope_hash`: after-payload binding and state binding are independent facts, so rotating a\nnonce must not look like a different after-shape. A BEARER grant's signing input stays\nbyte-identical to pre-ATOMIC issuances because the `|{state_nonce}` slot is appended only when\nnon-empty.\n\n### Challenge-first state binding\n\n```\nPOST /state-challenge {\"target_id\":\"42\"}\n  -> { state_nonce, current_digest, expires_at }\n```\n\n`current_digest` hashes the target's current row. **Absence is a different fact from empty**:\na missing row hashes the explicit marker `absent:<id>`, never the empty string — otherwise\n\"deleted\" and \"blank\" would be indistinguishable to the CAS.\n\n### The atomic execute path — ONE transaction\n\n```\nBEGIN                                          -- one pg client, held by the executor PROCESS\n  SELECT cr_execute_grant(...)                 -- consume + mutate + persist canonical preimage\n    -> unknown / expired / drift / 23505       => ROLLBACK (status stays unsigned, so COMMIT\n                                                 would also fail the deferred constraint)\n  PROCESS signs the exact returned preimage    -- local executor key; never KMS; never inside SQL\n  SELECT cap_seal(jti, preimage_hash, signature)\n    -> foreign preimage                        => RAISE, ROLLBACK\nCOMMIT                                         -- deferred trigger: status='consumed' cannot COMMIT\n```\n\nThe returned `atomic_execution_attestation` is issued only after COMMIT. It asserts the\nexecutor authorized this exact transaction for commit — not that the transaction committed.\n\n**Posture receipt (`cr.posture.receipt.v1`).** 42501 is the DENY; the posture reader\nre-reads `pg_catalog` and signs that the deny is still wired (owners, DML ACLs,\nSECURITY DEFINER, `cr_owner` NOLOGIN, TEMPORARY revoked). Drift (an admin GRANT)\ndoes not restore privileges — it revokes the enforcement claim and yields a signed\ndrift artifact.\n\n**`coderifts prove`.** `node demo/prove.js` (or `npm run prove`) runs the six panel\nproofs against live Postgres and emits a signed transcript. It adds no enforcement.\nGrant-binding is explicit: without a grant, \"signature valid; grant-binding NOT\nchecked\" — never a bare `ATTEST_VALID`.\n\nThe one-use guarantee is **the PRIMARY KEY**, not application logic. There is no\nSELECT-then-INSERT race and no \"have I seen this jti?\" check that could be wrong under\nconcurrency: 20 simultaneous requests with one grant all reach the INSERT, exactly one wins,\nand the other 19 roll back with their mutations undone.\n\n## Execution attestations (`atomic_execution_attestation`)\n\nAfter COMMIT the executor returns an `atomic_execution_attestation`: a signature over the\n**exact gate preimage bytes** with **its own** local key. That asserts the executor\nauthorized this exact transaction for commit — not that the transaction committed.\nExecutor keys are **customer-held** — CodeRifts never receives them. The registry uses the\n(b)-ready document shape from the spec (same shape as `.well-known/coderifts-keys.json`).\n\n```bash\nnode demo/verify-attest.js --token <attestation> --grant <grant>\n```\n\nStatuses mirror the reference kernel exactly: `ATTEST_VALID`,\n`ATTEST_RETIRED_KEY_VALID_AT_ISSUE`, `ATTEST_INVALID_SIGNATURE`, `ATTEST_UNKNOWN_KEY`,\n`ATTEST_MALFORMED`, `ATTEST_UNBOUND`.\n\nOne deliberate asymmetry with grants: a **retired** executor key still verifies an attestation\nwhose `committed_at` fell inside `[valid_from, retired_at)`. A grant is *live permission*\n(retired => never valid); an attestation is a *historical statement*, like a receipt.\n\n## Honesty — what this proves and what it does not\n\n**Proves:** a non-admin caller inside this boundary cannot mutate without a grant that\n(a) is signed by the pinned key, (b) has not expired, and (c) covers this exact operation,\ntarget, and request body — verified with no network access.\n\n**Does not prove:**\n\n- **No bypass.** Anything that reaches the data without traversing this middleware is\n  unaffected: root on the host, a DB console, an admin panel on another route, a migration\n  job, a second service sharing the database.\n- **BEARER is closed at this executor.** A grant with no `state_nonce` is refused\n  (`BEARER_NOT_PERMITTED`) and writes nothing. The format can still *name* BEARER\n  (verifier `grantProfile`); this process will not honour it. ATOMIC consumption is\n  one-use via the `consumed_grants` primary key.\n- **An `atomic_execution_attestation` proves that a holder of the executor key authorized this\n  exact preimage for commit.** It does not prove the executor's code is unmodified — **deploy\n  attestation is out of scope**, a later artifact, not this one. It does not prove a human saw\n  anything, does not prove the grant is still currently authorized, and does not claim the\n  transaction committed (STEP 5 is the posture receipt).\n- **The CAS detects drift; it does not prevent privileged writes.** Scene 9 shows root writing\n  straight to Postgres with no grant at all. Nothing here stops that. What the challenge-first\n  CAS does is *notice*: the granted mutation is refused because the state the issuer authorized\n  is no longer the state on disk.\n- **No global enforcement claim.** Coverage is **per-adapter**. Mounting the guard on a\n  route says something about that route and nothing about any other.\n- **No proof of possession.** `cnf` is reserved and unimplemented; absent `cnf` = bearer.\n- **Not receipt re-verification.** The grant binds a `receipt_digest`; it does not\n  re-check the receipt's signature or whether the receipt is still authorized. Callers\n  needing both check both artifacts.\n- **Scene 5 caveat.** Network isolation is proven only when the Docker path runs. Without\n  a Docker daemon the script falls back to a host run and says so — that still shows no\n  CodeRifts call is needed, but it does not demonstrate isolation.\n\n## Productionising this\n\n1. **Real keys.** Replace the demo registry with the live one from\n   `https://app.coderifts.com/.well-known/coderifts-keys.json` (same shape — `keys[]` of\n   `{kid, public_key_pem, status, valid_from, retired_at}`). Fetch it at **deploy** time\n   and pin the file; do not fetch per request, or you give up the offline property. Note\n   `Cache-Control: max-age=3600` and that rotation is additive — add the new key, keep the\n   old until its grants have expired.\n2. **Real grants.** POINT 1 already uses the authorize call (live or recorded server\n   grant). Data-plane panels still mint DEMO-KEY grants the local executor can consume.\n   `include_execution_grant: true` and forward the returned `execution_grant` to the\n   boundary as `CodeRifts-Execution-Grant`.\n3. **Label coverage honestly.** If you report enforcement upstream, label it\n   per-adapter (`substrate_enforced` for the routes actually behind a guard). A global\n   \"enforced\" claim is not supported by mounting this on some routes.\n4. **Decide on replay.** For destructive operations, pair the grant with a one-use record\n   keyed by `jti` (the format supplies one), or wait for the PHASE-2 executor profile.\n5. **Bound the audience.** Set `audience` to this service so a grant minted for another\n   boundary cannot be presented here.\n\nSpec: `coderifts-app/docs/cr-exec-v1.md`. Reference verifier:\n`coderifts-app/src/verdict-core/execution-grant.js`.\n","readmeFilename":"README.md"}