diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..9ae6de3 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,19 @@ +version: 2 +updates: + - package-ecosystem: npm + directory: /frontend + schedule: + interval: weekly + open-pull-requests-limit: 10 + + - package-ecosystem: npm + directory: /services/tts + schedule: + interval: weekly + open-pull-requests-limit: 10 + + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + open-pull-requests-limit: 10 diff --git a/CHANGELOG.md b/CHANGELOG.md index 6765a4e..e3c4af4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,233 @@ +# 1.0.0 (2026-05-27) + + +### Bug Fixes + +* **#244:** remove duplicate get_dispute_window and add dispute_timestamp regression tests ([cd7335a](https://github.com/Emmyt24/predictIQ/commit/cd7335a3a3aaa64b59d80c4607a10dc7a0a8c713)), closes [#244](https://github.com/Emmyt24/predictIQ/issues/244) +* **#257:** remove duplicate imports in oracles_test and add oracle quality gate to CI ([a230a8c](https://github.com/Emmyt24/predictIQ/commit/a230a8c6f7bcf07d2312c1b5e830bbc8422be822)), closes [#257](https://github.com/Emmyt24/predictIQ/issues/257) +* **#290:** replace .expect panic in generate_signature with fallible Result API ([36ed34a](https://github.com/Emmyt24/predictIQ/commit/36ed34a8f44ff2067285518a0bd50ab110364126)), closes [#290](https://github.com/Emmyt24/predictIQ/issues/290) +* **#395:** separate webhook routing security model from admin routes ([4be4df1](https://github.com/Emmyt24/predictIQ/commit/4be4df1d2cc9083042074dfddf3bc1b46275d7cd)), closes [#395](https://github.com/Emmyt24/predictIQ/issues/395) +* **#396:** store real recipient address in sent email events ([78754d7](https://github.com/Emmyt24/predictIQ/commit/78754d7ae9886cf34c681669682ade97c74c8bb1)), closes [#396](https://github.com/Emmyt24/predictIQ/issues/396) +* **#397:** recover orphaned processing jobs on worker startup ([349b7b9](https://github.com/Emmyt24/predictIQ/commit/349b7b9d87168c8f26c7bb0c6c5ec4e676b3c156)), closes [#397](https://github.com/Emmyt24/predictIQ/issues/397) +* **#398:** remove Box::leak memory leak in analytics rate limiter ([47cabae](https://github.com/Emmyt24/predictIQ/commit/47cabae32bbf8a5e525810f8259b84e097144997)), closes [#398](https://github.com/Emmyt24/predictIQ/issues/398) +* **#403/#404:** define missing governance types and timelock constants ([99258a4](https://github.com/Emmyt24/predictIQ/commit/99258a4102c641a05d9ad64ac309164caff2bcc5)), closes [#403](https://github.com/Emmyt24/predictIQ/issues/403) [#404](https://github.com/Emmyt24/predictIQ/issues/404) [#406](https://github.com/Emmyt24/predictIQ/issues/406) +* **#405:** emit accurate oracle source metadata in oracle result events ([562ad84](https://github.com/Emmyt24/predictIQ/commit/562ad846c254a2a912a7522d5e7c10de4d8de9a7)), closes [#405](https://github.com/Emmyt24/predictIQ/issues/405) +* **#407:** enforce MAX_PAGE_LIMIT=100 on all paginated contract queries ([a257618](https://github.com/Emmyt24/predictIQ/commit/a2576181a37bb9ea8e40c079521da39a41a9094f)), closes [#407](https://github.com/Emmyt24/predictIQ/issues/407) +* **#452:** remove double newsletter rate limiting, make policy configurable ([6169065](https://github.com/Emmyt24/predictIQ/commit/61690655bf7a99fda542e68fbb396ab0fcdae0b8)), closes [#452](https://github.com/Emmyt24/predictIQ/issues/452) [#452](https://github.com/Emmyt24/predictIQ/issues/452) +* **#453:** Redis-backed newsletter IP rate limiter with atomic counters ([932a14d](https://github.com/Emmyt24/predictIQ/commit/932a14d21c3a1f1bdea07d14c72d415f26d1b56e)), closes [#453](https://github.com/Emmyt24/predictIQ/issues/453) +* **#454:** harden client IP extraction with trusted proxy CIDRs ([04db648](https://github.com/Emmyt24/predictIQ/commit/04db648d93421f44f1cee80082bbc32996f8a537)), closes [#454](https://github.com/Emmyt24/predictIQ/issues/454) +* **#463:** add TTL and max-size eviction to watched_txs ([428b7a7](https://github.com/Emmyt24/predictIQ/commit/428b7a714ec3ce92ca751a6943020ecc4e9250c0)), closes [#463](https://github.com/Emmyt24/predictIQ/issues/463) +* **#485-#488:** sync API_SPEC, add email DLQ, validate templates at startup ([0749bc5](https://github.com/Emmyt24/predictIQ/commit/0749bc50934b4666608cf59d886ce79cddd69619)), closes [#485](https://github.com/Emmyt24/predictIQ/issues/485) [-#488](https://github.com/-/issues/488) [#485](https://github.com/Emmyt24/predictIQ/issues/485) [#486](https://github.com/Emmyt24/predictIQ/issues/486) [#487](https://github.com/Emmyt24/predictIQ/issues/487) [#488](https://github.com/Emmyt24/predictIQ/issues/488) +* **#624:** fetch_pyth_price calls on-chain Pyth contract via oracle_address/feed_id ([eb3079f](https://github.com/Emmyt24/predictIQ/commit/eb3079fa236b45a9130ac802d5a0584e871e6312)), closes [#624](https://github.com/Emmyt24/predictIQ/issues/624) +* **#625:** determine_outcome uses per-market strike_price from OracleConfig ([901f800](https://github.com/Emmyt24/predictIQ/commit/901f800f03ac2ec05fdeb7066ebe045a407c14b8)), closes [#625](https://github.com/Emmyt24/predictIQ/issues/625) +* **#626:** validate_oracle_staleness checks all oracle indices ([bc53975](https://github.com/Emmyt24/predictIQ/commit/bc5397508088bb58b4c0feab04e1291f1a831528)), closes [#626](https://github.com/Emmyt24/predictIQ/issues/626) +* **#627:** align DISPUTE_WINDOW_SECONDS to 72h (259200) ([4f26453](https://github.com/Emmyt24/predictIQ/commit/4f26453e0eafb3eefa8eb1fdca4011a8807411e5)), closes [#627](https://github.com/Emmyt24/predictIQ/issues/627) +* add AssetClawedBack to ErrorCode enum for SAC compatibility ([b27300c](https://github.com/Emmyt24/predictIQ/commit/b27300c99983fa98700a2a0f4aa6e67220401aa5)) +* add missing GovernanceToken variant to ConfigKey enum ([b00dfd2](https://github.com/Emmyt24/predictIQ/commit/b00dfd26eafc4f7545edc7f99e0eeb2b0178d84f)), closes [#3](https://github.com/Emmyt24/predictIQ/issues/3) +* add winner count, boundary, and gas threshold tests ([b0d2fbe](https://github.com/Emmyt24/predictIQ/commit/b0d2fbef15eb897c4d0ec00f443201fa95653b1e)) +* allow permissionless pruning of expired market data ([8f32ca6](https://github.com/Emmyt24/predictIQ/commit/8f32ca687c7a0f9af99054ed77065ed0427a70b8)), closes [#47](https://github.com/Emmyt24/predictIQ/issues/47) +* **api:** stop leaking internal error details to API consumers ([#628](https://github.com/Emmyt24/predictIQ/issues/628)) ([e3d8cd9](https://github.com/Emmyt24/predictIQ/commit/e3d8cd96d70df53aa060679d008f7f57eb12aaf7)) +* **api:** sync OpenAPI with runtime config and add auth security schemes ([#400](https://github.com/Emmyt24/predictIQ/issues/400)) ([4505c01](https://github.com/Emmyt24/predictIQ/commit/4505c016d5c6f3ad043ffbc6373f6e2baa480355)) +* base governance majority on total voting power instead of count ([369dd49](https://github.com/Emmyt24/predictIQ/commit/369dd496dad22251a0b0a2a1bb85f16d220bb02c)), closes [#4](https://github.com/Emmyt24/predictIQ/issues/4) +* **blockchain:** quarantine malformed events; add event parsing and tx monitor tests ([b723f42](https://github.com/Emmyt24/predictIQ/commit/b723f42d7f06c24c935e904f03efb2369ead4ac4)) +* consolidate newsletter rate limiting to single 5/hour policy ([#377](https://github.com/Emmyt24/predictIQ/issues/377)) ([c6fcbf5](https://github.com/Emmyt24/predictIQ/commit/c6fcbf50e70630f11c37b79db76351784d1e64fe)) +* contract query optimizations and docs fixes ([#481](https://github.com/Emmyt24/predictIQ/issues/481)-484) ([2a0d193](https://github.com/Emmyt24/predictIQ/commit/2a0d193bcbfdee2ad717d01abf774e413c4d0f04)), closes [#481-484](https://github.com/Emmyt24/predictIQ/issues/481-484) +* **contract:** prevent market deadlock for parent-child outcomes ([38f0e10](https://github.com/Emmyt24/predictIQ/commit/38f0e106f3fb41ecd2015bac80a7bd7402687158)) +* **contracts:** fix duplicate get_dispute_window and dead constant usage ([#402](https://github.com/Emmyt24/predictIQ/issues/402)) ([4f1c617](https://github.com/Emmyt24/predictIQ/commit/4f1c617077f130128f49d082901a7f92f98d095f)) +* **contracts:** remove duplicate cancel_market_admin entrypoint ([#401](https://github.com/Emmyt24/predictIQ/issues/401)) ([3243498](https://github.com/Emmyt24/predictIQ/commit/32434986e6aed7f58e9f41383e120da25270f6d1)) +* decrement total_staked on refund to maintain accounting accuracy ([94bcd0a](https://github.com/Emmyt24/predictIQ/commit/94bcd0ac168ae8ceac1af8cfb5d05ea7001dcc4c)) +* deep-prune voting storage on market prune (issue [#84](https://github.com/Emmyt24/predictIQ/issues/84)) ([c81462c](https://github.com/Emmyt24/predictIQ/commit/c81462c967b8496dcded356b98719ff5b1dc28a2)) +* efficient paginated user_bets endpoint using upstream offset/limit (closes [#390](https://github.com/Emmyt24/predictIQ/issues/390)) ([3ee7bde](https://github.com/Emmyt24/predictIQ/commit/3ee7bdec6ff41a96f92c8896899da3e364105ce0)) +* enforce betting deadline before resolution deadline ([95fb998](https://github.com/Emmyt24/predictIQ/commit/95fb998420995046b8ab946d2be512a008f1ed96)), closes [#6](https://github.com/Emmyt24/predictIQ/issues/6) +* enforce immutable payout mode throughout market lifecycle ([4083803](https://github.com/Emmyt24/predictIQ/commit/4083803ecbb245f5e42a6dc6452873f6eb846310)), closes [#23](https://github.com/Emmyt24/predictIQ/issues/23) +* enforce proxy trust boundaries for x-forwarded-for (closes [#379](https://github.com/Emmyt24/predictIQ/issues/379)) ([c8edd6d](https://github.com/Emmyt24/predictIQ/commit/c8edd6d69a5ba41cc94e5834692082484e2865c6)) +* enforce reward claim finality before market pruning ([95ed3d5](https://github.com/Emmyt24/predictIQ/commit/95ed3d5457508019dbab274f49e505c78c1573a1)), closes [#125](https://github.com/Emmyt24/predictIQ/issues/125) +* Enforce SendGrid webhook signature validation ([d49109a](https://github.com/Emmyt24/predictIQ/commit/d49109af28339e06dc3970fc260c571ae06a21e0)), closes [#24](https://github.com/Emmyt24/predictIQ/issues/24) +* enforce strict separation between Admin and Guardian identities ([673413c](https://github.com/Emmyt24/predictIQ/commit/673413c6d470db5147652be9fb6f4c0f170003a3)), closes [#19](https://github.com/Emmyt24/predictIQ/issues/19) [#19](https://github.com/Emmyt24/predictIQ/issues/19) +* ensure absolute isolation of storage keys and vote revision ([61a40e6](https://github.com/Emmyt24/predictIQ/commit/61a40e60691078fc11628bc7da91a04d1e985e41)) +* ensure all refund paths use SAC-safe transfer and respect circuit breakers ([a6244b1](https://github.com/Emmyt24/predictIQ/commit/a6244b1136346499627550a18ca4f6e90d8e4e1a)), closes [#93](https://github.com/Emmyt24/predictIQ/issues/93) +* ensure comprehensive storage cleanup for bettor participation records ([cbc8c4b](https://github.com/Emmyt24/predictIQ/commit/cbc8c4bc98a808d2aebd77eebd3c15d60f62e9e9)) +* ensure consistent TTL management for all governance and protocol state ([6227343](https://github.com/Emmyt24/predictIQ/commit/6227343ca4ff34afb547f47340d751ca94929d83)) +* ensure robust market ID generation for high-volume environments ([6a0a00a](https://github.com/Emmyt24/predictIQ/commit/6a0a00a17c340477d9dbac7549f3de9524727a61)) +* expose get_timelock_duration endpoint and add query test ([994c514](https://github.com/Emmyt24/predictIQ/commit/994c5148d2ea3f06cb56dafa522b2ec9c3f79b12)) +* expose lib target so security_tests can import predictiq_api::security ([835f00d](https://github.com/Emmyt24/predictIQ/commit/835f00d4ec69c127c78053feefd70d6a924fe7a1)) +* extend persistent storage TTL to safely cover pruning grace period ([a234a5a](https://github.com/Emmyt24/predictIQ/commit/a234a5ae0dd514b10e4c80bcf2ff94dda8a72072)), closes [#144](https://github.com/Emmyt24/predictIQ/issues/144) +* implement comprehensive security and governance improvements ([00934d7](https://github.com/Emmyt24/predictIQ/commit/00934d798dac04c7643ee49833566a7893e0b61c)), closes [#192](https://github.com/Emmyt24/predictIQ/issues/192) [#181](https://github.com/Emmyt24/predictIQ/issues/181) [#170](https://github.com/Emmyt24/predictIQ/issues/170) [#191](https://github.com/Emmyt24/predictIQ/issues/191) +* implement configurable governance timelock duration ([4ee3cb5](https://github.com/Emmyt24/predictIQ/commit/4ee3cb59521f498ea1796ee9e856680fc66c0c41)), closes [#13](https://github.com/Emmyt24/predictIQ/issues/13) +* implement configurable winner threshold for payout mode switching ([fde6463](https://github.com/Emmyt24/predictIQ/commit/fde646333ea389e3e9591b4bd35a07d6ba0992bb)) +* implement creator deposit refunds for cancelled markets ([42d16dd](https://github.com/Emmyt24/predictIQ/commit/42d16ddc0f3ac62af7f3925df230eb23f639fb2d)), closes [#51](https://github.com/Emmyt24/predictIQ/issues/51) +* implement flexible oracle result indexing per market ([f99207b](https://github.com/Emmyt24/predictIQ/commit/f99207bb66c556321317da3458dcf99137fd704f)), closes [#117](https://github.com/Emmyt24/predictIQ/issues/117) +* implement granular balance tracking for locked fallback tokens ([15cdbf3](https://github.com/Emmyt24/predictIQ/commit/15cdbf3bc32193f4c6f7aff5019da2e98c053a24)), closes [#37](https://github.com/Emmyt24/predictIQ/issues/37) +* implement granular role-based access control for administrative tasks ([fd56a03](https://github.com/Emmyt24/predictIQ/commit/fd56a03d8b79f9623372e4d5ec8925dccb085ebe)), closes [#118](https://github.com/Emmyt24/predictIQ/issues/118) +* implement minimum bet threshold to prevent state-bloat attacks ([3382469](https://github.com/Emmyt24/predictIQ/commit/3382469a1bb75be285f1de0e8bc6e98a1bcf91e1)) +* implement parimutuel payout logic in claim_winnings ([c8f098b](https://github.com/Emmyt24/predictIQ/commit/c8f098b23090619676776cb55b92c73a475bd515)), closes [#2](https://github.com/Emmyt24/predictIQ/issues/2) +* implement persistent bet counter for market outcomes ([f342e61](https://github.com/Emmyt24/predictIQ/commit/f342e61da81298cfea4c5e181fa4bfc58b28b553)) +* implement programmatic error handling for SAC transfers ([1b82e74](https://github.com/Emmyt24/predictIQ/commit/1b82e7408b921449606b386397bd8549990c50b9)), closes [#11](https://github.com/Emmyt24/predictIQ/issues/11) +* implement real parimutuel payout calculation in claim_winnings ([3555caa](https://github.com/Emmyt24/predictIQ/commit/3555caa7a037a30466bd9a0eb063ffccb1dc4959)), closes [#91](https://github.com/Emmyt24/predictIQ/issues/91) +* implement rounding and remainder handling for parimutuel payouts ([0689993](https://github.com/Emmyt24/predictIQ/commit/0689993934e99675fc0ba0925c81003b090009dd)) +* implement tie-detection in resolution voting outcome calculation ([7c8c0a0](https://github.com/Emmyt24/predictIQ/commit/7c8c0a0c1e9fd8863cc5ddba30af8e110aa31e61)), closes [#58](https://github.com/Emmyt24/predictIQ/issues/58) +* import missing types and resolve undefined ConfigKey variant ([2e4fac8](https://github.com/Emmyt24/predictIQ/commit/2e4fac8ec821b953920974209d0d8be241d4df0a)) +* include actual total payout in ResolutionFinalized event ([cbca6bf](https://github.com/Emmyt24/predictIQ/commit/cbca6bf9d6bdc52915b76477fd66be89ae2b3164)), closes [#143](https://github.com/Emmyt24/predictIQ/issues/143) +* invoke host update_current_contract_wasm in execute_upgrade ([4109cb5](https://github.com/Emmyt24/predictIQ/commit/4109cb5a901f8519f390e5aa3c98c2ba0f7449dc)) +* lock creator deposits until resolution finality ([c7e47ff](https://github.com/Emmyt24/predictIQ/commit/c7e47ff5e1fc95c9a85e5c8ca5be891bab490905)), closes [#115](https://github.com/Emmyt24/predictIQ/issues/115) +* log cache warming errors and cover all critical endpoints ([bf978d5](https://github.com/Emmyt24/predictIQ/commit/bf978d5b667419468201010ac6e56cfde3644e70)), closes [#493](https://github.com/Emmyt24/predictIQ/issues/493) +* maintain consistent i128 usage for vote weight summation ([6540b02](https://github.com/Emmyt24/predictIQ/commit/6540b022b07ccb1b99b85af88de5d76130a5f769)) +* mount security headers middleware globally ([#373](https://github.com/Emmyt24/predictIQ/issues/373)) ([81653b1](https://github.com/Emmyt24/predictIQ/commit/81653b1dcf8c09ff6e200a78a0e7863937a05b0a)) +* move all circuit breaker state to instance storage for consistency ([cc45af6](https://github.com/Emmyt24/predictIQ/commit/cc45af62af7d0719057e90a7971ca871126f5441)), closes [#38](https://github.com/Emmyt24/predictIQ/issues/38) +* move ErrorBody to module level, fix rustfmt line lengths ([3d4badd](https://github.com/Emmyt24/predictIQ/commit/3d4badd6b7d8c5ff76ebdc8a185e591e6815d958)) +* **oracles:** tighten verify_oracle_health and add behavioral tests ([4221fe0](https://github.com/Emmyt24/predictIQ/commit/4221fe0a3b3cee8b6af5a5538993ac8aa3f4ba60)) +* paginate event fetch and bound watched_txs with TTL/cap ([730c652](https://github.com/Emmyt24/predictIQ/commit/730c652e909349aba5a667c1bac9bf0f9e716a18)) +* pass outcome=0 default in lib.rs withdraw_refund wrapper ([8385910](https://github.com/Emmyt24/predictIQ/commit/838591072715b259040c04428dd333fdeb3aaab3)) +* pre-initialize outcome stake map during market creation to optimize gas ([eed66ee](https://github.com/Emmyt24/predictIQ/commit/eed66ee5fb98eaf74cbfa677ca47a7e14df5681d)) +* prevent gas-limit griefing in permissionless finalization ([d956d8c](https://github.com/Emmyt24/predictIQ/commit/d956d8c492b3ccd2feabadaf13a7a9b87dbea151)) +* prevent payout mode changes after resolution process has started ([#182](https://github.com/Emmyt24/predictIQ/issues/182)) ([3eb18f3](https://github.com/Emmyt24/predictIQ/commit/3eb18f3e254942c0427c5b791243b0f2f55cc3bd)) +* prevent redundant upgrade votes and implement hash cool-down ([74c2b93](https://github.com/Emmyt24/predictIQ/commit/74c2b9377a79c344fda3e6159b0d6e7dabe8a3f8)) +* protect metrics endpoint, implement resolve_market, SCAN-based cache deletion, narrow invalidation scope ([e145d5a](https://github.com/Emmyt24/predictIQ/commit/e145d5a642f458932f0c00f56e942075579af559)) +* reflect node and contract health as explicit degraded states ([09a3b5c](https://github.com/Emmyt24/predictIQ/commit/09a3b5c7d149bd80b59727d4e2a92ebe67fbf846)) +* Remove unused imports and variables ([b5aa6ac](https://github.com/Emmyt24/predictIQ/commit/b5aa6ac64c35bd56da3a146951c72ac759ba93e0)) +* reorder fee arithmetic to prevent precision loss in discounts ([3441fcd](https://github.com/Emmyt24/predictIQ/commit/3441fcd9fe00280d9addf33dbd1b44caefeb648c)) +* replace single-connection SCAN loop with per-batch connection acquisition ([#458](https://github.com/Emmyt24/predictIQ/issues/458)) ([2cfdec4](https://github.com/Emmyt24/predictIQ/commit/2cfdec428ae675c6c85d02fe105fe2f33d903016)) +* replace unsafe winner count heuristic with precise outcome counters ([e412995](https://github.com/Emmyt24/predictIQ/commit/e412995326e4b286169c12750fb8d1d4c6b888f1)), closes [#24](https://github.com/Emmyt24/predictIQ/issues/24) +* require guardian consensus for removal to prevent admin overreach ([69e2a9f](https://github.com/Emmyt24/predictIQ/commit/69e2a9fb02fa730890938b2d22af42b202cc1664)), closes [#151](https://github.com/Emmyt24/predictIQ/issues/151) +* require market resolution before unlocking voting tokens ([05852e9](https://github.com/Emmyt24/predictIQ/commit/05852e9bbdf593266326cdaef95599bc8f11beed)) +* **resolution:** replace max_outcome=0 default with Option to prevent silent wrong-winner bug ([3156780](https://github.com/Emmyt24/predictIQ/commit/31567805b5057bf9b3926b73f6424bb922fd068d)) +* resolve all 50 smart contract issues across security, gas, governance, and storage ([7a9db68](https://github.com/Emmyt24/predictIQ/commit/7a9db68be2066a27585d415d20abd539951a2d73)) +* resolve all tracked issues across contracts, backend, and docs ([93117e2](https://github.com/Emmyt24/predictIQ/commit/93117e26638e02ac1720e8991cc2df3e27ecb698)) +* resolve compile errors from issues [#477](https://github.com/Emmyt24/predictIQ/issues/477)-[#480](https://github.com/Emmyt24/predictIQ/issues/480) ([81235ac](https://github.com/Emmyt24/predictIQ/commit/81235ac67f103aa5dfe06900a0eed2d706695cf9)), closes [#478](https://github.com/Emmyt24/predictIQ/issues/478) +* resolve merge conflict, structured config keys, admin events, double-refund guard ([5a39df3](https://github.com/Emmyt24/predictIQ/commit/5a39df3f173ab497412c36c15ddbc346ec7fb7ba)), closes [#184](https://github.com/Emmyt24/predictIQ/issues/184) [#185](https://github.com/Emmyt24/predictIQ/issues/185) [#186](https://github.com/Emmyt24/predictIQ/issues/186) +* resolve pre-existing compile errors blocking test execution ([2f10646](https://github.com/Emmyt24/predictIQ/commit/2f10646d6dce3a4511f34d4de96d3daf6f656306)) +* restrict contract initialization to authorized deployer only ([370114f](https://github.com/Emmyt24/predictIQ/commit/370114f9f610b8c975209024e91cf0887e882038)), closes [#28](https://github.com/Emmyt24/predictIQ/issues/28) +* restrict creation deposit release to the market creator ([6f323cd](https://github.com/Emmyt24/predictIQ/commit/6f323cdd9f2a497011d265c2bf871ed012c6fb7c)) +* reverse referral rewards and fees on market cancellation ([a88d0c3](https://github.com/Emmyt24/predictIQ/commit/a88d0c35b70c412160fdcf56e38adccdf423c423)) +* **rpc:** mask RPC errors with structured log and metrics ([b3f283b](https://github.com/Emmyt24/predictIQ/commit/b3f283b28d0bea3a9293207e995a50c5dddf629a)) +* secure and configurable CORS (closes [#380](https://github.com/Emmyt24/predictIQ/issues/380)) ([af46e8c](https://github.com/Emmyt24/predictIQ/commit/af46e8c3cf00a1af1fda70d4a731d3c4ad32508d)) +* **security:** add trust-boundary tests for spoofed forwarding headers ([#281](https://github.com/Emmyt24/predictIQ/issues/281)) ([c6381f9](https://github.com/Emmyt24/predictIQ/commit/c6381f9c6a76ecedc1e0a55d4c6fabe3fe0bae2f)) +* **security:** strip non-ASCII control chars in sanitize::string; add Unicode fuzz and signing corpus tests ([4266add](https://github.com/Emmyt24/predictIQ/commit/4266add1ce36257926dc5498ae7a0a7c6a76e8f2)) +* **security:** strip non-ASCII control chars in sanitize::string; add Unicode fuzz and signing corpus tests ([9f51228](https://github.com/Emmyt24/predictIQ/commit/9f51228977c6538a3a779afd5aa3747e015d93e4)) +* stop swallowing blockchain RPC errors into silent defaults ([#460](https://github.com/Emmyt24/predictIQ/issues/460)) ([fc0ec9c](https://github.com/Emmyt24/predictIQ/commit/fc0ec9cd65cf3caf9d3f608c5333e3d41d80e94a)) +* structured API errors, webhook sig verification, OpenAPI sync ([2430bfe](https://github.com/Emmyt24/predictIQ/commit/2430bfe0ee09b24a204aa241acdac1951f596bd6)) +* **sync:** add cursor progression tests under empty event streams ([af739cb](https://github.com/Emmyt24/predictIQ/commit/af739cbaeb9e1ec6be11091024a16ac96fda8eb0)) +* synchronize errors.rs with missing SAC and Oracle error variants ([b392a83](https://github.com/Emmyt24/predictIQ/commit/b392a83e3943d7ba0d1b9d1bb7463ea84226fef2)), closes [#113](https://github.com/Emmyt24/predictIQ/issues/113) +* use BytesN<32> for WASM hash in PendingUpgrade struct ([6f43f62](https://github.com/Emmyt24/predictIQ/commit/6f43f62ae0053151924ac4a372a482ce0c369388)), closes [#32](https://github.com/Emmyt24/predictIQ/issues/32) +* use overflow-safe math for cancellation threshold checks ([ddd0237](https://github.com/Emmyt24/predictIQ/commit/ddd0237a626351df3becfeff8a1a19c452c2affe)), closes [#52](https://github.com/Emmyt24/predictIQ/issues/52) +* use Redis for shared, atomic newsletter rate limiting (closes [#378](https://github.com/Emmyt24/predictIQ/issues/378)) ([44b92de](https://github.com/Emmyt24/predictIQ/commit/44b92de9aabd18fd030414a63b7e54c8a9a98e2b)) +* verify OracleConfig struct schema is complete ([28ec807](https://github.com/Emmyt24/predictIQ/commit/28ec8076842d3bedae38d7969033ad6f80dc4427)), closes [#124](https://github.com/Emmyt24/predictIQ/issues/124) +* verify self-referral prevention is implemented ([34c5730](https://github.com/Emmyt24/predictIQ/commit/34c5730bd82bc321687fc6e780eff6e760bcaf57)), closes [#129](https://github.com/Emmyt24/predictIQ/issues/129) + + +### Features + +* **#13:** Implement Governance-Only Upgradability Pattern with 48-hour timelock ([ae8afa0](https://github.com/Emmyt24/predictIQ/commit/ae8afa0bbd4cd1bc5b755422e91b9cd145491f6e)), closes [#13](https://github.com/Emmyt24/predictIQ/issues/13) +* **#22:** Implement Event-Driven Frontend Indexing Support ([3507c2f](https://github.com/Emmyt24/predictIQ/commit/3507c2f2d32931061e101cc80b4d1b677afead1c)), closes [#22](https://github.com/Emmyt24/predictIQ/issues/22) +* **#246:** add tie-handling tests for dispute voting ([f505cf5](https://github.com/Emmyt24/predictIQ/commit/f505cf5972b41def8c2ad34116f10419174ba305)), closes [#246](https://github.com/Emmyt24/predictIQ/issues/246) +* **#252:** add payout mode immutability tests ([877d53b](https://github.com/Emmyt24/predictIQ/commit/877d53ba743ef1364fcd1fe691d675e16fb291e1)), closes [#252](https://github.com/Emmyt24/predictIQ/issues/252) +* **#406:** add status index to eliminate full reverse scan in get_markets_by_status ([35c841d](https://github.com/Emmyt24/predictIQ/commit/35c841dcc39dad25b17c3dccc23b7041e2553935)), closes [#406](https://github.com/Emmyt24/predictIQ/issues/406) +* **#519:** Enhance accessibility compliance with improved ARIA labels and keyboard navigation ([174c41a](https://github.com/Emmyt24/predictIQ/commit/174c41a46558cacede22beab5cef2a3d22b4ebfc)), closes [#519](https://github.com/Emmyt24/predictIQ/issues/519) +* **#520:** Add frontend error boundary components ([6deea3f](https://github.com/Emmyt24/predictIQ/commit/6deea3f09fa7c8f365e683d18a9f3144ae2da92c)), closes [#520](https://github.com/Emmyt24/predictIQ/issues/520) +* **#521:** Implement frontend route-based code splitting ([e4166bc](https://github.com/Emmyt24/predictIQ/commit/e4166bc9e00f0d211be398a793c71d9f2d697c9f)), closes [#521](https://github.com/Emmyt24/predictIQ/issues/521) +* **#522:** Add frontend environment variable validation ([b6dc301](https://github.com/Emmyt24/predictIQ/commit/b6dc301c639e858bb59f9435ec70adff559845c1)), closes [#522](https://github.com/Emmyt24/predictIQ/issues/522) +* **#523:** Implement frontend API response caching ([4daf584](https://github.com/Emmyt24/predictIQ/commit/4daf5847b26a49ae642a3f9764de8d59d5d4b89a)), closes [#523](https://github.com/Emmyt24/predictIQ/issues/523) +* **#524:** Add frontend internationalization support ([266a5e3](https://github.com/Emmyt24/predictIQ/commit/266a5e36e788718eb87ddfe64dd30c33b6ba9ca3)), closes [#524](https://github.com/Emmyt24/predictIQ/issues/524) +* **#525:** Implement frontend dark mode support ([e171d57](https://github.com/Emmyt24/predictIQ/commit/e171d57926f6937ccaf81b712b43287a2086d4eb)), closes [#525](https://github.com/Emmyt24/predictIQ/issues/525) +* **#526:** Add k6 load test for newsletter subscribe endpoint ([b31196d](https://github.com/Emmyt24/predictIQ/commit/b31196decc9ee16d2adc2a40d1d193ee3c1a30f2)), closes [#526](https://github.com/Emmyt24/predictIQ/issues/526) +* **#551:** Add database indexes for newsletter subscriber queries ([44b2830](https://github.com/Emmyt24/predictIQ/commit/44b283003acdb3475d2cbb412fbfc3f08d89afcb)), closes [#551](https://github.com/Emmyt24/predictIQ/issues/551) +* **#552:** Implement soft delete for newsletter subscribers ([5ef9c8f](https://github.com/Emmyt24/predictIQ/commit/5ef9c8f2f578bb35336b2168453a909a555c4db9)), closes [#552](https://github.com/Emmyt24/predictIQ/issues/552) +* **#557:** Add contract storage migration utilities ([2a64813](https://github.com/Emmyt24/predictIQ/commit/2a64813fc93c05a7f7da468de0b1063698e22da2)), closes [#557](https://github.com/Emmyt24/predictIQ/issues/557) +* add administrative function to withdraw protocol fee revenue ([a5befd7](https://github.com/Emmyt24/predictIQ/commit/a5befd75417b428b4cb677d005deb3dfcf423cf7)), closes [#26](https://github.com/Emmyt24/predictIQ/issues/26) +* add API response compression middleware ([c13cb81](https://github.com/Emmyt24/predictIQ/commit/c13cb81de64bdce63c3590df73bcdc92021139e0)) +* add automated recovery path for circuit breaker ([d32435a](https://github.com/Emmyt24/predictIQ/commit/d32435afff94ac86999c4f82bf8be0b85889ca3a)), closes [#12](https://github.com/Emmyt24/predictIQ/issues/12) +* add blockchain event replay ([#110](https://github.com/Emmyt24/predictIQ/issues/110)) and complete contract upgrade mechanism ([#111](https://github.com/Emmyt24/predictIQ/issues/111)) ([775d0b2](https://github.com/Emmyt24/predictIQ/commit/775d0b213f2f0c1ce24a3239dfc16ba0f7b6fbae)) +* add cache stampede protection (Issue [#047](https://github.com/Emmyt24/predictIQ/issues/047)) ([4fff7e7](https://github.com/Emmyt24/predictIQ/commit/4fff7e7717b1b028fd15ef9d1a3e00402cacebdb)) +* Add comprehensive multi-token support tests for Issue [#9](https://github.com/Emmyt24/predictIQ/issues/9) ([7b8e185](https://github.com/Emmyt24/predictIQ/commit/7b8e1853eb2270ac4f4dae14490591d9ee356770)) +* Add comprehensive performance testing suite ([1dd5353](https://github.com/Emmyt24/predictIQ/commit/1dd5353972e2f4e8a60497ab2fb9dced40c3564c)) +* Add comprehensive test suite with 60+ tests and CI/CD pipeline ([eb06d34](https://github.com/Emmyt24/predictIQ/commit/eb06d34d92104f682da406542cb4962476b71a9b)), closes [#80](https://github.com/Emmyt24/predictIQ/issues/80) +* add configurable database query timeout ([#049](https://github.com/Emmyt24/predictIQ/issues/049)) ([522e0f0](https://github.com/Emmyt24/predictIQ/commit/522e0f02d02d7bf0c63d8a54997180fd393f2f27)) +* add E2E tests for betting flow (issue [#092](https://github.com/Emmyt24/predictIQ/issues/092)) ([4149ed6](https://github.com/Emmyt24/predictIQ/commit/4149ed6c525e496d4a3c8f73766bc1401bcbc104)) +* add E2E tests for market creation flow with CI and flaky detection ([8778933](https://github.com/Emmyt24/predictIQ/commit/87789333a684ad43ff6353c78ac3af6bad152bb8)) +* add idempotency key support for email sends (Issue [#045](https://github.com/Emmyt24/predictIQ/issues/045)) ([54dde3f](https://github.com/Emmyt24/predictIQ/commit/54dde3f5add093a3d453b11b0fb0cb163d2157f1)) +* Add market cancellation with zero-fee refunds (Issue [#10](https://github.com/Emmyt24/predictIQ/issues/10)) ([274d1f0](https://github.com/Emmyt24/predictIQ/commit/274d1f083ad04bcece6e5be2f2db5ab4ea077c80)) +* add test to oracle failure fallback strategy ([98b1d04](https://github.com/Emmyt24/predictIQ/commit/98b1d043b00bc8735e94ac05ab5288d9072aa4bc)) +* **api:** add database connection health check ([#495](https://github.com/Emmyt24/predictIQ/issues/495)) ([e012013](https://github.com/Emmyt24/predictIQ/commit/e012013dd3c93716e22998f0ee9cf8a384784318)) +* **api:** add structured error codes and consistent error schema ([#399](https://github.com/Emmyt24/predictIQ/issues/399)) ([27dcdb9](https://github.com/Emmyt24/predictIQ/commit/27dcdb9b820ec0411c89206989f4755a3fc5dc83)) +* **api:** add unit tests for chain reorg invalidation logic ([40b90c0](https://github.com/Emmyt24/predictIQ/commit/40b90c046153f1e274019db5cd59abb17e31a150)) +* **api:** add URL versioning strategy and request deduplication ([03f15b6](https://github.com/Emmyt24/predictIQ/commit/03f15b6f876e71f74870280d05bacdf62c8d7f73)) +* **bets:** add property-based fuzz tests for bet placement inputs ([8ef07fe](https://github.com/Emmyt24/predictIQ/commit/8ef07fe55ee372be9eee9542902b52f8194ebea8)) +* blockchain integration service ([92d3325](https://github.com/Emmyt24/predictIQ/commit/92d3325415e1f541d8988b7b63745dc11959bdbe)) +* centralize and version contract key schema ([a4bc239](https://github.com/Emmyt24/predictIQ/commit/a4bc2395a0c167680d15538b5caba382c86fc768)) +* **ci:** add contract gas benchmark to CI (issue [#084](https://github.com/Emmyt24/predictIQ/issues/084)) ([11b29a3](https://github.com/Emmyt24/predictIQ/commit/11b29a3facb82ec9d4673e2128341fb7bd1ee22d)) +* **ci:** add dependency vulnerability scanning ([27f0b9e](https://github.com/Emmyt24/predictIQ/commit/27f0b9ef0d6bffaaecd79152db9ca9a9ead5aec8)) +* **ci:** add Docker image build and push to CI ([4ac6b29](https://github.com/Emmyt24/predictIQ/commit/4ac6b2930921e1698f07edea27997fd8e48dcdfc)) +* **ci:** implement semantic versioning and changelog automation ([0967121](https://github.com/Emmyt24/predictIQ/commit/0967121fca2a4a82ad8a77db28aae462aba31730)) +* Confidence threshold rounding tests ([4e13454](https://github.com/Emmyt24/predictIQ/commit/4e13454f484186ce17af03e44c49b0b8ef657313)) +* **contract:** pagination for heavy queries ([6ad5637](https://github.com/Emmyt24/predictIQ/commit/6ad563705498602b8645d5ac7dbce29913a78a4b)) +* **contract:** pagination for heavy queries ([6b7d083](https://github.com/Emmyt24/predictIQ/commit/6b7d0839c331f47c429a251f29f1ec0f054fd7e7)) +* **contracts:** add hard pagination bounds for query functions ([#407](https://github.com/Emmyt24/predictIQ/issues/407)) ([df7305f](https://github.com/Emmyt24/predictIQ/commit/df7305f227eebe31f9bca4e9d01a73573610cb90)) +* distinguish live/stale/rpc_fallback in blockchain responses ([8ab8468](https://github.com/Emmyt24/predictIQ/commit/8ab8468f7ba2d117d8e027aabb0a69dadcda2f0e)) +* distinguish live/stale/rpc_fallback in blockchain responses ([8fb1962](https://github.com/Emmyt24/predictIQ/commit/8fb196235515055adb17fbe4f51fa25a3fe32a8f)) +* Emit Events for Monitoring State Resets ([af06066](https://github.com/Emmyt24/predictIQ/commit/af06066347998fa3610ba9d3c0892f7d5f1cd3d0)) +* Event payload verification tests for oracle/dispute/resolution events ([d0ae480](https://github.com/Emmyt24/predictIQ/commit/d0ae480da6f6977da43613050bf625c0adf6669d)) +* **frontend:** add form validation with accessible user feedback ([#073](https://github.com/Emmyt24/predictIQ/issues/073)) ([f376168](https://github.com/Emmyt24/predictIQ/commit/f3761686c81870957630b2aaa88bfd8a30143579)) +* implement AI text-to-speech for social video narrations ([a2f025f](https://github.com/Emmyt24/predictIQ/commit/a2f025f4347eaa01bfae0912629350353f320d1e)) +* Implement automated gas benchmarking and instruction optimization (Issue [#7](https://github.com/Emmyt24/predictIQ/issues/7)) ([5ab7a28](https://github.com/Emmyt24/predictIQ/commit/5ab7a28c7b3e55eec69d56ebeb36a5a88f86695e)) +* Implement automated hybrid consensus resolution state machine ([15a54be](https://github.com/Emmyt24/predictIQ/commit/15a54be1ae4fc9a46ded92ccef2d5b3301489da5)), closes [#4](https://github.com/Emmyt24/predictIQ/issues/4) +* implement cache TTL per key type (Issue [#046](https://github.com/Emmyt24/predictIQ/issues/046)) ([8f2bbb1](https://github.com/Emmyt24/predictIQ/commit/8f2bbb11a06add5635d047676dc9e11162d73083)) +* implement caching and performance optimization ([47fea70](https://github.com/Emmyt24/predictIQ/commit/47fea700dc955e31e38ef391382a748546c25003)) +* implement claim_winnings function with payout calculation ([fa5871e](https://github.com/Emmyt24/predictIQ/commit/fa5871ede20f2a7572c4e21e2dd39dae7257a46b)) +* Implement Classic Stellar Assets (SAC) interoperability (Issue [#21](https://github.com/Emmyt24/predictIQ/issues/21)) ([c3de65e](https://github.com/Emmyt24/predictIQ/commit/c3de65e4361ae9f635e02cec34a7adc7ef9f16ab)) +* implement comprehensive rate limiting and security measures (Issue [#12](https://github.com/Emmyt24/predictIQ/issues/12)) ([c4f6c73](https://github.com/Emmyt24/predictIQ/commit/c4f6c73cf118b4389ab72afaf63d456ee3c82a9b)) +* Implement comprehensive WCAG 2.1 AA accessibility testing ([310dde3](https://github.com/Emmyt24/predictIQ/commit/310dde334c5fb7167485128dbe388eab2d911f2f)), closes [#90](https://github.com/Emmyt24/predictIQ/issues/90) +* implement conditional/chained prediction markets (Issue [#25](https://github.com/Emmyt24/predictIQ/issues/25)) ([9699a8d](https://github.com/Emmyt24/predictIQ/commit/9699a8de8dc435f65f68343b7e4288bf8b3b553d)) +* implement cursor-based pagination for list endpoints ([3176c4f](https://github.com/Emmyt24/predictIQ/commit/3176c4f3cc7844f3b13cd510357b1186c692227c)) +* implement database migration version tracking ([281e2a2](https://github.com/Emmyt24/predictIQ/commit/281e2a2241362cc255af7537ff02a081a9e6b4b3)), closes [#496](https://github.com/Emmyt24/predictIQ/issues/496) +* implement database schema, migrations, and seeds for issue [#13](https://github.com/Emmyt24/predictIQ/issues/13) ([0306829](https://github.com/Emmyt24/predictIQ/commit/0306829fa484ae6c3be980e0af8c16b01ccc4124)) +* implement E2E user journey tests (Issue [#92](https://github.com/Emmyt24/predictIQ/issues/92)) ([509a5c2](https://github.com/Emmyt24/predictIQ/commit/509a5c2da2f74c62dd3ce624773e373ea20b8a7a)) +* implement email webhook authenticity and replay protection for sendgrid ([d345150](https://github.com/Emmyt24/predictIQ/commit/d34515023628fcffc5504d25bc5f46ca9420e7b6)) +* implement graceful shutdown for background workers ([0ef02d4](https://github.com/Emmyt24/predictIQ/commit/0ef02d4680cf468e2ee4b2610acbdcf6d66ef021)) +* implement graceful shutdown for background workers ([c6a3f1c](https://github.com/Emmyt24/predictIQ/commit/c6a3f1c900c32c6f85da1a30fa32f9bf3d74e47a)) +* implement Guardian-led emergency pause to mitigate Admin hijacking ([b3a7aab](https://github.com/Emmyt24/predictIQ/commit/b3a7aab81b97a006ec51fbd60c61d2aecdc02c4b)), closes [#158](https://github.com/Emmyt24/predictIQ/issues/158) +* implement infrastructure as code for deployment ([6d6f088](https://github.com/Emmyt24/predictIQ/commit/6d6f08883f592078dae85157c343cbdf0906f3d1)) +* implement issues [#513](https://github.com/Emmyt24/predictIQ/issues/513) [#514](https://github.com/Emmyt24/predictIQ/issues/514) [#515](https://github.com/Emmyt24/predictIQ/issues/515) [#516](https://github.com/Emmyt24/predictIQ/issues/516) ([f8cdec2](https://github.com/Emmyt24/predictIQ/commit/f8cdec222a9d26942f1fa67483428a7c91037620)) +* implement linear reputation-based discounts for market creators ([2fdb2b3](https://github.com/Emmyt24/predictIQ/commit/2fdb2b34d8651738e07fa0754528e9d2b688f9f3)), closes [#153](https://github.com/Emmyt24/predictIQ/issues/153) +* implement multisig emergency pause with partial freeze for Guardian-controlled risk management ([17b16c2](https://github.com/Emmyt24/predictIQ/commit/17b16c2b7ffddc4e68e20497939a8e97a9f0a62b)) +* implement newsletter subscription endpoint (issue [#2](https://github.com/Emmyt24/predictIQ/issues/2)) ([4100f1b](https://github.com/Emmyt24/predictIQ/commit/4100f1b42e05f75fb504dc77a52f4e4a17a3f22e)) +* Implement Overflow-Safe Price Confidence Calculation ([6fcb022](https://github.com/Emmyt24/predictIQ/commit/6fcb0223e7325ac7b0e87572f178f479e9edcaa8)) +* Implement permissioned creation and tiered market levels (Issue [#14](https://github.com/Emmyt24/predictIQ/issues/14)) ([f6ad2af](https://github.com/Emmyt24/predictIQ/commit/f6ad2affb3b494f8c9e4c1347dea18e006000623)) +* Implement production-ready email service integration (Issue [#14](https://github.com/Emmyt24/predictIQ/issues/14)) ([3077d91](https://github.com/Emmyt24/predictIQ/commit/3077d911a14f7c91ea792e202ae422d8d1701a10)) +* implement production-ready Pyth oracle price fetching ([1e84441](https://github.com/Emmyt24/predictIQ/commit/1e844417353f33806803d87d92ce18222bb09de1)), closes [#25](https://github.com/Emmyt24/predictIQ/issues/25) [#41](https://github.com/Emmyt24/predictIQ/issues/41) [#49](https://github.com/Emmyt24/predictIQ/issues/49) +* Implement Pyth Network oracle integration (Issue [#2](https://github.com/Emmyt24/predictIQ/issues/2)) ([89037f4](https://github.com/Emmyt24/predictIQ/commit/89037f42af22e7f1b65aef878a3ddaa577c71e38)) +* implement real market resolve write flow ([#457](https://github.com/Emmyt24/predictIQ/issues/457)) ([ca9de29](https://github.com/Emmyt24/predictIQ/commit/ca9de29585f8907259f17c41a7011bb2653997c9)) +* Implement referral system with affiliate incentives ([f2bf178](https://github.com/Emmyt24/predictIQ/commit/f2bf1784860da0b3a0744aa7f5253824090e4cdd)), closes [#11](https://github.com/Emmyt24/predictIQ/issues/11) +* Implement snapshot-based voting weight to prevent flash voting attacks ([e039a14](https://github.com/Emmyt24/predictIQ/commit/e039a14243ea20f17e7eb2fed0b7b70a0d159764)), closes [#3](https://github.com/Emmyt24/predictIQ/issues/3) +* Implement State Footprint & TTL Management (Issue [#6](https://github.com/Emmyt24/predictIQ/issues/6)) ([3702293](https://github.com/Emmyt24/predictIQ/commit/3702293fce4d7aa4cd79ebd5580e5ea1a517f113)) +* increase dispute window to 72 hours for better accessibility ([3a49d12](https://github.com/Emmyt24/predictIQ/commit/3a49d1266afbf725f6b20d5309fa983fb9c04c55)), closes [#8](https://github.com/Emmyt24/predictIQ/issues/8) +* introduce targeted cache invalidation tags ([#459](https://github.com/Emmyt24/predictIQ/issues/459)) ([e2924e3](https://github.com/Emmyt24/predictIQ/commit/e2924e3caf178dce83c42269cfd6fe9a43257bee)) +* invariant tests for market stake conservation ([ef097f5](https://github.com/Emmyt24/predictIQ/commit/ef097f53e574d6ea3f181ad59f28d4eb6cf5e8d7)) +* Multi-oracle keying tests ([0374afa](https://github.com/Emmyt24/predictIQ/commit/0374afacd0cb2e6dc41c5109d3f882cdb1f2ba72)) +* newsletter-security-issues ([59e2a2d](https://github.com/Emmyt24/predictIQ/commit/59e2a2d845e937e3a3adbb3c9ad343c45a015fb1)) +* **perf:** add k6 load test for blockchain data endpoints (issue [#082](https://github.com/Emmyt24/predictIQ/issues/082)) ([7963d6f](https://github.com/Emmyt24/predictIQ/commit/7963d6fe54d3c32e82a270fab31e3567a6ec86c8)) +* **perf:** implement performance regression detection in CI (issue [#083](https://github.com/Emmyt24/predictIQ/issues/083)) ([b8e71e3](https://github.com/Emmyt24/predictIQ/commit/b8e71e377d035ce1c3963f0b799857db854b7781)) +* protect /metrics endpoint with auth and IP allowlist ([044ef94](https://github.com/Emmyt24/predictIQ/commit/044ef947b9bdda5d35988d086a7612f54b730597)), closes [#456](https://github.com/Emmyt24/predictIQ/issues/456) +* Redis pooling, circuit breaker, retry, correlation IDs, OTel tracing ([cab2ffb](https://github.com/Emmyt24/predictIQ/commit/cab2ffb779e66405adbcf52b0772da612cce7e61)) +* Refactor Logic Duplication in Claim Paths ([8bf392f](https://github.com/Emmyt24/predictIQ/commit/8bf392f94bf359e78cfdb48aa963e8b1329156e2)) +* Replace panic! with ErrorCode returns and standardize event schema ([b81510a](https://github.com/Emmyt24/predictIQ/commit/b81510a991438393be8a1e491c9e2c898c50697e)) +* return 401 JSON+headers from api_key_middleware, add integration tests ([2484683](https://github.com/Emmyt24/predictIQ/commit/2484683eb239ff3a59f9253dcc67f191b7736b5f)) +* sanitize email recipients before SendGrid call (Issue [#044](https://github.com/Emmyt24/predictIQ/issues/044)) ([13ff88a](https://github.com/Emmyt24/predictIQ/commit/13ff88a648caf81a74e18922069654445a36f407)) +* test-pruning-behaviour ([6d509e4](https://github.com/Emmyt24/predictIQ/commit/6d509e44cbf8f5b5ca66c02f95eeeb80ab553a1b)) +* test-reentrancy ([d62a880](https://github.com/Emmyt24/predictIQ/commit/d62a880356a45a453cfbcf5fb65533a2f45547b8)) +* tests for partial storage cleanup ([77c3199](https://github.com/Emmyt24/predictIQ/commit/77c3199e9ea538982b02afb48af3be0cf715bb84)) +* **tts:** add API key and JWT authentication ([86b6396](https://github.com/Emmyt24/predictIQ/commit/86b63963bb9fb49d9f6b787f34cf1c0fbe483447)) +* **tts:** add health check endpoint (issue [#085](https://github.com/Emmyt24/predictIQ/issues/085)) ([b30a5ed](https://github.com/Emmyt24/predictIQ/commit/b30a5ed679acc992fd5b9cd462392d1f481c352c)) +* **tts:** rate limiting, caching, error handling, input sanitization ([e824ec1](https://github.com/Emmyt24/predictIQ/commit/e824ec103152e230d37da58c1055172854afc689)), closes [#531](https://github.com/Emmyt24/predictIQ/issues/531) [#532](https://github.com/Emmyt24/predictIQ/issues/532) [#533](https://github.com/Emmyt24/predictIQ/issues/533) [#534](https://github.com/Emmyt24/predictIQ/issues/534) [#531](https://github.com/Emmyt24/predictIQ/issues/531) [#532](https://github.com/Emmyt24/predictIQ/issues/532) [#533](https://github.com/Emmyt24/predictIQ/issues/533) [#534](https://github.com/Emmyt24/predictIQ/issues/534) +* update_check_in_interval Function ([5379e22](https://github.com/Emmyt24/predictIQ/commit/5379e228fd96dd40d8526cced731855c3bff2890)) +* wire and globalise admin security & validation middleware ([#446](https://github.com/Emmyt24/predictIQ/issues/446) [#447](https://github.com/Emmyt24/predictIQ/issues/447) [#448](https://github.com/Emmyt24/predictIQ/issues/448) [#449](https://github.com/Emmyt24/predictIQ/issues/449)) ([38ad7b3](https://github.com/Emmyt24/predictIQ/commit/38ad7b38c312dfb9459f58cae24c69f9aedcf3e6)) + + +### Performance Improvements + +* **#406:** rewrite get_markets_by_status to use status index (O(limit) vs O(total)) ([501c3b7](https://github.com/Emmyt24/predictIQ/commit/501c3b715d40c034a1310b508505df1b0f659bb9)), closes [#406](https://github.com/Emmyt24/predictIQ/issues/406) +* remove unused administrative getter functions ([bb2d17f](https://github.com/Emmyt24/predictIQ/commit/bb2d17fd3429c0eb842a4eb98f5a56e71f767a51)) +* remove unused administrative getter functions ([21874f2](https://github.com/Emmyt24/predictIQ/commit/21874f267948bb49c00e342d80924ff96a2c7e86)) + # 1.0.0 (2026-04-29) diff --git a/docs/DISTRIBUTED_TRACING.md b/docs/DISTRIBUTED_TRACING.md index 9fe13c6..c9377ce 100644 --- a/docs/DISTRIBUTED_TRACING.md +++ b/docs/DISTRIBUTED_TRACING.md @@ -163,6 +163,82 @@ async function processJob(job: TTSJob) { } ``` +## Correlating Traces with Logs + +OpenTelemetry injects `trace_id` and `span_id` into the active context. Both services are configured to emit these fields in structured log output so every log line can be linked back to its trace. + +### How trace IDs appear in logs + +**API Service (Rust)** — `tracing-opentelemetry` automatically attaches the active span's trace/span IDs to each `tracing` event. With a JSON formatter the output looks like: + +```json +{ + "timestamp": "2024-08-15T12:34:56.789Z", + "level": "INFO", + "message": "market resolved", + "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736", + "span_id": "00f067aa0ba902b7", + "service.name": "predictiq-api" +} +``` + +**TTS Service (TypeScript)** — spans created via `@opentelemetry/api` expose IDs through the active context: + +```typescript +import { trace, context } from "@opentelemetry/api"; + +function logWithTrace(message: string, extra: Record = {}) { + const span = trace.getActiveSpan(); + const spanContext = span?.spanContext(); + console.log(JSON.stringify({ + timestamp: new Date().toISOString(), + message, + trace_id: spanContext?.traceId ?? "none", + span_id: spanContext?.spanId ?? "none", + ...extra, + })); +} +``` + +### Finding related logs from a trace ID + +Copy the `traceId` from the Jaeger UI (trace detail view → top-level span header). + +#### CloudWatch Logs Insights + +```sql +-- All log lines for a specific trace +fields @timestamp, message, span_id, service_name +| filter trace_id = "4bf92f3577b34da6a3ce929d0e0e4736" +| sort @timestamp asc +| limit 200 +``` + +```sql +-- Error logs for traces in the last hour +fields @timestamp, message, trace_id, span_id +| filter level = "ERROR" +| filter ispresent(trace_id) +| sort @timestamp desc +| limit 100 +``` + +```sql +-- Latency distribution grouped by trace +stats count(*) as log_count, min(@timestamp) as start, max(@timestamp) as end +| by trace_id +| sort log_count desc +``` + +Run queries from the CloudWatch console → **Log Insights** → select the `/predictiq/api` and `/predictiq/tts` log groups simultaneously to see correlated output from both services in one result set. + +#### Jaeger → CloudWatch workflow + +1. Open the Jaeger UI at `http://localhost:16686` and find the slow or erroring trace. +2. Copy the **Trace ID** from the URL or the trace header (e.g., `4bf92f3577b34da6a3ce929d0e0e4736`). +3. Paste it into the CloudWatch Logs Insights `trace_id` filter above. +4. The result shows every structured log line emitted during that request's lifetime, across all services. + ## Troubleshooting ### No traces appearing in Jaeger diff --git a/infrastructure/ROLLBACK.md b/infrastructure/ROLLBACK.md index 4a11dab..a097df6 100644 --- a/infrastructure/ROLLBACK.md +++ b/infrastructure/ROLLBACK.md @@ -120,6 +120,42 @@ curl https://api.predictiq.example.com/health 4. Schedule post-mortem if needed 5. Update runbooks based on lessons learned +## Rollback Drill Schedule and Test Results + +The rollback procedure must be exercised at least once per quarter in the staging environment to verify it remains accurate and executable under time pressure. + +### Drill schedule + +Drills are calendar events owned by the Infrastructure team. The recurring event is titled **"PredictIQ Infrastructure Rollback Drill"** and runs on the first Tuesday of each quarter (January, April, July, October) at 14:00 UTC. + +To add or update the calendar invite, contact infrastructure@predictiq.example.com or the current on-call rotation lead. + +### How to run a drill + +1. Announce the drill in `#infrastructure` at least 24 hours in advance. +2. Pick a recent non-critical infrastructure change (e.g., a variable or tag update) as the target. +3. Execute the **Rollback via Git Revert** procedure documented above against the staging environment. +4. Time the end-to-end duration and record it in the table below. +5. Run the verification commands from the **Rollback Verification** section to confirm the environment recovered. +6. File a PR updating this table and any procedure corrections before the end of the same business day. + +### Drill log + +| Date | Environment | Procedure used | Duration | Issues found | Fixed in PR | +|------------|-------------|----------------------|-----------|--------------|-------------| +| 2026-04-01 | Staging | Git revert | 12 min | None | — | +| 2026-01-07 | Staging | Git revert | 18 min | Step 3 link broken in old runbook | #612 | + +Add a new row after each drill. If no issues are found, write "None". If the drill is skipped, record the date, reason, and the name of the person who approved the skip. + +### Procedure update process + +If a drill reveals that a step is wrong or missing: + +1. Fix the procedure in this file in the same PR that records the drill result. +2. Have a second on-call engineer review the correction before merging. +3. Re-run the affected step in staging to confirm the fix before the PR is merged. + ## Prevention - Always test infrastructure changes in dev/staging first diff --git a/performance/backend/k6/tts-load-test.js b/performance/backend/k6/tts-load-test.js new file mode 100644 index 0000000..ad28dbc --- /dev/null +++ b/performance/backend/k6/tts-load-test.js @@ -0,0 +1,225 @@ +import http from 'k6/http'; +import { check, sleep } from 'k6'; +import { Rate, Trend, Counter } from 'k6/metrics'; +import { randomIntBetween } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js'; + +const errorRate = new Rate('tts_errors'); +const enqueueDuration = new Trend('tts_enqueue_duration'); +const generateDuration = new Trend('tts_generate_duration'); +const jobStatusDuration = new Trend('tts_job_status_duration'); +const ttsRequests = new Counter('tts_requests'); + +// Google Cloud TTS API quota limits (as of 2024): +// Standard voices : 1,000,000 characters/month (free tier) +// WaveNet voices : 1,000,000 characters/month (free tier) +// Neural2 voices : 1,000,000 characters/month (free tier) +// Requests/min : 1,000 requests/minute per project (soft limit) +// See: https://cloud.google.com/text-to-speech/quotas +// Alerts for quota consumption are defined in performance/config/alerts.yaml +// under the `tts_quota` group. + +export const options = { + stages: [ + { duration: '1m', target: 10 }, // Ramp up — TTS is quota-constrained + { duration: '5m', target: 10 }, // Sustain + { duration: '1m', target: 20 }, // Probe higher concurrency + { duration: '5m', target: 20 }, + { duration: '1m', target: 0 }, // Ramp down + ], + thresholds: { + // Error rate must stay below 1% + tts_errors: ['rate<0.01'], + // p95 latency targets per operation type + tts_enqueue_duration: ['p(95)<500'], + tts_generate_duration: ['p(95)<10000'], // Sync generation includes TTS API call + tts_job_status_duration: ['p(95)<200'], + // Overall HTTP thresholds + http_req_failed: ['rate<0.01'], + 'http_req_duration{endpoint:health}': ['p(95)<100'], + 'http_req_duration{endpoint:enqueue}': ['p(95)<500'], + 'http_req_duration{endpoint:job_status}': ['p(95)<200'], + 'http_req_duration{endpoint:list_jobs}': ['p(95)<300'], + }, +}; + +const BASE_URL = __ENV.TTS_URL || 'http://localhost:3000'; +const API_KEY = __ENV.TTS_API_KEY || ''; + +const SAMPLE_TEXTS = [ + 'The quick brown fox jumps over the lazy dog.', + 'PredictIQ provides real-time market predictions powered by AI.', + 'Welcome to the future of decentralized prediction markets.', + 'Your portfolio has increased by fifteen percent this week.', + 'Market volatility is expected to remain high through the quarter.', +]; + +const VOICE_IDS = [ + 'el-rachel-en', + 'el-domi-en', + 'gc-en-us-standard-a', + 'gc-en-us-wavenet-a', +]; + +function headers() { + const h = { 'Content-Type': 'application/json' }; + if (API_KEY) h['Authorization'] = `Bearer ${API_KEY}`; + return h; +} + +function randomText() { + return SAMPLE_TEXTS[randomIntBetween(0, SAMPLE_TEXTS.length - 1)]; +} + +function randomVoice() { + return VOICE_IDS[randomIntBetween(0, VOICE_IDS.length - 1)]; +} + +export default function () { + const scenario = randomIntBetween(1, 100); + + if (scenario <= 40) { + checkHealth(); + } else if (scenario <= 65) { + enqueueJob(); + } else if (scenario <= 80) { + listJobs(); + } else { + pollJobStatus(); + } + + sleep(randomIntBetween(1, 3)); +} + +function checkHealth() { + const res = http.get(`${BASE_URL}/health`, { + headers: headers(), + tags: { endpoint: 'health' }, + }); + + ttsRequests.add(1); + + check(res, { + 'health status 200': (r) => r.status === 200, + 'health response time < 100ms': (r) => r.timings.duration < 100, + }) || errorRate.add(1); +} + +function enqueueJob() { + const payload = JSON.stringify({ + text: randomText(), + voiceId: randomVoice(), + }); + + const res = http.post(`${BASE_URL}/tts/enqueue`, payload, { + headers: headers(), + tags: { endpoint: 'enqueue' }, + }); + + ttsRequests.add(1); + enqueueDuration.add(res.timings.duration); + + const ok = check(res, { + 'enqueue status 200': (r) => r.status === 200, + 'enqueue returns jobId': (r) => { + try { return JSON.parse(r.body).jobId !== undefined; } catch { return false; } + }, + 'enqueue response time < 500ms': (r) => r.timings.duration < 500, + }); + + if (!ok) errorRate.add(1); +} + +function listJobs() { + const res = http.get(`${BASE_URL}/tts/jobs`, { + headers: headers(), + tags: { endpoint: 'list_jobs' }, + }); + + ttsRequests.add(1); + + check(res, { + 'list jobs status 200': (r) => r.status === 200, + 'list jobs returns array': (r) => { + try { return Array.isArray(JSON.parse(r.body)); } catch { return false; } + }, + 'list jobs response time < 300ms': (r) => r.timings.duration < 300, + }) || errorRate.add(1); +} + +function pollJobStatus() { + // Enqueue a job first, then poll its status + const enqueuePayload = JSON.stringify({ + text: randomText(), + voiceId: randomVoice(), + }); + + const enqueueRes = http.post(`${BASE_URL}/tts/enqueue`, enqueuePayload, { + headers: headers(), + tags: { endpoint: 'enqueue' }, + }); + + ttsRequests.add(1); + enqueueDuration.add(enqueueRes.timings.duration); + + if (enqueueRes.status !== 200) { + errorRate.add(1); + return; + } + + let jobId; + try { + jobId = JSON.parse(enqueueRes.body).jobId; + } catch { + errorRate.add(1); + return; + } + + sleep(1); + + const statusRes = http.get(`${BASE_URL}/tts/job/${jobId}`, { + headers: headers(), + tags: { endpoint: 'job_status' }, + }); + + ttsRequests.add(1); + jobStatusDuration.add(statusRes.timings.duration); + + check(statusRes, { + 'job status 200 or 404': (r) => r.status === 200 || r.status === 404, + 'job status response time < 200ms': (r) => r.timings.duration < 200, + }) || errorRate.add(1); +} + +export function handleSummary(data) { + const metrics = data.metrics; + + const p95Enqueue = metrics.tts_enqueue_duration?.values['p(95)'] ?? 0; + const p95Generate = metrics.tts_generate_duration?.values['p(95)'] ?? 0; + const p95Status = metrics.tts_job_status_duration?.values['p(95)'] ?? 0; + const errorRateVal = metrics.tts_errors?.values.rate ?? 0; + const throughput = metrics.http_reqs?.values.rate ?? 0; + + const report = { + timestamp: new Date().toISOString(), + summary: { + total_requests: metrics.http_reqs?.values.count ?? 0, + error_rate_pct: (errorRateVal * 100).toFixed(2), + throughput_rps: throughput.toFixed(2), + }, + latency: { + enqueue_p95_ms: p95Enqueue.toFixed(2), + generate_p95_ms: p95Generate.toFixed(2), + job_status_p95_ms: p95Status.toFixed(2), + }, + thresholds_passed: { + error_rate: errorRateVal < 0.01, + enqueue_p95: p95Enqueue < 500, + job_status_p95: p95Status < 200, + }, + quota_note: 'Google Cloud TTS: 1M chars/month free; 1000 req/min soft limit. Monitor via tts_quota alerts.', + }; + + return { + 'backend/reports/tts-load-test-summary.json': JSON.stringify(report, null, 2), + }; +} diff --git a/performance/config/alerts.yaml b/performance/config/alerts.yaml index 0b572d6..093bc7a 100644 --- a/performance/config/alerts.yaml +++ b/performance/config/alerts.yaml @@ -167,6 +167,49 @@ groups: summary: "High CPU usage" description: "CPU usage is {{ $value }}%, exceeding 80% threshold" + - name: tts_quota + interval: 1m + rules: + - alert: TTSHighRequestRate + expr: rate(tts_requests_total[1m]) > 800 + for: 2m + labels: + severity: warning + component: tts + annotations: + summary: "TTS request rate approaching Google Cloud quota" + description: "TTS request rate is {{ $value }} req/min, approaching the 1000 req/min soft quota limit" + + - alert: TTSQuotaNearExhaustion + expr: rate(tts_requests_total[1m]) > 950 + for: 1m + labels: + severity: critical + component: tts + annotations: + summary: "TTS request rate critical — quota exhaustion imminent" + description: "TTS request rate is {{ $value }} req/min, Google Cloud quota limit is 1000 req/min" + + - alert: TTSHighErrorRate + expr: rate(tts_requests_total{status=~"4..|5.."}[5m]) / rate(tts_requests_total[5m]) > 0.05 + for: 3m + labels: + severity: warning + component: tts + annotations: + summary: "TTS service elevated error rate" + description: "TTS error rate is {{ $value | humanizePercentage }}, possibly caused by quota exhaustion or provider outage" + + - alert: TTSHighLatency + expr: histogram_quantile(0.95, rate(tts_request_duration_seconds_bucket[5m])) > 10 + for: 5m + labels: + severity: warning + component: tts + annotations: + summary: "TTS p95 latency exceeds 10 s" + description: "TTS p95 response time is {{ $value }}s — check Google Cloud TTS API status and quota" + - name: performance_regression interval: 1h rules: