diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5fc0acc4..59f766fb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -52,7 +52,7 @@ repos: hooks: - id: ty name: ty (type check) - entry: uv run ty check . --exclude docs/** --exclude fern/** --exclude third_party/** --exclude ./examples/** --exclude .cache/** --exclude .claude/** + entry: uv run ty check . --force-exclude --exclude docs/ --exclude fern/ --exclude third_party/ --exclude examples/ --exclude .cache/ --exclude .claude/ language: system types: [python] pass_filenames: false diff --git a/ATTRIBUTIONS-Rust.md b/ATTRIBUTIONS-Rust.md index 9ccd2236..c46298db 100644 --- a/ATTRIBUTIONS-Rust.md +++ b/ATTRIBUTIONS-Rust.md @@ -119,6 +119,87 @@ limitations under the License. ``` +## anes - 0.1.6 +**Repository URL**: https://github.com/zrzka/anes-rs +**License Type(s)**: Apache-2.0 +### License: https://spdx.org/licenses/Apache-2.0.html +``` +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +``` + ## anstream - 1.0.0 **Repository URL**: https://github.com/rust-cli/anstyle.git **License Type(s)**: Apache-2.0 @@ -5263,8 +5344,8 @@ limitations under the License. ``` -## clap - 4.6.0 -**Repository URL**: https://github.com/clap-rs/clap +## ciborium - 0.2.2 +**Repository URL**: https://github.com/enarx/ciborium **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html ``` @@ -5448,7 +5529,7 @@ limitations under the License. APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" + boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a @@ -5456,7 +5537,7 @@ limitations under the License. same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright {yyyy} {name of copyright owner} + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -5470,11 +5551,638 @@ limitations under the License. See the License for the specific language governing permissions and limitations under the License. +``` +## ciborium-io - 0.2.2 +**Repository URL**: https://github.com/enarx/ciborium +**License Type(s)**: Apache-2.0 +### License: https://spdx.org/licenses/Apache-2.0.html ``` + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ -## clap_builder - 4.6.0 -**Repository URL**: https://github.com/clap-rs/clap + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +``` + +## ciborium-ll - 0.2.2 +**Repository URL**: https://github.com/enarx/ciborium +**License Type(s)**: Apache-2.0 +### License: https://spdx.org/licenses/Apache-2.0.html +``` + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +``` + +## clap - 4.6.0 +**Repository URL**: https://github.com/clap-rs/clap +**License Type(s)**: Apache-2.0 +### License: https://spdx.org/licenses/Apache-2.0.html +``` + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +``` + +## clap_builder - 4.6.0 +**Repository URL**: https://github.com/clap-rs/clap **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html ``` @@ -7896,8 +8604,8 @@ limitations under the License. ``` -## crossbeam-utils - 0.8.21 -**Repository URL**: https://github.com/crossbeam-rs/crossbeam +## criterion - 0.5.1 +**Repository URL**: https://github.com/bheisler/criterion.rs **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html ``` @@ -8105,8 +8813,8 @@ limitations under the License. ``` -## crypto-common - 0.1.7 -**Repository URL**: https://github.com/RustCrypto/traits +## criterion-plot - 0.5.0 +**Repository URL**: https://github.com/bheisler/criterion.rs **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html ``` @@ -8304,7 +9012,7 @@ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -8314,8 +9022,8 @@ limitations under the License. ``` -## crypto-common - 0.2.1 -**Repository URL**: https://github.com/RustCrypto/traits +## crossbeam-deque - 0.8.6 +**Repository URL**: https://github.com/crossbeam-rs/crossbeam **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html ``` @@ -8513,7 +9221,7 @@ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -8523,277 +9231,455 @@ limitations under the License. ``` -## ctor - 0.2.9 -**Repository URL**: https://github.com/mmastrac/rust-ctor -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html -``` -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -``` - -## data-encoding - 2.11.0 -**Repository URL**: https://github.com/ia0/data-encoding -**License Type(s)**: MIT -### License: https://spdx.org/licenses/MIT.html -``` -The MIT License (MIT) - -Copyright (c) 2015-2020 Julien Cretin -Copyright (c) 2017-2020 Google Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -``` - -## dialoguer - 0.11.0 -**Repository URL**: https://github.com/console-rs/dialoguer -**License Type(s)**: MIT -### License: https://spdx.org/licenses/MIT.html -``` -The MIT License (MIT) - -Copyright (c) 2017 Armin Ronacher - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - -``` - -## digest - 0.10.7 -**Repository URL**: https://github.com/RustCrypto/traits +## crossbeam-epoch - 0.9.18 +**Repository URL**: https://github.com/crossbeam-rs/crossbeam +**License Type(s)**: Apache-2.0 +### License: https://spdx.org/licenses/Apache-2.0.html +``` + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +``` + +## crossbeam-utils - 0.8.21 +**Repository URL**: https://github.com/crossbeam-rs/crossbeam +**License Type(s)**: Apache-2.0 +### License: https://spdx.org/licenses/Apache-2.0.html +``` + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +``` + +## crunchy - 0.2.4 +**Repository URL**: https://github.com/eira-fransham/crunchy +**License Type(s)**: MIT +### License: https://spdx.org/licenses/MIT.html +``` +The MIT License (MIT) + +Copyright 2017-2023 Eira Fransham. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +``` + +## crypto-common - 0.1.7 +**Repository URL**: https://github.com/RustCrypto/traits **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html ``` @@ -9001,7 +9887,7 @@ limitations under the License. ``` -## digest - 0.11.2 +## crypto-common - 0.2.1 **Repository URL**: https://github.com/RustCrypto/traits **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html @@ -9210,8 +10096,1404 @@ limitations under the License. ``` -## displaydoc - 0.2.5 -**Repository URL**: https://github.com/yaahc/displaydoc +## ctor - 0.2.9 +**Repository URL**: https://github.com/mmastrac/rust-ctor +**License Type(s)**: Apache-2.0 +### License: https://spdx.org/licenses/Apache-2.0.html +``` +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +``` + +## data-encoding - 2.11.0 +**Repository URL**: https://github.com/ia0/data-encoding +**License Type(s)**: MIT +### License: https://spdx.org/licenses/MIT.html +``` +The MIT License (MIT) + +Copyright (c) 2015-2020 Julien Cretin +Copyright (c) 2017-2020 Google Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +``` + +## dialoguer - 0.11.0 +**Repository URL**: https://github.com/console-rs/dialoguer +**License Type(s)**: MIT +### License: https://spdx.org/licenses/MIT.html +``` +The MIT License (MIT) + +Copyright (c) 2017 Armin Ronacher + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +``` + +## digest - 0.10.7 +**Repository URL**: https://github.com/RustCrypto/traits +**License Type(s)**: Apache-2.0 +### License: https://spdx.org/licenses/Apache-2.0.html +``` + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +``` + +## digest - 0.11.2 +**Repository URL**: https://github.com/RustCrypto/traits +**License Type(s)**: Apache-2.0 +### License: https://spdx.org/licenses/Apache-2.0.html +``` + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +``` + +## displaydoc - 0.2.5 +**Repository URL**: https://github.com/yaahc/displaydoc +**License Type(s)**: Apache-2.0 +### License: https://spdx.org/licenses/Apache-2.0.html +``` + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +``` + +## dyn-clone - 1.0.20 +**Repository URL**: https://github.com/dtolnay/dyn-clone +**License Type(s)**: Apache-2.0 +### License: https://spdx.org/licenses/Apache-2.0.html +``` +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +``` + +## either - 1.15.0 +**Repository URL**: https://github.com/rayon-rs/either +**License Type(s)**: Apache-2.0 +### License: https://spdx.org/licenses/Apache-2.0.html +``` + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +``` + +## encode_unicode - 1.0.0 +**Repository URL**: https://github.com/tormol/encode_unicode +**License Type(s)**: Apache-2.0 +### License: https://spdx.org/licenses/Apache-2.0.html +``` + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +``` + +## equivalent - 1.0.2 +**Repository URL**: https://github.com/indexmap-rs/equivalent **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html ``` @@ -9419,89 +11701,8 @@ limitations under the License. ``` -## dyn-clone - 1.0.20 -**Repository URL**: https://github.com/dtolnay/dyn-clone -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html -``` -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - -"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - - (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. - - You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -``` - -## either - 1.15.0 -**Repository URL**: https://github.com/rayon-rs/either +## errno - 0.3.14 +**Repository URL**: https://github.com/lambda-fairy/rust-errno **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html ``` @@ -9709,218 +11910,8 @@ limitations under the License. ``` -## encode_unicode - 1.0.0 -**Repository URL**: https://github.com/tormol/encode_unicode -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html -``` - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -``` - -## equivalent - 1.0.2 -**Repository URL**: https://github.com/indexmap-rs/equivalent +## event-listener - 5.4.1 +**Repository URL**: https://github.com/smol-rs/event-listener **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html ``` @@ -10128,8 +12119,8 @@ limitations under the License. ``` -## errno - 0.3.14 -**Repository URL**: https://github.com/lambda-fairy/rust-errno +## event-listener-strategy - 0.5.4 +**Repository URL**: https://github.com/smol-rs/event-listener-strategy **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html ``` @@ -10337,8 +12328,8 @@ limitations under the License. ``` -## event-listener - 5.4.1 -**Repository URL**: https://github.com/smol-rs/event-listener +## fastrand - 2.4.1 +**Repository URL**: https://github.com/smol-rs/fastrand **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html ``` @@ -10546,8 +12537,8 @@ limitations under the License. ``` -## event-listener-strategy - 0.5.4 -**Repository URL**: https://github.com/smol-rs/event-listener-strategy +## find-msvc-tools - 0.1.9 +**Repository URL**: https://github.com/rust-lang/cc-rs **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html ``` @@ -10755,8 +12746,8 @@ limitations under the License. ``` -## fastrand - 2.4.1 -**Repository URL**: https://github.com/smol-rs/fastrand +## fnv - 1.0.7 +**Repository URL**: https://github.com/servo/rust-fnv **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html ``` @@ -10964,217 +12955,35 @@ limitations under the License. ``` -## find-msvc-tools - 0.1.9 -**Repository URL**: https://github.com/rust-lang/cc-rs -**License Type(s)**: Apache-2.0 -### License: https://spdx.org/licenses/Apache-2.0.html +## foldhash - 0.1.5 +**Repository URL**: https://github.com/orlp/foldhash +**License Type(s)**: Zlib +### License: https://spdx.org/licenses/Zlib.html +### License File: LICENSE ``` - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. +Copyright (c) 2024 Orson Peters -Copyright [yyyy] [name of copyright owner] +This software is provided 'as-is', without any express or implied warranty. In +no event will the authors be held liable for any damages arising from the use of +this software. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at +Permission is granted to anyone to use this software for any purpose, including +commercial applications, and to alter it and redistribute it freely, subject to +the following restrictions: - http://www.apache.org/licenses/LICENSE-2.0 +1. The origin of this software must not be misrepresented; you must not claim + that you wrote the original software. If you use this software in a product, + an acknowledgment in the product documentation would be appreciated but is + not required. -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. ``` -## fnv - 1.0.7 -**Repository URL**: https://github.com/servo/rust-fnv +## form_urlencoded - 1.2.2 +**Repository URL**: https://github.com/servo/rust-url **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html ``` @@ -11382,35 +13191,8 @@ limitations under the License. ``` -## foldhash - 0.1.5 -**Repository URL**: https://github.com/orlp/foldhash -**License Type(s)**: Zlib -### License: https://spdx.org/licenses/Zlib.html -### License File: LICENSE -``` -Copyright (c) 2024 Orson Peters - -This software is provided 'as-is', without any express or implied warranty. In -no event will the authors be held liable for any damages arising from the use of -this software. - -Permission is granted to anyone to use this software for any purpose, including -commercial applications, and to alter it and redistribute it freely, subject to -the following restrictions: - -1. The origin of this software must not be misrepresented; you must not claim - that you wrote the original software. If you use this software in a product, - an acknowledgment in the product documentation would be appreciated but is - not required. - -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - -3. This notice may not be removed or altered from any source distribution. -``` - -## form_urlencoded - 1.2.2 -**Repository URL**: https://github.com/servo/rust-url +## futures - 0.3.32 +**Repository URL**: https://github.com/rust-lang/futures-rs **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html ``` @@ -11602,7 +13384,8 @@ APPENDIX: How to apply the Apache License to your work. same "printed page" as the copyright notice for easier identification within third-party archives. -Copyright [yyyy] [name of copyright owner] +Copyright (c) 2016 Alex Crichton +Copyright (c) 2017 The Tokio Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -11618,7 +13401,7 @@ limitations under the License. ``` -## futures - 0.3.32 +## futures-channel - 0.3.32 **Repository URL**: https://github.com/rust-lang/futures-rs **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html @@ -11828,7 +13611,7 @@ limitations under the License. ``` -## futures-channel - 0.3.32 +## futures-core - 0.3.32 **Repository URL**: https://github.com/rust-lang/futures-rs **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html @@ -12038,7 +13821,7 @@ limitations under the License. ``` -## futures-core - 0.3.32 +## futures-executor - 0.3.32 **Repository URL**: https://github.com/rust-lang/futures-rs **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html @@ -12248,7 +14031,7 @@ limitations under the License. ``` -## futures-executor - 0.3.32 +## futures-io - 0.3.32 **Repository URL**: https://github.com/rust-lang/futures-rs **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html @@ -12458,7 +14241,7 @@ limitations under the License. ``` -## futures-io - 0.3.32 +## futures-macro - 0.3.32 **Repository URL**: https://github.com/rust-lang/futures-rs **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html @@ -12668,7 +14451,7 @@ limitations under the License. ``` -## futures-macro - 0.3.32 +## futures-sink - 0.3.32 **Repository URL**: https://github.com/rust-lang/futures-rs **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html @@ -12878,7 +14661,7 @@ limitations under the License. ``` -## futures-sink - 0.3.32 +## futures-task - 0.3.32 **Repository URL**: https://github.com/rust-lang/futures-rs **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html @@ -13088,7 +14871,7 @@ limitations under the License. ``` -## futures-task - 0.3.32 +## futures-util - 0.3.32 **Repository URL**: https://github.com/rust-lang/futures-rs **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html @@ -13298,14 +15081,42 @@ limitations under the License. ``` -## futures-util - 0.3.32 -**Repository URL**: https://github.com/rust-lang/futures-rs +## generic-array - 0.14.7 +**Repository URL**: https://github.com/fizyk20/generic-array.git +**License Type(s)**: MIT +### License: https://spdx.org/licenses/MIT.html +``` +The MIT License (MIT) + +Copyright (c) 2015 Bartłomiej Kamiński + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +``` + +## getrandom - 0.2.17 +**Repository URL**: https://github.com/rust-random/getrandom **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html ``` Apache License Version 2.0, January 2004 - http://www.apache.org/licenses/ + https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION @@ -13491,14 +15302,13 @@ APPENDIX: How to apply the Apache License to your work. same "printed page" as the copyright notice for easier identification within third-party archives. -Copyright (c) 2016 Alex Crichton -Copyright (c) 2017 The Tokio Authors +Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -13508,35 +15318,7 @@ limitations under the License. ``` -## generic-array - 0.14.7 -**Repository URL**: https://github.com/fizyk20/generic-array.git -**License Type(s)**: MIT -### License: https://spdx.org/licenses/MIT.html -``` -The MIT License (MIT) - -Copyright (c) 2015 Bartłomiej Kamiński - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -``` - -## getrandom - 0.2.17 +## getrandom - 0.3.4 **Repository URL**: https://github.com/rust-random/getrandom **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html @@ -13745,7 +15527,7 @@ limitations under the License. ``` -## getrandom - 0.3.4 +## getrandom - 0.4.2 **Repository URL**: https://github.com/rust-random/getrandom **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html @@ -13954,14 +15736,129 @@ limitations under the License. ``` -## getrandom - 0.4.2 -**Repository URL**: https://github.com/rust-random/getrandom +## h2 - 0.4.13 +**Repository URL**: https://github.com/hyperium/h2 +**License Type(s)**: MIT +### License: https://spdx.org/licenses/MIT.html +``` +Copyright (c) 2017 h2 authors + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +``` + +## half - 2.7.1 +**Repository URL**: https://github.com/VoidStarKat/half-rs **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html +``` +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +``` + +## hashbrown - 0.15.5 +**Repository URL**: https://github.com/rust-lang/hashbrown +**License Type(s)**: MIT OR Apache-2.0 +### License: https://spdx.org/licenses/ +### License File: LICENSE-APACHE ``` Apache License Version 2.0, January 2004 - https://www.apache.org/licenses/ + http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION @@ -14153,22 +16050,18 @@ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - https://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - ``` -## h2 - 0.4.13 -**Repository URL**: https://github.com/hyperium/h2 -**License Type(s)**: MIT -### License: https://spdx.org/licenses/MIT.html +### License File: LICENSE-MIT ``` -Copyright (c) 2017 h2 authors +Copyright (c) 2016 Amanieu d'Antras Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated @@ -14193,14 +16086,12 @@ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ``` -## hashbrown - 0.15.5 +## hashbrown - 0.17.0 **Repository URL**: https://github.com/rust-lang/hashbrown -**License Type(s)**: MIT OR Apache-2.0 -### License: https://spdx.org/licenses/ -### License File: LICENSE-APACHE +**License Type(s)**: Apache-2.0 +### License: https://spdx.org/licenses/Apache-2.0.html ``` Apache License Version 2.0, January 2004 @@ -14403,39 +16294,11 @@ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -``` - -### License File: LICENSE-MIT -``` -Copyright (c) 2016 Amanieu d'Antras - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. ``` -## hashbrown - 0.17.0 -**Repository URL**: https://github.com/rust-lang/hashbrown +## heck - 0.5.0 +**Repository URL**: https://github.com/withoutboats/heck **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html ``` @@ -14643,8 +16506,8 @@ limitations under the License. ``` -## heck - 0.5.0 -**Repository URL**: https://github.com/withoutboats/heck +## hermit-abi - 0.5.2 +**Repository URL**: https://github.com/hermit-os/hermit-rs **License Type(s)**: Apache-2.0 ### License: https://spdx.org/licenses/Apache-2.0.html ``` @@ -18516,6 +20379,37 @@ limitations under the License. ``` +## is-terminal - 0.4.17 +**Repository URL**: https://github.com/sunfishcode/is-terminal +**License Type(s)**: MIT +### License: https://spdx.org/licenses/MIT.html +``` +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +``` + ## is_terminal_polyfill - 1.70.2 **Repository URL**: https://github.com/polyfill-rs/is_terminal_polyfill **License Type(s)**: Apache-2.0 @@ -18724,6 +20618,215 @@ limitations under the License. limitations under the License. +``` + +## itertools - 0.10.5 +**Repository URL**: https://github.com/rust-itertools/itertools +**License Type(s)**: Apache-2.0 +### License: https://spdx.org/licenses/Apache-2.0.html +``` + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + ``` ## itertools - 0.14.0 @@ -24546,6 +26649,84 @@ limitations under the License. ``` +## plotters - 0.3.7 +**Repository URL**: https://github.com/plotters-rs/plotters +**License Type(s)**: MIT +### License: https://spdx.org/licenses/MIT.html +``` +MIT License + +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO +EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. + +``` + +## plotters-backend - 0.3.7 +**Repository URL**: https://github.com/plotters-rs/plotters +**License Type(s)**: MIT +### License: https://spdx.org/licenses/MIT.html +``` +MIT License + +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO +EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. + +``` + +## plotters-svg - 0.3.7 +**Repository URL**: https://github.com/plotters-rs/plotters.git +**License Type(s)**: MIT +### License: https://spdx.org/licenses/MIT.html +``` +MIT License + +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO +EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. + +``` + ## portable-atomic - 1.13.1 **Repository URL**: https://github.com/taiki-e/portable-atomic **License Type(s)**: Apache-2.0 @@ -27796,6 +29977,424 @@ APPENDIX: How to apply the Apache License to your work. ``` +## rayon - 1.12.0 +**Repository URL**: https://github.com/rayon-rs/rayon +**License Type(s)**: Apache-2.0 +### License: https://spdx.org/licenses/Apache-2.0.html +``` + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +``` + +## rayon-core - 1.13.0 +**Repository URL**: https://github.com/rayon-rs/rayon +**License Type(s)**: Apache-2.0 +### License: https://spdx.org/licenses/Apache-2.0.html +``` + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +``` + ## redis - 1.2.0 **Repository URL**: https://github.com/redis-rs/redis-rs **License Type(s)**: BSD-3-Clause @@ -34922,6 +37521,215 @@ ICU 1.8.1 to ICU 57.1 © 1995-2016 International Business Machines Corporation a ``` +## tinytemplate - 1.2.1 +**Repository URL**: https://github.com/bheisler/TinyTemplate +**License Type(s)**: Apache-2.0 +### License: https://spdx.org/licenses/Apache-2.0.html +``` + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +``` + ## tinyvec - 1.11.0 **Repository URL**: https://github.com/Lokathor/tinyvec **License Type(s)**: Zlib OR Apache-2.0 OR MIT @@ -48283,9 +51091,8 @@ ICU 1.8.1 to ICU 57.1 © 1995-2016 International Business Machines Corporation a ## zerocopy-derive - 0.8.48 **Repository URL**: https://github.com/google/zerocopy -**License Type(s)**: BSD-2-Clause OR Apache-2.0 OR MIT -### License: https://spdx.org/licenses/ -### License File: LICENSE-APACHE +**License Type(s)**: Apache-2.0 +### License: https://spdx.org/licenses/Apache-2.0.html ``` Apache License Version 2.0, January 2004 @@ -48489,63 +51296,6 @@ ICU 1.8.1 to ICU 57.1 © 1995-2016 International Business Machines Corporation a See the License for the specific language governing permissions and limitations under the License. -``` - -### License File: LICENSE-BSD -``` -Copyright 2019 The Fuchsia Authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -``` - -### License File: LICENSE-MIT -``` -Copyright 2023 The Fuchsia Authors - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. ``` diff --git a/Cargo.lock b/Cargo.lock index c28b4667..7a2d495a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,6 +20,12 @@ dependencies = [ "libc", ] +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + [[package]] name = "anstream" version = "1.0.0" @@ -325,6 +331,33 @@ dependencies = [ "windows-link", ] +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "clap" version = "4.6.0" @@ -477,12 +510,73 @@ dependencies = [ "libc", ] +[[package]] +name = "criterion" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "is-terminal", + "itertools 0.10.5", + "num-traits", + "once_cell", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools 0.10.5", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + [[package]] name = "crypto-common" version = "0.1.7" @@ -807,6 +901,17 @@ dependencies = [ "tracing", ] +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + [[package]] name = "hashbrown" version = "0.15.5" @@ -828,6 +933,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + [[package]] name = "http" version = "1.4.0" @@ -1123,12 +1234,32 @@ dependencies = [ "serde", ] +[[package]] +name = "is-terminal" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.61.2", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.14.0" @@ -1367,7 +1498,9 @@ name = "nemo-relay-adaptive" version = "0.5.0" dependencies = [ "chrono", + "criterion", "nemo-relay", + "nemo-relay-adaptive-topology", "redis", "regex", "serde", @@ -1381,6 +1514,15 @@ dependencies = [ "uuid", ] +[[package]] +name = "nemo-relay-adaptive-topology" +version = "0.5.0" +dependencies = [ + "libm", + "serde", + "serde_json", +] + [[package]] name = "nemo-relay-cli" version = "0.5.0" @@ -1471,6 +1613,7 @@ dependencies = [ "chrono", "nemo-relay", "nemo-relay-adaptive", + "nemo-relay-adaptive-topology", "nemo-relay-pii-redaction", "pyo3", "pyo3-async-runtimes", @@ -1559,7 +1702,7 @@ dependencies = [ "http-body-util", "humantime", "hyper", - "itertools", + "itertools 0.14.0", "md-5", "parking_lot", "percent-encoding", @@ -1757,6 +1900,34 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + [[package]] name = "portable-atomic" version = "1.13.1" @@ -1817,7 +1988,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" dependencies = [ "anyhow", - "itertools", + "itertools 0.14.0", "proc-macro2", "quote", "syn", @@ -2037,6 +2208,26 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" +[[package]] +name = "rayon" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "redis" version = "1.2.0" @@ -2651,6 +2842,16 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "tinyvec" version = "1.11.0" diff --git a/Cargo.toml b/Cargo.toml index 660593ce..58a3a44d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ members = [ "crates/core", "crates/adaptive", + "crates/adaptive-topology", "crates/pii-redaction", "crates/cli", # Language Bindings @@ -25,6 +26,7 @@ repository = "https://github.com/NVIDIA/NeMo-Relay" [workspace.dependencies] nemo-relay = { version = "0.5.0", path = "crates/core", default-features = false } nemo-relay-adaptive = { version = "0.5.0", path = "crates/adaptive" } +nemo-relay-adaptive-topology = { version = "0.5.0", path = "crates/adaptive-topology" } nemo-relay-pii-redaction = { version = "0.5.0", path = "crates/pii-redaction" } nemo-relay-ffi = { version = "0.5.0", path = "crates/ffi" } nemo-relay-cli = { version = "0.5.0", path = "crates/cli" } diff --git a/crates/adaptive-topology/Cargo.toml b/crates/adaptive-topology/Cargo.toml new file mode 100644 index 00000000..28c1e4bb --- /dev/null +++ b/crates/adaptive-topology/Cargo.toml @@ -0,0 +1,27 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +[package] +name = "nemo-relay-adaptive-topology" +version.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true +description = "Topology, manifold, and adaptive threshold primitives for NeMo Relay." +readme = "README.md" + +[lints] +workspace = true + +[dependencies] +libm = "0.2" +serde = { version = "1", features = ["derive"], optional = true } + +[features] +default = ["std"] +std = [] +alloc = [] +serde = ["dep:serde"] + +[dev-dependencies] +serde_json = "1" diff --git a/crates/adaptive-topology/README.md b/crates/adaptive-topology/README.md new file mode 100644 index 00000000..bf0c18b7 --- /dev/null +++ b/crates/adaptive-topology/README.md @@ -0,0 +1,61 @@ + + +# nemo-relay-adaptive-topology + +Topology-inspired, manifold, and adaptive-threshold primitives for NeMo Relay. + +This crate provides a small deterministic toolkit for observing and reacting to +the shape of runtime data. The signals are intentionally lightweight +approximations for adaptive runtime control; they are not an exact persistent +homology implementation. The crate is designed to work in `no_std` +environments as well as standard Rust builds. + +## Module Map + +- `governor` — `GeometricGovernor`, a PD controller that adapts a sensitivity + threshold `epsilon` to keep an effective tick rate near a target. +- `drift` — `DriftDetector`, a centroid velocity tracker that measures + unexpected drift by comparing each new centroid with the position predicted + from the previous step. +- `convergence` — `BettiNumbers` and `ConvergenceDetector`, which declare + convergence when Betti numbers stabilize, drift decays, and error drops. +- `geometry` — `BlockMetadata` summaries and `HierarchicalBlockTree` for + multi-scale geometric queries and compression hints. +- `manifold` — `ManifoldPoint`, `TimeDelayEmbedder`, `SparseAttentionGraph`, + and `GeometricConcentrator` for embedding streams and analyzing local + manifold structure. +- `topology` — `TopologicalShape` and byte-stream Betti approximations for + shape signatures and verification. + +## Example + +```rust +use nemo_relay_adaptive_topology::{GeometricGovernor, DriftDetector, ConvergenceDetector, BettiNumbers}; + +let mut governor = GeometricGovernor::new(); +for _ in 0..10 { + // High deviation should raise the threshold to reduce sensitivity. + governor.adapt(10_000.0, 0.001); +} + +let mut drift = DriftDetector::<3>::new(); +drift.update(&[1.0, 0.0, 0.0]); +drift.update(&[2.0, 0.0, 0.0]); +assert!(drift.is_drifting(0.5)); + +let mut conv = ConvergenceDetector::new(0.001, 3); +conv.record_epoch(BettiNumbers::new(1, 0), 0.05, 0.02); +conv.record_epoch(BettiNumbers::new(1, 0), 0.01, 0.015); +conv.record_epoch(BettiNumbers::new(1, 0), 0.005, 0.01); +assert!(conv.is_converged()); +``` + +## Features + +- `std` (default) — enable standard-library support. +- `alloc` — reserved for future allocation-dependent APIs in `no_std` + builds. +- `serde` — derive `Serialize`/`Deserialize` for public types. diff --git a/crates/adaptive-topology/src/convergence.rs b/crates/adaptive-topology/src/convergence.rs new file mode 100644 index 00000000..6bbb8b42 --- /dev/null +++ b/crates/adaptive-topology/src/convergence.rs @@ -0,0 +1,413 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Topological convergence detection via Betti-number stability and drift decay. + +use libm::exp; + +/// Maximum number of epochs retained in each history ring buffer. +const MAX_HISTORY: usize = 32; + +/// Default minimum stability window length. +const MIN_STABILITY_WINDOW: usize = 3; + +/// Drift values below this threshold are considered converged. +const FINAL_DRIFT_THRESHOLD: f64 = 0.01; + +/// Weight given to Betti stability in [`ConvergenceDetector::convergence_score`]. +const BETTI_STABILITY_WEIGHT: f64 = 0.4; + +/// Weight given to drift in [`ConvergenceDetector::convergence_score`]. +const DRIFT_WEIGHT: f64 = 0.3; + +/// Weight given to error in [`ConvergenceDetector::convergence_score`]. +const ERROR_WEIGHT: f64 = 0.3; + +const DEFAULT_EPSILON: f64 = 0.001; + +/// Topological Betti numbers describing the shape of a point cloud. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct BettiNumbers { + /// Number of connected components. + pub beta_0: u32, + /// Number of 1-dimensional holes (loops). + pub beta_1: u32, +} + +impl BettiNumbers { + /// Create a new pair of Betti numbers. + pub const fn new(beta_0: u32, beta_1: u32) -> Self { + Self { beta_0, beta_1 } + } + + /// Return true when the shape is a single connected component with no loops. + pub fn is_singular(&self) -> bool { + self.beta_0 == 1 && self.beta_1 == 0 + } + + /// L1 distance between two Betti signatures. + pub fn distance(&self, other: &Self) -> u32 { + self.beta_0 + .abs_diff(other.beta_0) + .saturating_add(self.beta_1.abs_diff(other.beta_1)) + } +} + +impl Default for BettiNumbers { + fn default() -> Self { + Self { + beta_0: 1, + beta_1: 0, + } + } +} + +/// Fixed-size ring buffer for tracking a scalar history without allocation. +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(bound( + serialize = "T: serde::Serialize", + deserialize = "T: serde::Deserialize<'de>" + )) +)] +#[derive(Debug, Clone, Copy, PartialEq)] +struct RingBuffer { + #[cfg_attr(feature = "serde", serde(with = "crate::serde_arrays"))] + data: [T; N], + len: usize, + pos: usize, +} + +impl RingBuffer { + fn new() -> Self { + Self { + data: [T::default(); N], + len: 0, + pos: 0, + } + } + + fn push(&mut self, value: T) { + self.data[self.pos] = value; + self.pos = (self.pos + 1) % N; + if self.len < N { + self.len += 1; + } + } + + fn last(&self) -> Option { + if self.len == 0 { + return None; + } + let idx = (self.pos + N - 1) % N; + Some(self.data[idx]) + } + + fn len(&self) -> usize { + self.len + } + + fn copy_window(&self, window_size: usize, out: &mut [T]) -> usize { + let window_size = window_size.min(self.len).min(out.len()); + if window_size == 0 { + return 0; + } + + let start = (self.pos + N - window_size) % N; + for (i, slot) in out.iter_mut().enumerate().take(window_size) { + *slot = self.data[(start + i) % N]; + } + window_size + } +} + +/// Detects convergence using topological stability. +/// +/// Convergence is declared when either: +/// * the last recorded error is below `epsilon`, or +/// * Betti numbers are stable over `stability_window` epochs, drift is +/// monotonically decreasing, and the final drift is below +/// `FINAL_DRIFT_THRESHOLD`. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct ConvergenceDetector { + betti_history: RingBuffer, + drift_history: RingBuffer, + error_history: RingBuffer, + stability_window: usize, + epsilon: f64, + epoch: u32, +} + +impl ConvergenceDetector { + /// Create a new detector. + /// + /// `epsilon` is the error threshold. `stability_window` is the minimum + /// number of epochs required to judge stability and is clamped to at + /// least `MIN_STABILITY_WINDOW`. + pub fn new(epsilon: f64, stability_window: usize) -> Self { + Self { + betti_history: RingBuffer::new(), + drift_history: RingBuffer::new(), + error_history: RingBuffer::new(), + stability_window: stability_window.max(MIN_STABILITY_WINDOW), + epsilon: sanitize_positive(epsilon, DEFAULT_EPSILON), + epoch: 0, + } + } + + /// Record an epoch's metrics. + pub fn record_epoch(&mut self, betti: BettiNumbers, drift: f64, error: f64) { + self.betti_history.push(betti); + self.drift_history.push(sanitize_non_negative(drift)); + self.error_history.push(sanitize_non_negative(error)); + self.epoch += 1; + } + + /// Return true if convergence criteria are satisfied. + pub fn is_converged(&self) -> bool { + if self.is_error_converged() { + return true; + } + + self.is_betti_stable() && self.is_drift_decreasing() + } + + /// Return true if the most recent error is below epsilon. + fn is_error_converged(&self) -> bool { + self.error_history + .last() + .map(|e| e < self.epsilon) + .unwrap_or(false) + } + + /// Return true if Betti numbers are identical across the stability window. + fn is_betti_stable(&self) -> bool { + if self.betti_history.len() < self.stability_window { + return false; + } + + let mut window = [BettiNumbers::default(); MAX_HISTORY]; + let n = self + .betti_history + .copy_window(self.stability_window, &mut window); + let first = window[0]; + window[..n].iter().all(|b| *b == first) + } + + /// Return true if drift is monotonically non-increasing and the final + /// value is below `FINAL_DRIFT_THRESHOLD`. + fn is_drift_decreasing(&self) -> bool { + if self.drift_history.len() < self.stability_window { + return false; + } + + let mut window = [0.0; MAX_HISTORY]; + let n = self + .drift_history + .copy_window(self.stability_window, &mut window); + + for pair in window[..n].windows(2) { + if pair[1] > pair[0] { + return false; + } + } + + window[n - 1] < FINAL_DRIFT_THRESHOLD + } + + /// Return a score in `[0, 1]` indicating how close to converged the + /// detector is, where `1.0` means fully converged. + pub fn convergence_score(&self) -> f64 { + let n = self.betti_history.len(); + if n == 0 { + return 0.0; + } + + let mut score = 0.0; + + // Betti stability contributes 40%. + if n >= self.stability_window { + let mut window = [BettiNumbers::default(); MAX_HISTORY]; + let count = self + .betti_history + .copy_window(self.stability_window, &mut window); + let variations = window[..count].windows(2).filter(|w| w[0] != w[1]).count(); + let betti_score = 1.0 - (variations as f64 / self.stability_window as f64); + score += BETTI_STABILITY_WEIGHT * betti_score; + } + + // Drift contribution: exponential decay with drift. + if let Some(last_drift) = self.drift_history.last() { + let drift_score = exp(-last_drift * 10.0).min(1.0); + score += DRIFT_WEIGHT * drift_score; + } + + // Error contribution. + if let Some(last_error) = self.error_history.last() { + let error_score = if last_error < self.epsilon { + 1.0 + } else { + (self.epsilon / last_error).min(1.0) + }; + score += ERROR_WEIGHT * error_score; + } + + score + } + + /// Return the number of epochs recorded. + pub fn epoch(&self) -> u32 { + self.epoch + } + + /// Return the most recent Betti numbers, if any. + pub fn last_betti(&self) -> Option { + self.betti_history.last() + } + + /// Return the most recent error, if any. + pub fn last_error(&self) -> Option { + self.error_history.last() + } + + /// Reset the detector. + pub fn reset(&mut self) { + self.betti_history = RingBuffer::new(); + self.drift_history = RingBuffer::new(); + self.error_history = RingBuffer::new(); + self.epoch = 0; + } +} + +impl Default for ConvergenceDetector { + fn default() -> Self { + Self::new(DEFAULT_EPSILON, MIN_STABILITY_WINDOW) + } +} + +fn sanitize_positive(value: f64, fallback: f64) -> f64 { + if value.is_finite() && value > 0.0 { + value + } else { + fallback + } +} + +fn sanitize_non_negative(value: f64) -> f64 { + if value.is_finite() && value >= 0.0 { + value + } else { + f64::INFINITY + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn empty_detector_is_not_converged() { + let detector = ConvergenceDetector::new(0.001, 3); + assert!(!detector.is_converged()); + assert_eq!(detector.convergence_score(), 0.0); + } + + #[test] + fn betti_distance_handles_extreme_public_inputs() { + let a = BettiNumbers::new(u32::MAX, 0); + let b = BettiNumbers::new(0, u32::MAX); + assert_eq!(a.distance(&b), u32::MAX); + } + + #[test] + fn non_finite_metrics_do_not_poison_convergence_score() { + let mut detector = ConvergenceDetector::new(f64::NAN, 0); + detector.record_epoch(BettiNumbers::new(1, 0), f64::NAN, f64::NAN); + assert!(!detector.is_converged()); + assert!(detector.convergence_score().is_finite()); + assert_eq!(detector.last_error(), Some(f64::INFINITY)); + } + + #[test] + fn error_below_epsilon_converges() { + let mut detector = ConvergenceDetector::new(0.01, 3); + detector.record_epoch(BettiNumbers::new(1, 0), 0.5, 0.005); + assert!(detector.is_converged()); + } + + #[test] + fn stable_betti_and_decreasing_drift_converges() { + let mut detector = ConvergenceDetector::new(0.001, 3); + detector.record_epoch(BettiNumbers::new(1, 0), 0.1, 0.05); + detector.record_epoch(BettiNumbers::new(1, 0), 0.05, 0.04); + detector.record_epoch(BettiNumbers::new(1, 0), 0.001, 0.03); + assert!(detector.is_converged()); + } + + #[test] + fn unstable_betti_does_not_converge() { + let mut detector = ConvergenceDetector::new(0.001, 3); + detector.record_epoch(BettiNumbers::new(1, 0), 0.05, 0.04); + detector.record_epoch(BettiNumbers::new(2, 0), 0.03, 0.03); + detector.record_epoch(BettiNumbers::new(1, 0), 0.001, 0.02); + assert!(!detector.is_converged()); + } + + #[test] + fn increasing_drift_does_not_converge() { + let mut detector = ConvergenceDetector::new(0.001, 3); + detector.record_epoch(BettiNumbers::new(1, 0), 0.01, 0.04); + detector.record_epoch(BettiNumbers::new(1, 0), 0.05, 0.03); + detector.record_epoch(BettiNumbers::new(1, 0), 0.001, 0.02); + assert!(!detector.is_converged()); + } + + #[test] + fn final_drift_above_threshold_does_not_converge() { + let mut detector = ConvergenceDetector::new(0.001, 3); + detector.record_epoch(BettiNumbers::new(1, 0), 0.1, 0.04); + detector.record_epoch(BettiNumbers::new(1, 0), 0.05, 0.03); + detector.record_epoch(BettiNumbers::new(1, 0), 0.02, 0.02); + assert!(!detector.is_converged()); + } + + #[test] + fn convergence_score_increases_with_stability() { + let mut detector = ConvergenceDetector::new(0.001, 3); + detector.record_epoch(BettiNumbers::new(1, 0), 0.5, 0.1); + let score1 = detector.convergence_score(); + detector.record_epoch(BettiNumbers::new(1, 0), 0.1, 0.05); + detector.record_epoch(BettiNumbers::new(1, 0), 0.001, 0.001); + let score2 = detector.convergence_score(); + assert!(score2 > score1); + assert!(score2 <= 1.0); + } + + #[test] + fn ring_buffer_wraps_correctly() { + let mut buf = RingBuffer::::new(); + for i in 1..=6 { + buf.push(i); + } + assert_eq!(buf.len(), 4); + assert_eq!(buf.last(), Some(6)); + + let mut window = [0; 4]; + let n = buf.copy_window(4, &mut window); + assert_eq!(n, 4); + assert_eq!(window, [3, 4, 5, 6]); + } + + #[test] + fn reset_clears_detector() { + let mut detector = ConvergenceDetector::new(0.001, 3); + detector.record_epoch(BettiNumbers::new(1, 0), 0.001, 0.0001); + detector.reset(); + assert_eq!(detector.epoch(), 0); + assert!(detector.last_betti().is_none()); + assert!(!detector.is_converged()); + } +} diff --git a/crates/adaptive-topology/src/drift.rs b/crates/adaptive-topology/src/drift.rs new file mode 100644 index 00000000..edab8d61 --- /dev/null +++ b/crates/adaptive-topology/src/drift.rs @@ -0,0 +1,159 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Centroid trajectory tracking for semantic drift detection. + +use libm::sqrt; + +/// Tracks the velocity of a centroid trajectory. +/// +/// The detector stores the previous centroid and estimates an expected next +/// position from the last observed velocity. Drift is measured as the +/// distance between the actual next centroid and the predicted one. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct DriftDetector { + #[cfg_attr(feature = "serde", serde(with = "crate::serde_arrays"))] + previous: [f64; D], + has_previous: bool, + #[cfg_attr(feature = "serde", serde(with = "crate::serde_arrays"))] + velocity: [f64; D], + #[cfg_attr(feature = "serde", serde(with = "crate::serde_arrays"))] + expected: [f64; D], +} + +impl DriftDetector { + /// Create a new detector with no previous observation and zero velocity. + pub fn new() -> Self { + Self { + previous: [0.0; D], + has_previous: false, + velocity: [0.0; D], + expected: [0.0; D], + } + } + + /// Record a new centroid and return the drift from the predicted position. + /// + /// On the first observation the drift is zero because no prediction is + /// available yet. + pub fn update(&mut self, centroid: &[f64; D]) -> f64 { + let drift = if self.has_previous { + l2_distance(&self.expected, centroid) + } else { + 0.0 + }; + + if self.has_previous { + for (d, vel) in self.velocity.iter_mut().enumerate().take(D) { + *vel = centroid[d] - self.previous[d]; + } + } + + for (d, exp) in self.expected.iter_mut().enumerate().take(D) { + *exp = centroid[d] + self.velocity[d]; + } + + self.previous = *centroid; + self.has_previous = true; + + drift + } + + /// Return true if the current velocity magnitude exceeds `threshold`. + pub fn is_drifting(&self, threshold: f64) -> bool { + self.velocity_magnitude() > threshold + } + + /// Return the magnitude of the current velocity vector. + pub fn velocity_magnitude(&self) -> f64 { + vector_norm(&self.velocity) + } + + /// Reset the detector to its initial state. + pub fn reset(&mut self) { + self.previous = [0.0; D]; + self.has_previous = false; + self.velocity = [0.0; D]; + self.expected = [0.0; D]; + } +} + +impl Default for DriftDetector { + fn default() -> Self { + Self::new() + } +} + +fn l2_distance(a: &[f64; D], b: &[f64; D]) -> f64 { + let mut sum = 0.0; + for d in 0..D { + let diff = a[d] - b[d]; + sum += diff * diff; + } + sqrt(sum) +} + +fn vector_norm(v: &[f64; D]) -> f64 { + let mut sum = 0.0; + for &coord in v.iter() { + sum += coord * coord; + } + sqrt(sum) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn first_update_has_zero_drift() { + let mut detector = DriftDetector::<3>::new(); + assert_eq!(detector.update(&[1.0, 2.0, 3.0]), 0.0); + } + + #[test] + fn steady_velocity_is_tracked() { + let mut detector = DriftDetector::<3>::new(); + detector.update(&[0.0, 0.0, 0.0]); + detector.update(&[1.0, 0.0, 0.0]); + detector.update(&[2.0, 0.0, 0.0]); + + assert!((detector.velocity[0] - 1.0).abs() < 1e-10); + assert!((detector.velocity_magnitude() - 1.0).abs() < 1e-10); + assert!(!detector.is_drifting(2.0)); + assert!(detector.is_drifting(0.5)); + } + + #[test] + fn sudden_drift_is_detected() { + let mut detector = DriftDetector::<3>::new(); + detector.update(&[0.0, 0.0, 0.0]); + detector.update(&[1.0, 0.0, 0.0]); + detector.update(&[2.0, 0.0, 0.0]); + + let drift = detector.update(&[5.0, 0.0, 0.0]); + assert!(drift > 1.0); + assert!(detector.is_drifting(1.5)); + } + + #[test] + fn velocity_tracks_last_step() { + let mut detector = DriftDetector::<1>::new(); + for i in 0..10 { + detector.update(&[i as f64]); + } + assert!((detector.velocity[0] - 1.0).abs() < 1e-10); + } + + #[test] + fn reset_clears_detector() { + let mut detector = DriftDetector::<3>::new(); + detector.update(&[1.0, 0.0, 0.0]); + detector.update(&[2.0, 0.0, 0.0]); + detector.reset(); + + assert_eq!(detector.velocity_magnitude(), 0.0); + assert_eq!(detector.update(&[5.0, 0.0, 0.0]), 0.0); + } +} diff --git a/crates/adaptive-topology/src/geometry.rs b/crates/adaptive-topology/src/geometry.rs new file mode 100644 index 00000000..c11505af --- /dev/null +++ b/crates/adaptive-topology/src/geometry.rs @@ -0,0 +1,431 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Geometric summaries of data blocks and hierarchical aggregation trees. + +use libm::sqrt; + +/// Maximum number of blocks retained at the finest level. +const MAX_BLOCKS: usize = 128; + +/// Threshold below which a vector norm is treated as zero to avoid division +/// by very small numbers. +const NORM_EPSILON: f64 = 1e-10; + +/// Variance threshold below which a block is considered tightly clustered. +const LOW_VARIANCE_THRESHOLD: f64 = 0.1; + +/// Concentration threshold above which a block is considered highly aligned. +const HIGH_CONCENTRATION_THRESHOLD: f64 = 0.9; + +/// Compression ratio assigned to strategies that encode blocks compactly. +const COMPACT_COMPRESSION_RATIO: f64 = 4.0; + +/// Compression ratio assigned when no compression is applied. +const NO_COMPRESSION_RATIO: f64 = 1.0; + +/// Geometric summary of a block of `D`-dimensional points. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct BlockMetadata { + /// Centroid (arithmetic mean) of the points in the block. + #[cfg_attr(feature = "serde", serde(with = "crate::serde_arrays"))] + pub centroid: [f64; D], + /// Maximum distance from the centroid to any point in the block. + pub radius: f64, + /// Variance of distances from the centroid. + pub variance: f64, + /// Average cosine alignment of points with the centroid. + pub concentration: f64, + /// Number of points summarized by this block. + pub count: usize, +} + +impl Default for BlockMetadata { + fn default() -> Self { + Self::empty() + } +} + +impl BlockMetadata { + /// Return an empty block with all fields set to zero. + pub const fn empty() -> Self { + Self { + centroid: [0.0; D], + radius: 0.0, + variance: 0.0, + concentration: 0.0, + count: 0, + } + } + + /// Compute metadata from a slice of `D`-dimensional points. + pub fn from_points(points: &[[f64; D]]) -> Self { + if points.is_empty() { + return Self::empty(); + } + + let n = points.len(); + let mut centroid = [0.0f64; D]; + for point in points { + for d in 0..D { + centroid[d] += point[d]; + } + } + for val in centroid.iter_mut() { + *val /= n as f64; + } + + let centroid_norm = vector_norm(¢roid); + let mut max_dist = 0.0f64; + let mut sum_dist = 0.0f64; + let mut sum_dist_sq = 0.0f64; + let mut sum_cosine = 0.0f64; + + for point in points { + let dist = l2_distance(¢roid, point); + max_dist = max_dist.max(dist); + sum_dist += dist; + sum_dist_sq += dist * dist; + + if centroid_norm > NORM_EPSILON { + let point_norm = vector_norm(point); + if point_norm > NORM_EPSILON { + let dot = dot_product(¢roid, point); + sum_cosine += dot / (centroid_norm * point_norm); + } + } + } + + let mean_dist = sum_dist / n as f64; + let variance = (sum_dist_sq / n as f64) - (mean_dist * mean_dist); + + Self { + centroid, + radius: max_dist, + variance: variance.max(0.0), + concentration: sum_cosine / n as f64, + count: n, + } + } + + /// Return an upper bound on the dot-product score with `query`. + /// + /// The bound follows from the Cauchy-Schwarz inequality: + /// `q · p ≤ ||q|| * (||centroid|| + radius)` for any point `p` in the + /// block. + pub fn upper_bound_score(&self, query: &[f64; D]) -> f64 { + let q_norm = vector_norm(query); + let c_norm = vector_norm(&self.centroid); + q_norm * (c_norm + self.radius) + } + + /// Return true if the block can be pruned because its upper-bound score + /// is below `threshold`. + pub fn can_prune(&self, query: &[f64; D], threshold: f64) -> bool { + self.upper_bound_score(query) < threshold + } +} + +/// Strategy for compressing a block based on its geometric properties. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum CompressionStrategy { + /// Store the centroid and delta-encode residuals. + CentroidDelta, + /// Aggressive 4-bit quantization for highly concentrated blocks. + Int4Quantize, + /// Keep full precision for dispersed blocks. + FullPrecision, +} + +/// Select a compression strategy for a block from its metadata. +pub fn select_compression(meta: &BlockMetadata) -> CompressionStrategy { + if meta.variance < LOW_VARIANCE_THRESHOLD { + CompressionStrategy::CentroidDelta + } else if meta.concentration > HIGH_CONCENTRATION_THRESHOLD { + CompressionStrategy::Int4Quantize + } else { + CompressionStrategy::FullPrecision + } +} + +/// Estimate the compression ratio achievable for a block. +pub fn estimate_compression_ratio(meta: &BlockMetadata) -> f64 { + match select_compression(meta) { + CompressionStrategy::CentroidDelta => COMPACT_COMPRESSION_RATIO, + CompressionStrategy::Int4Quantize => COMPACT_COMPRESSION_RATIO, + CompressionStrategy::FullPrecision => NO_COMPRESSION_RATIO, + } +} + +/// Hierarchical tree of geometric block summaries. +/// +/// The tree has three fixed levels with a fan-in of four. Level 0 stores the +/// finest blocks, level 1 aggregates four level-0 blocks, and level 2 +/// aggregates four level-1 blocks. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct HierarchicalBlockTree { + #[cfg_attr( + feature = "serde", + serde( + serialize_with = "crate::serde_arrays::serialize_2d", + deserialize_with = "crate::serde_arrays::deserialize_2d" + ) + )] + levels: [[BlockMetadata; MAX_BLOCKS]; 3], + counts: [usize; 3], +} + +impl HierarchicalBlockTree { + /// Create an empty hierarchical block tree. + pub fn new() -> Self { + Self { + levels: [[BlockMetadata::empty(); MAX_BLOCKS]; 3], + counts: [0; 3], + } + } + + /// Build the hierarchy from a slice of fine-level blocks. + pub fn build_from_blocks(&mut self, blocks: &[BlockMetadata]) { + let n0 = blocks.len().min(MAX_BLOCKS); + self.levels[0][..n0].copy_from_slice(&blocks[..n0]); + self.counts[0] = n0; + + let n1 = n0.div_ceil(4); + for i in 0..n1 { + let start = i * 4; + let end = (start + 4).min(n0); + self.levels[1][i] = aggregate_blocks(&blocks[start..end]); + } + self.counts[1] = n1; + + let n2 = n1.div_ceil(4); + for i in 0..n2 { + let start = i * 4; + let end = (start + 4).min(n1); + self.levels[2][i] = aggregate_blocks(&self.levels[1][start..end]); + } + self.counts[2] = n2; + } + + /// Query the tree and return a boolean mask indicating which level-0 + /// blocks cannot be pruned for `query` given `threshold`. + pub fn hierarchical_query(&self, query: &[f64; D], threshold: f64) -> [bool; MAX_BLOCKS] { + let mut result = [false; MAX_BLOCKS]; + + let mut active_l2 = [true; MAX_BLOCKS]; + for (i, active) in active_l2.iter_mut().enumerate().take(self.counts[2]) { + if self.levels[2][i].can_prune(query, threshold) { + *active = false; + } + } + + let mut active_l1 = [false; MAX_BLOCKS]; + for (i, active) in active_l1.iter_mut().enumerate().take(self.counts[1]) { + let parent = i / 4; + if parent < self.counts[2] + && active_l2[parent] + && !self.levels[1][i].can_prune(query, threshold) + { + *active = true; + } + } + + for (i, res) in result.iter_mut().enumerate().take(self.counts[0]) { + let parent = i / 4; + if parent < self.counts[1] + && active_l1[parent] + && !self.levels[0][i].can_prune(query, threshold) + { + *res = true; + } + } + + result + } + + /// Return the fraction of level-0 blocks that are marked inactive. + /// + /// Returns `0.0` when the tree has no level-0 blocks. + pub fn pruning_ratio(&self, active_mask: &[bool; MAX_BLOCKS]) -> f64 { + if self.counts[0] == 0 { + return 0.0; + } + let active = active_mask.iter().filter(|&&x| x).count(); + 1.0 - (active as f64 / self.counts[0] as f64) + } +} + +impl Default for HierarchicalBlockTree { + fn default() -> Self { + Self::new() + } +} + +fn aggregate_blocks(blocks: &[BlockMetadata]) -> BlockMetadata { + if blocks.is_empty() { + return BlockMetadata::empty(); + } + + let mut centroid = [0.0f64; D]; + let mut total_count = 0usize; + let mut max_radius = 0.0f64; + let mut sum_variance = 0.0f64; + let mut sum_concentration = 0.0f64; + + for block in blocks { + let w = block.count as f64; + for (d, c) in centroid.iter_mut().enumerate() { + *c += block.centroid[d] * w; + } + total_count += block.count; + max_radius = max_radius.max(block.radius); + sum_variance += block.variance * w; + sum_concentration += block.concentration * w; + } + + if total_count > 0 { + for c in centroid.iter_mut() { + *c /= total_count as f64; + } + } + + for block in blocks { + let dist = l2_distance(¢roid, &block.centroid); + let effective_radius = dist + block.radius; + max_radius = max_radius.max(effective_radius); + } + + BlockMetadata { + centroid, + radius: max_radius, + variance: if total_count > 0 { + sum_variance / total_count as f64 + } else { + 0.0 + }, + concentration: if total_count > 0 { + sum_concentration / total_count as f64 + } else { + 0.0 + }, + count: total_count, + } +} + +fn l2_distance(a: &[f64; D], b: &[f64; D]) -> f64 { + let mut sum = 0.0; + for d in 0..D { + let diff = a[d] - b[d]; + sum += diff * diff; + } + sqrt(sum) +} + +fn dot_product(a: &[f64; D], b: &[f64; D]) -> f64 { + let mut sum = 0.0; + for d in 0..D { + sum += a[d] * b[d]; + } + sum +} + +fn vector_norm(v: &[f64; D]) -> f64 { + sqrt(dot_product(v, v)) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn single_point_metadata() { + let points = [[1.0, 2.0, 3.0]]; + let meta = BlockMetadata::from_points(&points); + + assert!((meta.centroid[0] - 1.0).abs() < 1e-10); + assert_eq!(meta.radius, 0.0); + assert_eq!(meta.count, 1); + } + + #[test] + fn centroid_and_radius() { + let points = [[0.0, 0.0, 0.0], [2.0, 0.0, 0.0]]; + let meta = BlockMetadata::from_points(&points); + + assert!((meta.centroid[0] - 1.0).abs() < 1e-10); + assert!((meta.radius - 1.0).abs() < 1e-10); + } + + #[test] + fn empty_block_is_empty() { + let meta = BlockMetadata::<3>::from_points(&[]); + assert_eq!(meta, BlockMetadata::empty()); + } + + #[test] + fn pruning_bound() { + let points = [[1.0, 0.0, 0.0], [2.0, 0.0, 0.0]]; + let meta = BlockMetadata::from_points(&points); + let query = [1.0, 0.0, 0.0]; + + // upper_bound_score = ||q|| * (||centroid|| + radius) = 1 * (1 + 1) = 2. + assert!(meta.can_prune(&query, 3.0)); + assert!(!meta.can_prune(&query, 1.0)); + } + + #[test] + fn compression_strategy_selection() { + let mut meta = BlockMetadata::<3>::empty(); + + meta.variance = 0.05; + assert_eq!( + select_compression(&meta), + CompressionStrategy::CentroidDelta + ); + + meta.variance = 0.5; + meta.concentration = 0.95; + assert_eq!(select_compression(&meta), CompressionStrategy::Int4Quantize); + + meta.concentration = 0.5; + assert_eq!( + select_compression(&meta), + CompressionStrategy::FullPrecision + ); + } + + #[test] + fn hierarchical_query_prunes_blocks() { + let mut tree = HierarchicalBlockTree::<3>::new(); + let blocks = [ + BlockMetadata::from_points(&[[0.0, 0.0, 0.0]]), + BlockMetadata::from_points(&[[100.0, 0.0, 0.0]]), + ]; + tree.build_from_blocks(&blocks); + + // query norm is 1, so block 0 has score 0 and is pruned, + // while block 1 has score 100 and is kept. + let query = [1.0, 0.0, 0.0]; + let threshold = 10.0; + let mask = tree.hierarchical_query(&query, threshold); + + assert!(!mask[0]); + assert!(mask[1]); + assert!(tree.pruning_ratio(&mask) > 0.0); + } + + #[test] + fn aggregation_counts_children() { + let blocks = [ + BlockMetadata::from_points(&[[0.0, 0.0, 0.0], [2.0, 0.0, 0.0]]), + BlockMetadata::from_points(&[[4.0, 0.0, 0.0], [6.0, 0.0, 0.0]]), + ]; + let parent = aggregate_blocks(&blocks); + + assert_eq!(parent.count, 4); + assert!((parent.centroid[0] - 3.0).abs() < 1e-10); + } +} diff --git a/crates/adaptive-topology/src/governor.rs b/crates/adaptive-topology/src/governor.rs new file mode 100644 index 00000000..5d6152d6 --- /dev/null +++ b/crates/adaptive-topology/src/governor.rs @@ -0,0 +1,231 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Adaptive threshold controller using a PD control law on an effective tick rate. + +/// Target effective tick rate the governor tries to maintain, measured in Hz. +/// +/// This value balances responsiveness against overhead: higher rates react +/// faster but consume more CPU, while lower rates are cheaper but may miss +/// transients. +const TARGET_TICK_RATE: f64 = 1000.0; + +/// Proportional gain applied to the instantaneous control error. +const ALPHA: f64 = 0.01; + +/// Derivative gain applied to the rate of change of the control error. +/// +/// The derivative term dampens oscillations caused by the proportional +/// response alone. +const BETA: f64 = 0.05; + +/// Minimum allowed epsilon. Prevents the threshold from collapsing to zero, +/// which would force continuous triggering. +const EPSILON_MIN: f64 = 0.001; + +/// Maximum allowed epsilon. Prevents the threshold from growing so large +/// that the system never wakes up. +const EPSILON_MAX: f64 = 10.0; + +/// Default initial epsilon when no explicit starting threshold is supplied. +const EPSILON_INITIAL: f64 = 0.1; + +/// Adaptive threshold controller. +/// +/// The controller maintains a sensitivity threshold `epsilon`. It observes +/// the effective tick rate `deviation_delta / epsilon` and adjusts epsilon +/// so the rate stays near `TARGET_TICK_RATE`. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct GeometricGovernor { + epsilon: f64, + last_error: f64, + alpha: f64, + beta: f64, + adjustment_count: u64, +} + +impl GeometricGovernor { + /// Create a new governor with the default threshold and gains. + pub fn new() -> Self { + Self { + epsilon: EPSILON_INITIAL, + last_error: 0.0, + alpha: ALPHA, + beta: BETA, + adjustment_count: 0, + } + } + + /// Create a governor with a custom initial threshold. + /// + /// The supplied value is clamped to `EPSILON_MIN` and `EPSILON_MAX`. + pub fn with_epsilon(epsilon: f64) -> Self { + let mut gov = Self::new(); + if epsilon.is_finite() { + gov.epsilon = epsilon.clamp(EPSILON_MIN, EPSILON_MAX); + } + gov + } + + /// Create a governor with custom proportional and derivative gains. + pub fn with_gains(alpha: f64, beta: f64) -> Self { + Self { + epsilon: EPSILON_INITIAL, + last_error: 0.0, + alpha: if alpha.is_finite() { alpha } else { ALPHA }, + beta: if beta.is_finite() { beta } else { BETA }, + adjustment_count: 0, + } + } + + /// Return the current epsilon value. + pub fn epsilon(&self) -> f64 { + self.epsilon + } + + /// Return the number of adaptations performed so far. + pub fn adjustment_count(&self) -> u64 { + self.adjustment_count + } + + /// Return the error from the most recent adaptation. + pub fn last_error(&self) -> f64 { + self.last_error + } + + /// Adapt epsilon based on the observed deviation over `dt` seconds. + /// + /// The effective tick rate is `deviation_delta / epsilon`. The control + /// error is `TARGET_TICK_RATE - rate`. A positive error means the system + /// is too slow and epsilon should be lowered; a negative error means the + /// system is too fast and epsilon should be raised. + pub fn adapt(&mut self, deviation_delta: f64, dt: f64) -> f64 { + if dt <= 0.0 || !dt.is_finite() || !deviation_delta.is_finite() || self.epsilon <= 0.0 { + return self.epsilon; + } + + let current_rate = deviation_delta / self.epsilon; + let error = TARGET_TICK_RATE - current_rate; + let d_error = (error - self.last_error) / dt; + let adjustment = self.alpha * error + self.beta * d_error; + + // Subtract the adjustment so that a negative error (too fast) raises + // epsilon and a positive error (too slow) lowers epsilon. This fixes + // the sign bug in the original Aether-Lang implementation. + self.epsilon = (self.epsilon - adjustment).clamp(EPSILON_MIN, EPSILON_MAX); + self.last_error = error; + self.adjustment_count += 1; + + self.epsilon + } + + /// Return true if `deviation` meets or exceeds the current threshold. + pub fn should_trigger(&self, deviation: f64) -> bool { + deviation.is_finite() && deviation >= self.epsilon + } + + /// Reset the governor to its initial state. + pub fn reset(&mut self) { + self.epsilon = EPSILON_INITIAL; + self.last_error = 0.0; + self.adjustment_count = 0; + } +} + +impl Default for GeometricGovernor { + fn default() -> Self { + Self::new() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn initial_epsilon_is_default() { + let gov = GeometricGovernor::new(); + assert!((gov.epsilon() - EPSILON_INITIAL).abs() < 1e-10); + } + + #[test] + fn custom_epsilon_is_clamped() { + let low = GeometricGovernor::with_epsilon(0.0001); + assert!((low.epsilon() - EPSILON_MIN).abs() < 1e-10); + + let high = GeometricGovernor::with_epsilon(100.0); + assert!((high.epsilon() - EPSILON_MAX).abs() < 1e-10); + } + + #[test] + fn non_finite_inputs_keep_governor_state_valid() { + let mut gov = GeometricGovernor::with_epsilon(f64::NAN); + assert!((gov.epsilon() - EPSILON_INITIAL).abs() < 1e-10); + assert_eq!(gov.adapt(f64::NAN, 1.0), EPSILON_INITIAL); + assert_eq!(gov.adapt(1.0, f64::INFINITY), EPSILON_INITIAL); + assert!(!gov.should_trigger(f64::NAN)); + } + + #[test] + fn high_load_raises_epsilon() { + let mut gov = GeometricGovernor::new(); + let initial = gov.epsilon(); + + // High deviation means the system is waking too often, so epsilon + // should increase to reduce sensitivity. + gov.adapt(10_000.0, 0.001); + + assert!(gov.epsilon() > initial, "high deviation must raise epsilon"); + } + + #[test] + fn low_load_lowers_epsilon() { + let mut gov = GeometricGovernor::new(); + let initial = gov.epsilon(); + + // Very low deviation means the system is too sluggish, so epsilon + // should decrease to increase sensitivity. + for _ in 0..10 { + gov.adapt(0.0001, 0.001); + } + + assert!(gov.epsilon() < initial, "low deviation must lower epsilon"); + } + + #[test] + fn epsilon_stays_within_bounds() { + let mut gov = GeometricGovernor::new(); + for _ in 0..10_000 { + gov.adapt(1_000_000.0, 0.001); + } + assert!(gov.epsilon() >= EPSILON_MIN); + assert!(gov.epsilon() <= EPSILON_MAX); + } + + #[test] + fn zero_dt_is_ignored() { + let mut gov = GeometricGovernor::new(); + let before = gov.epsilon(); + assert_eq!(gov.adapt(100.0, 0.0), before); + assert_eq!(gov.adjustment_count(), 0); + } + + #[test] + fn trigger_threshold() { + let gov = GeometricGovernor::with_epsilon(0.5); + assert!(!gov.should_trigger(0.4)); + assert!(gov.should_trigger(0.5)); + assert!(gov.should_trigger(0.6)); + } + + #[test] + fn reset_clears_state() { + let mut gov = GeometricGovernor::new(); + gov.adapt(10_000.0, 0.001); + gov.reset(); + assert!((gov.epsilon() - EPSILON_INITIAL).abs() < 1e-10); + assert_eq!(gov.adjustment_count(), 0); + assert_eq!(gov.last_error(), 0.0); + } +} diff --git a/crates/adaptive-topology/src/lib.rs b/crates/adaptive-topology/src/lib.rs new file mode 100644 index 00000000..745caaa3 --- /dev/null +++ b/crates/adaptive-topology/src/lib.rs @@ -0,0 +1,216 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Topology, manifold, drift, and adaptive-threshold primitives for NeMo Relay. + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(feature = "serde")] +pub(crate) mod serde_arrays { + //! Helpers for serializing fixed-size arrays that serde does not handle + //! natively (const-generic sizes or lengths above the built-in limit). + + use core::fmt; + use core::marker::PhantomData; + use serde::de::{SeqAccess, Visitor}; + use serde::ser::SerializeTuple; + use serde::{Deserializer, Serializer}; + + /// Serialize a fixed-size array as a tuple sequence. + pub fn serialize(value: &[T; N], serializer: S) -> Result + where + T: serde::Serialize, + S: Serializer, + { + let mut tuple = serializer.serialize_tuple(N)?; + for item in value.iter() { + tuple.serialize_element(item)?; + } + tuple.end() + } + + /// Deserialize a fixed-size array from a tuple sequence. + pub fn deserialize<'de, T, D, const N: usize>(deserializer: D) -> Result<[T; N], D::Error> + where + T: serde::Deserialize<'de> + Default + Copy, + D: Deserializer<'de>, + { + struct ArrayVisitor(PhantomData); + + impl<'de, T, const N: usize> Visitor<'de> for ArrayVisitor + where + T: serde::Deserialize<'de> + Default + Copy, + { + type Value = [T; N]; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "an array of {} elements", N) + } + + fn visit_seq>(self, mut seq: A) -> Result { + let mut arr = [T::default(); N]; + for (i, slot) in arr.iter_mut().enumerate() { + *slot = seq + .next_element()? + .ok_or_else(|| serde::de::Error::invalid_length(i, &self))?; + } + Ok(arr) + } + } + + deserializer.deserialize_tuple(N, ArrayVisitor(PhantomData)) + } + + /// Serialize a fixed-size two-dimensional array as a flat tuple sequence. + pub fn serialize_2d( + value: &[[T; N]; M], + serializer: S, + ) -> Result + where + T: serde::Serialize, + S: Serializer, + { + let mut tuple = serializer.serialize_tuple(M * N)?; + for row in value.iter() { + for item in row.iter() { + tuple.serialize_element(item)?; + } + } + tuple.end() + } + + /// Deserialize a fixed-size two-dimensional array from a flat tuple sequence. + pub fn deserialize_2d<'de, T, D, const M: usize, const N: usize>( + deserializer: D, + ) -> Result<[[T; N]; M], D::Error> + where + T: serde::Deserialize<'de> + Default + Copy, + D: Deserializer<'de>, + { + struct Array2Visitor(PhantomData); + + impl<'de, T, const M: usize, const N: usize> Visitor<'de> for Array2Visitor + where + T: serde::Deserialize<'de> + Default + Copy, + { + type Value = [[T; N]; M]; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "a {}x{} array", M, N) + } + + fn visit_seq>(self, mut seq: A) -> Result { + let mut arr = [[T::default(); N]; M]; + for (i, row) in arr.iter_mut().enumerate() { + for (j, slot) in row.iter_mut().enumerate() { + *slot = seq + .next_element()? + .ok_or_else(|| serde::de::Error::invalid_length(i * N + j, &self))?; + } + } + Ok(arr) + } + } + + deserializer.deserialize_tuple(M * N, Array2Visitor(PhantomData)) + } +} + +pub mod convergence; +pub mod drift; +pub mod geometry; +pub mod governor; +pub mod manifold; +pub mod topology; + +pub use convergence::{BettiNumbers, ConvergenceDetector}; +pub use drift::DriftDetector; +pub use governor::GeometricGovernor; + +#[cfg(all(test, feature = "serde"))] +mod serde_tests { + use super::*; + use geometry::{BlockMetadata, CompressionStrategy, HierarchicalBlockTree}; + use manifold::{GeometricConcentrator, ManifoldPoint, SparseAttentionGraph, TimeDelayEmbedder}; + use topology::{TopologicalShape, VerifyResult}; + + #[test] + fn round_trip_public_types() { + let governor = GeometricGovernor::new(); + let governor_json = serde_json::to_string(&governor).unwrap(); + let governor_back: GeometricGovernor = serde_json::from_str(&governor_json).unwrap(); + assert_eq!(governor, governor_back); + + let betti = BettiNumbers::new(1, 0); + let betti_json = serde_json::to_string(&betti).unwrap(); + let betti_back: BettiNumbers = serde_json::from_str(&betti_json).unwrap(); + assert_eq!(betti, betti_back); + + let shape = TopologicalShape::new(2, 1, 100); + let shape_json = serde_json::to_string(&shape).unwrap(); + let shape_back: TopologicalShape = serde_json::from_str(&shape_json).unwrap(); + assert_eq!(shape, shape_back); + + let verify = VerifyResult::Pass; + let verify_json = serde_json::to_string(&verify).unwrap(); + let verify_back: VerifyResult = serde_json::from_str(&verify_json).unwrap(); + assert_eq!(verify, verify_back); + + let point = ManifoldPoint::<3>::new([1.0, 2.0, 3.0]); + let point_json = serde_json::to_string(&point).unwrap(); + let point_back: ManifoldPoint<3> = serde_json::from_str(&point_json).unwrap(); + assert_eq!(point, point_back); + + let mut embedder = TimeDelayEmbedder::<2>::new(1); + embedder.push(1.0); + embedder.push(2.0); + embedder.push(3.0); + let embedder_json = serde_json::to_string(&embedder).unwrap(); + let embedder_back: TimeDelayEmbedder<2> = serde_json::from_str(&embedder_json).unwrap(); + assert_eq!(embedder, embedder_back); + + let mut graph = SparseAttentionGraph::<3>::new(1.0); + graph.add_point(ManifoldPoint::new([0.0, 0.0, 0.0])); + graph.add_point(ManifoldPoint::new([0.5, 0.0, 0.0])); + let graph_json = serde_json::to_string(&graph).unwrap(); + let graph_back: SparseAttentionGraph<3> = serde_json::from_str(&graph_json).unwrap(); + assert_eq!(graph, graph_back); + + let mut concentrator = GeometricConcentrator::<3>::new(); + concentrator.update(&ManifoldPoint::new([1.0, 0.0, 0.0])); + let concentrator_json = serde_json::to_string(&concentrator).unwrap(); + let concentrator_back: GeometricConcentrator<3> = + serde_json::from_str(&concentrator_json).unwrap(); + assert_eq!(concentrator, concentrator_back); + + let block = BlockMetadata::<3>::from_points(&[[1.0, 0.0, 0.0], [2.0, 0.0, 0.0]]); + let block_json = serde_json::to_string(&block).unwrap(); + let block_back: BlockMetadata<3> = serde_json::from_str(&block_json).unwrap(); + assert_eq!(block, block_back); + + let strategy = CompressionStrategy::Int4Quantize; + let strategy_json = serde_json::to_string(&strategy).unwrap(); + let strategy_back: CompressionStrategy = serde_json::from_str(&strategy_json).unwrap(); + assert_eq!(strategy, strategy_back); + + let mut tree = HierarchicalBlockTree::<3>::new(); + tree.build_from_blocks(&[block]); + let tree_json = serde_json::to_string(&tree).unwrap(); + let tree_back: HierarchicalBlockTree<3> = serde_json::from_str(&tree_json).unwrap(); + assert_eq!(tree, tree_back); + + let mut drift = DriftDetector::<3>::new(); + drift.update(&[1.0, 0.0, 0.0]); + drift.update(&[2.0, 0.0, 0.0]); + let drift_json = serde_json::to_string(&drift).unwrap(); + let drift_back: DriftDetector<3> = serde_json::from_str(&drift_json).unwrap(); + assert_eq!(drift, drift_back); + + let mut detector = ConvergenceDetector::new(0.001, 3); + detector.record_epoch(BettiNumbers::new(1, 0), 0.05, 0.04); + detector.record_epoch(BettiNumbers::new(1, 0), 0.001, 0.02); + let detector_json = serde_json::to_string(&detector).unwrap(); + let detector_back: ConvergenceDetector = serde_json::from_str(&detector_json).unwrap(); + assert_eq!(detector, detector_back); + } +} diff --git a/crates/adaptive-topology/src/manifold.rs b/crates/adaptive-topology/src/manifold.rs new file mode 100644 index 00000000..61d5092d --- /dev/null +++ b/crates/adaptive-topology/src/manifold.rs @@ -0,0 +1,467 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Manifold primitives: points, time-delay embeddings, sparse attention graphs, +//! and geometric concentration. + +use libm::sqrt; + +/// Default time-delay parameter used when none is supplied. +const DEFAULT_TAU: usize = 1; + +/// Maximum number of points stored in a [`SparseAttentionGraph`]. +/// +/// The limit keeps the adjacency bitmasks within a single `u64` per point +/// and bounds stack usage in `no_std` builds. +const MAX_GRAPH_POINTS: usize = 64; + +/// Default capacity of the scalar buffer used by [`TimeDelayEmbedder`]. +/// +/// The buffer must hold at least `D * tau` samples. A capacity of 256 +/// supports embedding dimensions and delays used by the public API. +const EMBED_BUFFER_CAPACITY: usize = 256; + +/// Maximum dimension tracked by [`GeometricConcentrator`] for running +/// statistics. Concentration is a dimension-reduction primitive; capping +/// the tracked dimension at 8 keeps the struct small. +const MAX_CONCENTRATOR_DIM: usize = 8; + +/// A point in a `D`-dimensional manifold. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct ManifoldPoint { + /// Coordinates of the point. + #[cfg_attr(feature = "serde", serde(with = "crate::serde_arrays"))] + pub coords: [f64; D], +} + +impl Default for ManifoldPoint { + fn default() -> Self { + Self::zero() + } +} + +impl ManifoldPoint { + /// Create a point at the origin. + pub const fn zero() -> Self { + Self { coords: [0.0; D] } + } + + /// Create a point from its coordinates. + pub const fn new(coords: [f64; D]) -> Self { + Self { coords } + } + + /// Return the Euclidean distance to another point. + pub fn distance(&self, other: &Self) -> f64 { + let mut sum = 0.0; + for i in 0..D { + let d = self.coords[i] - other.coords[i]; + sum += d * d; + } + sqrt(sum) + } + + /// Return true if this point lies within `epsilon` of `other`. + pub fn is_neighbor(&self, other: &Self, epsilon: f64) -> bool { + self.distance(other) < epsilon + } +} + +/// Time-delay embedder that maps a 1-D scalar signal into a `D`-dimensional +/// manifold according to Takens' embedding theorem. +/// +/// The embedding at time `t` is `[x(t), x(t-tau), x(t-2*tau), ...]`. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct TimeDelayEmbedder { + tau: usize, + #[cfg_attr(feature = "serde", serde(with = "crate::serde_arrays"))] + buffer: [f64; EMBED_BUFFER_CAPACITY], + buffer_pos: usize, + buffer_len: usize, +} + +impl TimeDelayEmbedder { + /// Create an embedder with the supplied delay. A zero delay is normalized + /// to `DEFAULT_TAU`. + /// + /// # Panics + /// + /// Panics if `D * tau` exceeds `EMBED_BUFFER_CAPACITY`. This is a + /// programming error, not a runtime failure. + pub fn new(tau: usize) -> Self { + let tau = if tau == 0 { DEFAULT_TAU } else { tau }; + assert!( + D * tau <= EMBED_BUFFER_CAPACITY, + "TimeDelayEmbedder D * tau ({}) exceeds EMBED_BUFFER_CAPACITY ({})", + D * tau, + EMBED_BUFFER_CAPACITY + ); + Self { + tau, + buffer: [0.0; EMBED_BUFFER_CAPACITY], + buffer_pos: 0, + buffer_len: 0, + } + } + + /// Push a new scalar sample into the buffer. + pub fn push(&mut self, value: f64) { + self.buffer[self.buffer_pos] = value; + self.buffer_pos = (self.buffer_pos + 1) % EMBED_BUFFER_CAPACITY; + if self.buffer_len < EMBED_BUFFER_CAPACITY { + self.buffer_len += 1; + } + } + + /// Return the current embedded point, or `None` if the buffer does not + /// yet contain enough samples. + pub fn embed(&self) -> Option> { + let required = D * self.tau; + if self.buffer_len < required { + return None; + } + + let mut point = ManifoldPoint::zero(); + for i in 0..D { + let offset = i * self.tau; + let idx = + (self.buffer_pos + EMBED_BUFFER_CAPACITY - 1 - offset) % EMBED_BUFFER_CAPACITY; + point.coords[i] = self.buffer[idx]; + } + + Some(point) + } + + /// Reset the embedder to an empty state. + pub fn reset(&mut self) { + self.buffer = [0.0; EMBED_BUFFER_CAPACITY]; + self.buffer_pos = 0; + self.buffer_len = 0; + } +} + +/// Sparse attention graph where edges exist only between points within an +/// epsilon-neighborhood. +/// +/// The adjacency is stored as a `u64` bitmask per point, limiting the graph +/// to `MAX_GRAPH_POINTS` vertices. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct SparseAttentionGraph { + #[cfg_attr(feature = "serde", serde(with = "crate::serde_arrays"))] + points: [ManifoldPoint; MAX_GRAPH_POINTS], + point_count: usize, + epsilon: f64, + #[cfg_attr(feature = "serde", serde(with = "crate::serde_arrays"))] + adjacency: [u64; MAX_GRAPH_POINTS], +} + +impl SparseAttentionGraph { + /// Create an empty graph with the given neighborhood radius. + pub fn new(epsilon: f64) -> Self { + Self { + points: [ManifoldPoint::zero(); MAX_GRAPH_POINTS], + point_count: 0, + epsilon, + adjacency: [0; MAX_GRAPH_POINTS], + } + } + + /// Add a point to the graph and return its index, or `None` if the + /// graph is full. + pub fn add_point(&mut self, point: ManifoldPoint) -> Option { + if self.point_count >= MAX_GRAPH_POINTS { + return None; + } + + let idx = self.point_count; + self.points[idx] = point; + + let mut mask = 0u64; + for i in 0..idx { + if point.is_neighbor(&self.points[i], self.epsilon) { + mask |= 1 << i; + self.adjacency[i] |= 1 << idx; + } + } + self.adjacency[idx] = mask; + + self.point_count += 1; + Some(idx) + } + + /// Return the number of neighbors (degree) of point `idx`. + pub fn degree(&self, idx: usize) -> u32 { + if idx >= self.point_count { + return 0; + } + self.adjacency[idx].count_ones() + } + + /// Return true if points `i` and `j` are neighbors. + pub fn are_neighbors(&self, i: usize, j: usize) -> bool { + if i >= self.point_count || j >= self.point_count { + return false; + } + (self.adjacency[i] & (1 << j)) != 0 + } + + /// Count connected components (`β₀`) using iterative depth-first search. + pub fn compute_betti_0(&self) -> u32 { + if self.point_count == 0 { + return 0; + } + + let mut visited = [false; MAX_GRAPH_POINTS]; + let mut components = 0u32; + + for start in 0..self.point_count { + if visited[start] { + continue; + } + + components += 1; + let mut stack = [0usize; MAX_GRAPH_POINTS]; + let mut stack_top = 1; + stack[0] = start; + + while stack_top > 0 { + stack_top -= 1; + let current = stack[stack_top]; + + if visited[current] { + continue; + } + visited[current] = true; + + for (neighbor, is_visited) in visited.iter().enumerate().take(self.point_count) { + if !is_visited + && self.are_neighbors(current, neighbor) + && stack_top < MAX_GRAPH_POINTS + { + stack[stack_top] = neighbor; + stack_top += 1; + } + } + } + } + + components + } + + /// Estimate the number of 1-dimensional holes (`β₁`) using the Euler + /// characteristic approximation `β₁ ≈ E - V + β₀`. + pub fn estimate_betti_1(&self) -> u32 { + let v = self.point_count as i32; + let mut e = 0i32; + + for i in 0..self.point_count { + e += self.adjacency[i].count_ones() as i32; + } + e /= 2; + + let b0 = self.compute_betti_0() as i32; + let b1 = e - v + b0; + b1.max(0) as u32 + } + + /// Return the topological shape signature `(β₀, β₁)`. + pub fn shape(&self) -> (u32, u32) { + (self.compute_betti_0(), self.estimate_betti_1()) + } + + /// Clear all points and edges from the graph. + pub fn clear(&mut self) { + self.point_count = 0; + self.adjacency = [0; MAX_GRAPH_POINTS]; + } +} + +/// Streaming geometric concentrator that tracks per-coordinate mean and +/// variance to identify the principal axis of a point cloud. +/// +/// Only the first eight coordinates of each point participate in the +/// running statistics; dimensions beyond 8 are ignored. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct GeometricConcentrator { + mean: [f64; MAX_CONCENTRATOR_DIM], + variance: [f64; MAX_CONCENTRATOR_DIM], + count: u64, +} + +impl GeometricConcentrator { + /// Create a new concentrator with zero statistics. + pub fn new() -> Self { + Self { + mean: [0.0; MAX_CONCENTRATOR_DIM], + variance: [0.0; MAX_CONCENTRATOR_DIM], + count: 0, + } + } + + /// Update running statistics with a new point using Welford's algorithm. + pub fn update(&mut self, point: &ManifoldPoint) { + self.count += 1; + let n = self.count as f64; + + for i in 0..D.min(MAX_CONCENTRATOR_DIM) { + let delta = point.coords[i] - self.mean[i]; + self.mean[i] += delta / n; + let delta2 = point.coords[i] - self.mean[i]; + self.variance[i] += delta * delta2; + } + } + + /// Return the index of the dimension with the largest variance. + pub fn principal_dimension(&self) -> usize { + let mut max_var = 0.0; + let mut max_dim = 0; + + if self.count > 0 { + for i in 0..D.min(MAX_CONCENTRATOR_DIM) { + let var = self.variance[i] / self.count as f64; + if var > max_var { + max_var = var; + max_dim = i; + } + } + } + + max_dim + } + + /// Project a point onto the principal axis relative to the running mean. + pub fn concentrate_1d(&self, point: &ManifoldPoint) -> f64 { + let dim = self.principal_dimension(); + if dim < D { + point.coords[dim] - self.mean[dim] + } else { + 0.0 + } + } + + /// Return the fraction of total variance captured by the principal + /// dimension. + pub fn concentration_ratio(&self) -> f64 { + if self.count < 2 { + return 0.0; + } + + let dims = D.min(MAX_CONCENTRATOR_DIM); + let total: f64 = self.variance[..dims].iter().sum::() / self.count as f64; + if total == 0.0 { + return 0.0; + } + + let principal = self.variance[self.principal_dimension()] / self.count as f64; + principal / total + } + + /// Reset the concentrator to its initial state. + pub fn reset(&mut self) { + self.mean = [0.0; MAX_CONCENTRATOR_DIM]; + self.variance = [0.0; MAX_CONCENTRATOR_DIM]; + self.count = 0; + } +} + +impl Default for GeometricConcentrator { + fn default() -> Self { + Self::new() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn point_distance() { + let p1 = ManifoldPoint::<3>::new([0.0, 0.0, 0.0]); + let p2 = ManifoldPoint::<3>::new([3.0, 4.0, 0.0]); + assert!((p1.distance(&p2) - 5.0).abs() < 1e-10); + } + + #[test] + fn neighbor_check_respects_epsilon() { + let p1 = ManifoldPoint::<3>::new([0.0, 0.0, 0.0]); + let p2 = ManifoldPoint::<3>::new([0.1, 0.1, 0.0]); + + assert!(p1.is_neighbor(&p2, 0.5)); + assert!(!p1.is_neighbor(&p2, 0.1)); + } + + #[test] + fn time_delay_embedding() { + let mut embedder = TimeDelayEmbedder::<3>::new(1); + for i in 0..10 { + embedder.push(i as f64); + } + + let point = embedder.embed().unwrap(); + assert!((point.coords[0] - 9.0).abs() < 1e-10); + assert!((point.coords[1] - 8.0).abs() < 1e-10); + assert!((point.coords[2] - 7.0).abs() < 1e-10); + } + + #[test] + fn embedder_returns_none_until_ready() { + let mut embedder = TimeDelayEmbedder::<3>::new(2); + for i in 0..5 { + embedder.push(i as f64); + } + assert!(embedder.embed().is_none()); + + embedder.push(5.0); + assert!(embedder.embed().is_some()); + } + + #[test] + #[should_panic(expected = "exceeds EMBED_BUFFER_CAPACITY")] + fn embedder_panics_for_excessive_delay() { + let _ = TimeDelayEmbedder::<256>::new(2); + } + + #[test] + fn single_component_graph() { + let mut graph = SparseAttentionGraph::<3>::new(1.0); + graph.add_point(ManifoldPoint::new([0.0, 0.0, 0.0])); + graph.add_point(ManifoldPoint::new([0.5, 0.0, 0.0])); + graph.add_point(ManifoldPoint::new([0.5, 0.5, 0.0])); + + assert_eq!(graph.compute_betti_0(), 1); + } + + #[test] + fn disconnected_components() { + let mut graph = SparseAttentionGraph::<2>::new(0.1); + graph.add_point(ManifoldPoint::new([0.0, 0.0])); + graph.add_point(ManifoldPoint::new([10.0, 0.0])); + graph.add_point(ManifoldPoint::new([10.1, 0.0])); + + assert_eq!(graph.compute_betti_0(), 2); + } + + #[test] + fn graph_full_returns_none() { + let mut graph = SparseAttentionGraph::<1>::new(1.0); + for _ in 0..MAX_GRAPH_POINTS { + assert!(graph.add_point(ManifoldPoint::new([0.0])).is_some()); + } + assert!(graph.add_point(ManifoldPoint::new([0.0])).is_none()); + } + + #[test] + fn concentrator_principal_axis() { + let mut concentrator = GeometricConcentrator::<3>::new(); + concentrator.update(&ManifoldPoint::new([10.0, 0.0, 0.0])); + concentrator.update(&ManifoldPoint::new([11.0, 0.0, 0.0])); + concentrator.update(&ManifoldPoint::new([12.0, 0.0, 0.0])); + + assert_eq!(concentrator.principal_dimension(), 0); + assert!(concentrator.concentration_ratio() > 0.99); + } +} diff --git a/crates/adaptive-topology/src/topology.rs b/crates/adaptive-topology/src/topology.rs new file mode 100644 index 00000000..c65ad757 --- /dev/null +++ b/crates/adaptive-topology/src/topology.rs @@ -0,0 +1,319 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Topological shape signatures and binary-data verification primitives. + +use libm::sqrt; + +/// Distance threshold used to separate connected components when computing +/// `β₀` over a 1-D byte stream. +const CLUSTER_THRESHOLD: i16 = 15; + +/// Sliding window size used for localized topology analysis. +const WINDOW_SIZE: usize = 64; + +/// Minimum component density (`β₀ / len`) expected for valid data. +const DENSITY_MIN: f64 = 0.1; + +/// Maximum component density expected for valid data. +const DENSITY_MAX: f64 = 0.6; + +/// Maximum allowed `β₁` loop count per window. +const MAX_BETTI_1: u32 = 10; + +/// Tolerance used to decide whether two byte values "close" a loop when +/// computing `β₁`. +const LOOP_TOLERANCE: i16 = 5; + +/// Topological shape signature of a byte sequence. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct TopologicalShape { + /// Number of connected components (`β₀`). + pub betti_0: u32, + /// Heuristic estimate of the number of 1-dimensional holes (loops). + pub betti_1: u32, + /// Normalized component density (`β₀ / data_length`). + pub density: f64, +} + +impl TopologicalShape { + /// Create a shape from Betti numbers and the source data length. + pub fn new(betti_0: u32, betti_1: u32, data_len: usize) -> Self { + let density = if data_len > 0 { + betti_0 as f64 / data_len as f64 + } else { + 0.0 + }; + + Self { + betti_0, + betti_1, + density, + } + } + + /// Return the Euclidean distance between two shape signatures in + /// `(β₀, β₁, density)` space. + pub fn distance(&self, other: &Self) -> f64 { + let d0 = self.betti_0 as f64 - other.betti_0 as f64; + let d1 = self.betti_1 as f64 - other.betti_1 as f64; + let dd = self.density - other.density; + + sqrt(d0 * d0 + d1 * d1 + dd * dd) + } +} + +/// Approximate `β₀` for a 1-D byte stream by counting gaps larger than +/// `CLUSTER_THRESHOLD`. +pub fn compute_betti_0(data: &[u8]) -> u32 { + if data.is_empty() { + return 0; + } + + let mut components = 1u32; + + for window in data.windows(2) { + let dist = (window[0] as i16 - window[1] as i16).abs(); + + if dist > CLUSTER_THRESHOLD { + components += 1; + } + } + + components +} + +/// Heuristic estimate of loop count for a 1-D byte stream. +/// +/// This detects short return patterns of the form `a -> b -> c -> ~a`. It is +/// not a true topological `β₁` computation; it is a fast, deterministic +/// approximation used by [`compute_shape`]. +pub fn estimate_loop_count(data: &[u8]) -> u32 { + if data.len() < 4 { + return 0; + } + + let mut loops = 0u32; + + for window in data.windows(4) { + let a = window[0] as i16; + let b = window[1] as i16; + let c = window[2] as i16; + let d = window[3] as i16; + + if (a - d).abs() <= LOOP_TOLERANCE { + // Count only loops where the middle values actually traverse + // away from the start value. + if (a - b).abs() > LOOP_TOLERANCE || (a - c).abs() > LOOP_TOLERANCE { + loops += 1; + } + } + } + + loops +} + +/// Compute the full topological shape signature of a byte sequence. +pub fn compute_shape(data: &[u8]) -> TopologicalShape { + let betti_0 = compute_betti_0(data); + let betti_1 = estimate_loop_count(data); + TopologicalShape::new(betti_0, betti_1, data.len()) +} + +/// Result of verifying a byte sequence against topological constraints. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum VerifyResult { + /// The data passed all topological checks. + Pass, + /// The component density fell outside the expected range. + InvalidDensity { + /// Observed density. + actual: f64, + /// Minimum allowed density. + min: f64, + /// Maximum allowed density. + max: f64, + }, + /// The loop count exceeded the allowed maximum. + ExcessiveLoops { + /// Observed loop count. + count: u32, + /// Maximum allowed loop count. + max: u32, + }, + /// The shape differed from the reference by more than the threshold. + ShapeMismatch { + /// Observed distance to the reference. + distance: f64, + /// Allowed distance threshold. + threshold: f64, + }, +} + +/// Verify a byte sequence against built-in density and loop-complexity +/// heuristics. +pub fn verify_shape(data: &[u8]) -> VerifyResult { + let shape = compute_shape(data); + + if shape.density < DENSITY_MIN || shape.density > DENSITY_MAX { + return VerifyResult::InvalidDensity { + actual: shape.density, + min: DENSITY_MIN, + max: DENSITY_MAX, + }; + } + + if shape.betti_1 > MAX_BETTI_1 { + return VerifyResult::ExcessiveLoops { + count: shape.betti_1, + max: MAX_BETTI_1, + }; + } + + VerifyResult::Pass +} + +/// Convenience wrapper that returns `true` if `verify_shape` passes. +pub fn is_shape_valid(data: &[u8]) -> bool { + matches!(verify_shape(data), VerifyResult::Pass) +} + +/// Verify a byte sequence against a reference shape using a Wasserstein-like +/// distance, then apply the standard shape checks. +pub fn verify_against_reference( + data: &[u8], + reference: &TopologicalShape, + threshold: f64, +) -> VerifyResult { + let shape = compute_shape(data); + let distance = shape.distance(reference); + + if distance > threshold { + return VerifyResult::ShapeMismatch { + distance, + threshold, + }; + } + + verify_shape(data) +} + +/// Apply `is_shape_valid` over a sliding window of size `window_size`. +/// +/// A `window_size` of zero defaults to `WINDOW_SIZE`. Returns `Ok(())` if +/// every window passes, or `Err(offset)` at the first failing offset. +pub fn verify_sliding_window(data: &[u8], window_size: usize) -> Result<(), usize> { + let size = if window_size == 0 { + WINDOW_SIZE + } else { + window_size + }; + + if data.len() < size { + return if is_shape_valid(data) { Ok(()) } else { Err(0) }; + } + + for (offset, window) in data.windows(size).enumerate() { + if !is_shape_valid(window) { + return Err(offset); + } + } + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn empty_data_has_zero_shape() { + assert_eq!(compute_betti_0(&[]), 0); + assert_eq!(estimate_loop_count(&[]), 0); + let shape = compute_shape(&[]); + assert_eq!(shape.density, 0.0); + } + + #[test] + fn single_component_for_uniform_data() { + let nop_sled = [0x90u8; 64]; + let shape = compute_shape(&nop_sled); + assert_eq!(shape.betti_0, 1); + } + + #[test] + fn two_components_for_single_gap() { + assert_eq!(compute_betti_0(&[0u8, 100]), 2); + } + + #[test] + fn shape_distance() { + let a = TopologicalShape::new(1, 0, 10); + let b = TopologicalShape::new(2, 1, 10); + assert!(a.distance(&b) > 0.0); + assert_eq!(a.distance(&a), 0.0); + } + + #[test] + fn verify_shape_returns_reason() { + // A 64-byte uniform block has density 0, which fails density check. + let data = [0x90u8; 64]; + let result = verify_shape(&data); + assert!(matches!(result, VerifyResult::InvalidDensity { .. })); + } + + #[test] + fn reference_verification_rejects_distant_shape() { + let data = [0x00u8; 16]; + let reference = TopologicalShape::new(10, 5, 16); + let result = verify_against_reference(&data, &reference, 1.0); + assert!(matches!(result, VerifyResult::ShapeMismatch { .. })); + } + + #[test] + fn sliding_window_short_input() { + // A single-byte input has density 1.0, which fails the density check. + let data = [0x90u8]; + assert_eq!(verify_sliding_window(&data, 0), Err(0)); + } + + #[test] + fn sliding_window_passes_multiple_windows() { + // 128 bytes of grouped values: every 64-byte window has 8 components + // and zero loops, giving a valid density of 8/64. + let mut data = [0u8; 128]; + for (i, byte) in data.iter_mut().enumerate() { + let group = i / 8; + *byte = if group % 2 == 0 { 0 } else { 100 }; + } + assert!(verify_sliding_window(&data, 64).is_ok()); + } + + #[test] + fn sliding_window_first_passes_later_fails() { + // First 64 bytes are valid; the remaining 64 bytes are uniform and + // fail the density check, causing a later window to error. + let mut data = [0x90u8; 128]; + for (i, byte) in data.iter_mut().enumerate().take(64) { + let group = i / 8; + *byte = if group % 2 == 0 { 0 } else { 100 }; + } + let result = verify_sliding_window(&data, 64); + assert!(result.is_err()); + assert!(result.unwrap_err() > 0); + } + + #[test] + fn sliding_window_boundary_full_window() { + // When the input length exactly equals the window size, one window + // is verified and the call succeeds for valid data. + let mut data = [0u8; 64]; + for (i, byte) in data.iter_mut().enumerate() { + let group = i / 8; + *byte = if group % 2 == 0 { 0 } else { 100 }; + } + assert!(verify_sliding_window(&data, 64).is_ok()); + } +} diff --git a/crates/adaptive/Cargo.toml b/crates/adaptive/Cargo.toml index c59bf27e..c4e9650b 100644 --- a/crates/adaptive/Cargo.toml +++ b/crates/adaptive/Cargo.toml @@ -15,6 +15,7 @@ workspace = true [dependencies] nemo-relay.workspace = true +nemo-relay-adaptive-topology.workspace = true uuid = { workspace = true, features = ["v4", "v7", "serde"] } serde = { version = "1", features = ["derive"] } serde_json = "1" @@ -34,6 +35,11 @@ redis-backend = ["redis"] [dev-dependencies] tokio = { version = "1", default-features = false, features = ["rt", "macros", "sync", "time", "test-util", "rt-multi-thread"] } tokio-stream = { version = "0.1", default-features = false } +criterion = { version = "0.5", features = ["html_reports"] } + +[[bench]] +name = "convergence_bench" +harness = false [[test]] name = "redis_integration" @@ -46,3 +52,11 @@ path = "tests/integration/runtime_integration_tests.rs" [[test]] name = "acg_module_surface" path = "tests/integration/acg_module_surface_tests.rs" + +[[test]] +name = "topology_convergence" +path = "tests/integration/topology_convergence_tests.rs" + +[[test]] +name = "tool_parallelism_plan" +path = "tests/integration/tool_parallelism_plan_tests.rs" diff --git a/crates/adaptive/README.md b/crates/adaptive/README.md index be23b65b..48f5a054 100644 --- a/crates/adaptive/README.md +++ b/crates/adaptive/README.md @@ -42,7 +42,8 @@ framework. - ✅ **`AdaptiveConfig`**: A canonical config contract for the top-level `adaptive` plugin component. - ✅ **Built-in component settings**: Typed config helpers for telemetry, - adaptive hints, tool parallelism, and the Adaptive Cache Governor. + adaptive hints, tool parallelism, the Adaptive Cache Governor, and + topology-aware convergence, drift, and hint-governor controls. - ✅ **State backends**: In-memory state by default and Redis-backed state behind the `redis-backend` feature. - ✅ **Learning primitives**: Runtime helpers and learners built on NeMo Relay @@ -50,6 +51,9 @@ framework. - ✅ **Adaptive Cache Governor (ACG) module surface**: The canonical `nemo_relay_adaptive::acg` module for PromptIR, provider plugins, stability analysis, and cache telemetry normalization. +- ✅ **Topology-aware adaptive controls**: Optional deterministic signals for + ACG convergence, stale tool-plan invalidation, and learned hint load + shedding. ## Installation diff --git a/crates/adaptive/benches/convergence_bench.rs b/crates/adaptive/benches/convergence_bench.rs new file mode 100644 index 00000000..845b4df7 --- /dev/null +++ b/crates/adaptive/benches/convergence_bench.rs @@ -0,0 +1,183 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Benchmark comparing observations-to-decision for the ACG learner with and +//! without topological convergence detection. +//! +//! The synthetic prompt profile consists of 50 identical observations. Without +//! convergence detection the learner processes the full observation sequence +//! before deciding, while topological convergence detection declares +//! convergence after the configured stability window. +#![allow(missing_docs)] + +use std::collections::HashMap; +use std::sync::{Arc, LazyLock, RwLock}; + +use chrono::Utc; +use criterion::{Criterion, black_box, criterion_group, criterion_main}; +use nemo_relay::codec::request::{AnnotatedLlmRequest, Message, MessageContent}; +use nemo_relay_adaptive::acg::build_prompt_ir; +use nemo_relay_adaptive::acg::prompt_ir::PromptIR; +use nemo_relay_adaptive::acg::stability::StabilityThresholds; +use nemo_relay_adaptive::acg_learner::AcgLearner; +use nemo_relay_adaptive::config::ConvergenceConfig; +use nemo_relay_adaptive::learner::traits::Learner; +use nemo_relay_adaptive::types::cache::HotCache; +use nemo_relay_adaptive::types::records::{CallKind, CallRecord, RunRecord}; +use nemo_relay_adaptive::{InMemoryBackend, StorageBackendDyn}; +use uuid::Uuid; + +static RUNTIME: LazyLock = + LazyLock::new(|| tokio::runtime::Runtime::new().expect("tokio runtime")); + +fn identical_request() -> AnnotatedLlmRequest { + AnnotatedLlmRequest { + messages: vec![ + Message::System { + content: MessageContent::Text("You are a helpful assistant.".to_string()), + name: None, + }, + Message::User { + content: MessageContent::Text("Summarize this.".to_string()), + name: None, + }, + ], + model: Some("gpt-4o".to_string()), + params: None, + tools: None, + tool_choice: None, + store: None, + previous_response_id: None, + truncation: None, + reasoning: None, + include: None, + user: None, + metadata: None, + service_tier: None, + parallel_tool_calls: None, + max_output_tokens: None, + max_tool_calls: None, + top_logprobs: None, + stream: None, + extra: serde_json::Map::new(), + } +} + +fn build_stable_observations(count: usize) -> Vec { + let request = identical_request(); + (0..count) + .map(|_| build_prompt_ir(&request).expect("valid prompt IR")) + .collect() +} + +fn build_run(request: AnnotatedLlmRequest) -> RunRecord { + let now = Utc::now(); + RunRecord { + id: Uuid::now_v7(), + agent_id: "convergence-agent".to_string(), + calls: vec![CallRecord { + kind: CallKind::Llm, + name: "planner".to_string(), + started_at: now, + ended_at: Some(now), + metadata_snapshot: None, + output_tokens: None, + prompt_tokens: None, + total_tokens: None, + model_name: None, + tool_call_count: None, + annotated_request: Some(request.into()), + annotated_response: None, + }], + started_at: now, + ended_at: Some(now), + } +} + +fn empty_cache() -> Arc> { + Arc::new(RwLock::new(HotCache { + plan: None, + trie: None, + agent_hints_default: None, + acg_profiles: HashMap::new(), + acg_profile_observation_counts: HashMap::new(), + acg_stability: None, + acg_observation_count: 0, + })) +} + +fn observations_without_convergence(observations: &[PromptIR]) -> usize { + RUNTIME.block_on(async { + let learner = AcgLearner::new("convergence-agent", 100, StabilityThresholds::default()); + let backend = InMemoryBackend::new(); + let cache = empty_cache(); + + for _ in 0..observations.len() { + let run = build_run(identical_request()); + learner + .process_run(&run, &backend, &cache) + .await + .expect("process run"); + } + observations.len() + }) +} + +fn observations_with_convergence(observations: &[PromptIR]) -> usize { + RUNTIME.block_on(async { + let config = ConvergenceConfig { + enabled: true, + epsilon: 0.001, + stability_window: 3, + }; + let learner = AcgLearner::new_with_convergence( + "convergence-agent", + 100, + StabilityThresholds::default(), + Some(config), + ); + let backend = InMemoryBackend::new(); + let cache = empty_cache(); + + for index in 0..observations.len() { + let run = build_run(identical_request()); + learner + .process_run(&run, &backend, &cache) + .await + .expect("process run"); + + let stability = backend + .load_stability("convergence-agent") + .await + .expect("load stability") + .expect("stability exists"); + if stability.converged { + return index + 1; + } + } + observations.len() + }) +} + +fn bench_convergence(c: &mut Criterion) { + let observations = build_stable_observations(50); + + c.bench_function("without_convergence", |b| { + b.iter(|| observations_without_convergence(black_box(&observations))) + }); + + c.bench_function("with_convergence", |b| { + b.iter(|| observations_with_convergence(black_box(&observations))) + }); + + let without = observations_without_convergence(&observations); + let with = observations_with_convergence(&observations); + println!("observations-to-decision: without={without}, with={with}"); + assert!( + with <= without, + "convergence path should use fewer or equal observations: {with} <= {without}" + ); +} + +criterion_group!(benches, bench_convergence); +criterion_main!(benches); diff --git a/crates/adaptive/src/acg/stability.rs b/crates/adaptive/src/acg/stability.rs index 6141ffa5..f6966b35 100644 --- a/crates/adaptive/src/acg/stability.rs +++ b/crates/adaptive/src/acg/stability.rs @@ -41,6 +41,9 @@ pub struct StabilityAnalysisResult { pub stable_prefix_length: usize, /// Total number of observations included in the analysis. pub total_observations: u32, + /// Whether topological convergence has been declared for this profile. + #[serde(default)] + pub converged: bool, } struct SpanObservations { @@ -70,6 +73,7 @@ pub fn analyze_stability( scores: Vec::new(), stable_prefix_length: 0, total_observations: 0, + converged: false, }; } @@ -94,6 +98,7 @@ pub fn analyze_stability( scores, stable_prefix_length, total_observations, + converged: false, } } diff --git a/crates/adaptive/src/acg_learner.rs b/crates/adaptive/src/acg_learner.rs index 5c0a31ae..2e75ad35 100644 --- a/crates/adaptive/src/acg_learner.rs +++ b/crates/adaptive/src/acg_learner.rs @@ -8,9 +8,12 @@ use std::future::Future; use std::pin::Pin; use std::sync::{Arc, RwLock}; +use nemo_relay_adaptive_topology::{BettiNumbers, ConvergenceDetector}; + use crate::acg::ir_builder::build_prompt_ir; use crate::acg::prompt_ir::PromptIR; use crate::acg::stability::{StabilityThresholds, analyze_stability}; +use crate::config::ConvergenceConfig; use crate::acg_profile::derive_acg_learning_key; use crate::error::{AdaptiveError, Result}; @@ -28,6 +31,8 @@ pub struct AcgLearner { agent_id: String, observation_window: usize, thresholds: StabilityThresholds, + convergence: Option, + convergence_detectors: Arc>>, } impl AcgLearner { @@ -45,12 +50,97 @@ impl AcgLearner { agent_id: impl Into, observation_window: usize, thresholds: StabilityThresholds, + ) -> Self { + Self::new_with_convergence(agent_id, observation_window, thresholds, None) + } + + /// Create a new ACG learner with optional topological convergence + /// detection. + /// + /// # Parameters + /// - `agent_id`: Agent identifier whose observations should be updated. + /// - `observation_window`: Maximum number of observations to retain per + /// profile. + /// - `thresholds`: Stability thresholds used during analysis. + /// - `convergence`: Optional convergence configuration; takes precedence + /// over any global settings when provided. + /// + /// # Returns + /// A configured [`AcgLearner`]. + pub fn new_with_convergence( + agent_id: impl Into, + observation_window: usize, + thresholds: StabilityThresholds, + convergence: Option, ) -> Self { Self { agent_id: agent_id.into(), observation_window, thresholds, + convergence, + convergence_detectors: Arc::new(RwLock::new(HashMap::new())), + } + } + + /// Map a stability analysis result to the topological feature vector used + /// by the convergence detector. + /// + /// The mapping treats the stable prefix of the observation sequence as the + /// number of connected components (`beta_0`) and the remaining unstable + /// spans as 1-dimensional holes (`beta_1`). Drift measures the unstable + /// fraction, and error is the complement of the average stability score. + fn stability_to_convergence_features( + stability: &crate::acg::stability::StabilityAnalysisResult, + ) -> (BettiNumbers, f64, f64) { + let total_spans = stability.scores.len(); + let betti_0 = stability.stable_prefix_length as u32; + let betti_1 = total_spans.saturating_sub(stability.stable_prefix_length) as u32; + let drift = 1.0 - (stability.stable_prefix_length as f64 / total_spans.max(1) as f64); + let avg_score = if stability.scores.is_empty() { + 0.0 + } else { + stability + .scores + .iter() + .map(|score| score.score) + .sum::() + / stability.scores.len() as f64 + }; + let error = 1.0 - avg_score; + + (BettiNumbers::new(betti_0, betti_1), drift, error) + } + + /// Update the per-profile topological convergence detector and return + /// whether the profile has converged. + fn record_stability_epoch( + &self, + profile_key: &str, + stability: &crate::acg::stability::StabilityAnalysisResult, + ) -> Result { + let Some(ref config) = self.convergence else { + return Ok(false); + }; + if !config.enabled { + return Ok(false); } + + let mut detectors = self.convergence_detectors.write().map_err(|error| { + AdaptiveError::Internal(format!("convergence detector lock poisoned: {error}")) + })?; + let stability_window = config.stability_window.max(3); + let detector = detectors + .entry(profile_key.to_string()) + .or_insert_with(|| ConvergenceDetector::new(config.epsilon, stability_window)); + + let (betti, drift, error) = Self::stability_to_convergence_features(stability); + detector.record_epoch(betti, drift, error); + + // Require at least `stability_window` epochs before allowing + // convergence so that error-based convergence cannot fire on the very + // first observation. + let enough_epochs = detector.epoch() as usize >= stability_window; + Ok(detector.is_converged() && enough_epochs) } } @@ -90,6 +180,33 @@ impl Learner for AcgLearner { for (profile_key, new_observations) in grouped_observations.drain() { let existing = backend.load_observations(&profile_key).await?; + let existing_stability = backend.load_stability(&profile_key).await?; + + // If the profile has already converged, reuse the cached + // stability result and skip adding new observations. + if existing_stability + .as_ref() + .map(|stability| stability.converged) + .unwrap_or(false) + { + let cached = existing_stability.unwrap(); + profile_counts.insert(profile_key.clone(), cached.total_observations); + profile_stability.insert(profile_key.clone(), cached.clone()); + + let replace_best = best_profile_seed + .as_ref() + .map(|(_, current)| { + (cached.stable_prefix_length, cached.total_observations) + > (current.stable_prefix_length, current.total_observations) + }) + .unwrap_or(true); + if replace_best { + let observations = existing.unwrap_or_default(); + best_profile_seed = Some((observations, cached)); + } + continue; + } + let mut window: VecDeque = existing.unwrap_or_default().into_iter().collect(); @@ -101,17 +218,26 @@ impl Learner for AcgLearner { } let observations_vec: Vec = window.into_iter().collect(); + let mut stability_result = analyze_stability(&observations_vec, &self.thresholds); + + if self.record_stability_epoch(&profile_key, &stability_result)? { + stability_result.converged = true; + } + backend - .store_observations(&profile_key, &observations_vec) + .store_stability(&profile_key, &stability_result) .await?; - let stability_result = analyze_stability(&observations_vec, &self.thresholds); + // Store the observations that produced this stability result. + // On the epoch that first declares convergence these + // observations are preserved; on subsequent runs the cached + // converged result is reused and this path is skipped. backend - .store_stability(&profile_key, &stability_result) + .store_observations(&profile_key, &observations_vec) .await?; profile_counts.insert(profile_key.clone(), stability_result.total_observations); - profile_stability.insert(profile_key, stability_result.clone()); + profile_stability.insert(profile_key.clone(), stability_result.clone()); let replace_best = best_profile_seed .as_ref() diff --git a/crates/adaptive/src/adaptive_hints_intercept.rs b/crates/adaptive/src/adaptive_hints_intercept.rs index 05613aad..381499e9 100644 --- a/crates/adaptive/src/adaptive_hints_intercept.rs +++ b/crates/adaptive/src/adaptive_hints_intercept.rs @@ -10,12 +10,15 @@ //! transforms the [`LlmRequest`] before it reaches the callable. use std::sync::atomic::{AtomicU32, Ordering}; -use std::sync::{Arc, RwLock}; +use std::sync::{Arc, Mutex, RwLock}; +use std::time::Instant; use nemo_relay::api::llm::LlmRequest; use nemo_relay::api::runtime::LlmRequestInterceptFn; use nemo_relay::codec::request::AnnotatedLlmRequest; +use nemo_relay_adaptive_topology::GeometricGovernor; +use crate::config::GovernorConfig; use crate::context_helpers::{ extract_scope_path, read_manual_latency_sensitivity, resolve_agent_id, }; @@ -121,15 +124,29 @@ pub struct AdaptiveHintsIntercept { hot_cache: Arc>, agent_id: String, call_counter: AtomicU32, + governor: Option>>, } impl AdaptiveHintsIntercept { /// Creates a new `AdaptiveHintsIntercept`. pub fn new(hot_cache: Arc>, agent_id: String) -> Self { + Self::with_governor(hot_cache, agent_id, None) + } + + /// Creates a new `AdaptiveHintsIntercept` with optional load shedding. + pub fn with_governor( + hot_cache: Arc>, + agent_id: String, + governor: Option, + ) -> Self { + let governor = governor + .filter(|config| config.enabled) + .map(|config| Arc::new(Mutex::new(HintGovernor::new(config.epsilon)))); Self { hot_cache, agent_id, call_counter: AtomicU32::new(1), + governor, } } @@ -163,6 +180,21 @@ impl AdaptiveHintsIntercept { } } + fn should_inject_hints(&self, hints: &AgentHints, manual_ls: Option) -> bool { + if manual_ls.is_some() { + return true; + } + + let Some(governor) = &self.governor else { + return true; + }; + + governor + .lock() + .map(|mut governor| governor.allow(hints.latency_sensitivity)) + .unwrap_or(true) + } + /// Converts this intercept into an [`LlmRequestInterceptFn`] suitable for /// registration with [`register_llm_request_intercept`]. /// @@ -188,7 +220,9 @@ impl AdaptiveHintsIntercept { scope_depth, ); - if let Some(hints) = final_hints { + if let Some(hints) = final_hints + && this.should_inject_hints(&hints, manual_ls) + { inject_agent_hints(&mut request, &hints); } @@ -198,6 +232,32 @@ impl AdaptiveHintsIntercept { } } +struct HintGovernor { + governor: GeometricGovernor, + last_seen: Option, +} + +impl HintGovernor { + fn new(epsilon: f64) -> Self { + Self { + governor: GeometricGovernor::with_epsilon(epsilon), + last_seen: None, + } + } + + fn allow(&mut self, latency_sensitivity: f64) -> bool { + let allow = self.governor.should_trigger(latency_sensitivity); + let now = Instant::now(); + if let Some(last_seen) = self.last_seen { + let dt = now.duration_since(last_seen).as_secs_f64().max(0.000_001); + let observed_rate = 1.0 / dt; + self.governor.adapt(observed_rate, dt); + } + self.last_seen = Some(now); + allow + } +} + #[cfg(test)] #[path = "../tests/unit/adaptive_hints_intercept_tests.rs"] mod tests; diff --git a/crates/adaptive/src/config.rs b/crates/adaptive/src/config.rs index c24bc4e5..799cb955 100644 --- a/crates/adaptive/src/config.rs +++ b/crates/adaptive/src/config.rs @@ -32,6 +32,9 @@ pub struct AdaptiveConfig { /// Adaptive Cache Governor settings. #[serde(default, skip_serializing_if = "Option::is_none")] pub acg: Option, + /// Global topological convergence settings. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub convergence: Option, /// Adaptive-local unsupported-config policy. #[serde(default)] pub policy: ConfigPolicy, @@ -47,6 +50,7 @@ impl Default for AdaptiveConfig { adaptive_hints: None, tool_parallelism: None, acg: None, + convergence: None, policy: ConfigPolicy::default(), } } @@ -123,6 +127,9 @@ pub struct AdaptiveHintsComponentConfig { /// JSON path used when injecting request-body hints. #[serde(default = "default_adaptive_hints_path")] pub inject_body_path: String, + /// Optional topology-aware load-shedding governor for hint injection. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub governor: Option, } impl Default for AdaptiveHintsComponentConfig { @@ -132,6 +139,7 @@ impl Default for AdaptiveHintsComponentConfig { break_chain: false, inject_header: true, inject_body_path: default_adaptive_hints_path(), + governor: None, } } } @@ -145,6 +153,9 @@ pub struct ToolParallelismComponentConfig { /// Scheduling mode such as `observe_only`, `inject_hints`, or `schedule`. #[serde(default = "default_tool_parallelism_mode")] pub mode: String, + /// Optional topology-aware drift detector for stale plan invalidation. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub drift: Option, } impl Default for ToolParallelismComponentConfig { @@ -152,6 +163,71 @@ impl Default for ToolParallelismComponentConfig { Self { priority: default_priority(), mode: default_tool_parallelism_mode(), + drift: None, + } + } +} + +/// Typed helper for topology-aware hint load shedding. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct GovernorConfig { + /// Whether the governor is active. + #[serde(default)] + pub enabled: bool, + /// Initial sensitivity threshold used by the governor. + #[serde(default = "default_governor_epsilon")] + pub epsilon: f64, +} + +impl Default for GovernorConfig { + fn default() -> Self { + Self { + enabled: false, + epsilon: default_governor_epsilon(), + } + } +} + +/// Typed helper for topology-aware tool plan drift detection. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct DriftConfig { + /// Whether drift detection is active. + #[serde(default)] + pub enabled: bool, + /// Drift distance above which the existing execution plan is invalidated. + #[serde(default = "default_drift_threshold")] + pub threshold: f64, +} + +impl Default for DriftConfig { + fn default() -> Self { + Self { + enabled: false, + threshold: default_drift_threshold(), + } + } +} + +/// Typed helper for topological convergence detection settings. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ConvergenceConfig { + /// Whether convergence detection is active. + #[serde(default)] + pub enabled: bool, + /// Error threshold below which the detector is considered converged. + #[serde(default = "default_convergence_epsilon")] + pub epsilon: f64, + /// Minimum number of epochs required to judge Betti-number stability. + #[serde(default = "default_convergence_stability_window")] + pub stability_window: usize, +} + +impl Default for ConvergenceConfig { + fn default() -> Self { + Self { + enabled: false, + epsilon: default_convergence_epsilon(), + stability_window: default_convergence_stability_window(), } } } @@ -171,6 +247,9 @@ pub struct AcgComponentConfig { /// Stability classification thresholds used by the learner. #[serde(default)] pub stability_thresholds: crate::acg::stability::StabilityThresholds, + /// Optional component-scoped topological convergence settings. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub convergence: Option, } impl Default for AcgComponentConfig { @@ -180,6 +259,7 @@ impl Default for AcgComponentConfig { observation_window: default_acg_observation_window(), priority: default_acg_priority(), stability_thresholds: crate::acg::stability::StabilityThresholds::default(), + convergence: None, } } } @@ -216,6 +296,22 @@ fn default_acg_priority() -> i32 { 50 } +fn default_convergence_epsilon() -> f64 { + 0.001 +} + +fn default_convergence_stability_window() -> usize { + 3 +} + +fn default_governor_epsilon() -> f64 { + 1.0 +} + +fn default_drift_threshold() -> f64 { + 0.75 +} + nemo_relay::editor_config! { impl AdaptiveConfig { agent_id => { label: "fallback_agent_id", kind: String, optional: true }, @@ -254,6 +350,13 @@ nemo_relay::editor_config! { nested: AcgComponentConfig, default: AcgComponentConfig, }, + convergence => { + label: "convergence", + kind: Section, + optional: true, + nested: ConvergenceConfig, + default: ConvergenceConfig, + }, policy => { label: "policy", kind: Section, @@ -294,6 +397,13 @@ nemo_relay::editor_config! { break_chain => { label: "break_chain", kind: Boolean }, inject_header => { label: "inject_header", kind: Boolean }, inject_body_path => { label: "inject_body_path", kind: String }, + governor => { + label: "governor", + kind: Section, + optional: true, + nested: GovernorConfig, + default: GovernorConfig, + }, } } @@ -305,6 +415,27 @@ nemo_relay::editor_config! { kind: Enum, values: ["observe_only", "inject_hints", "schedule"], }, + drift => { + label: "drift", + kind: Section, + optional: true, + nested: DriftConfig, + default: DriftConfig, + }, + } +} + +nemo_relay::editor_config! { + impl GovernorConfig { + enabled => { label: "enabled", kind: Boolean }, + epsilon => { label: "epsilon", kind: Float }, + } +} + +nemo_relay::editor_config! { + impl DriftConfig { + enabled => { label: "enabled", kind: Boolean }, + threshold => { label: "threshold", kind: Float }, } } @@ -323,6 +454,21 @@ nemo_relay::editor_config! { nested: crate::acg::stability::StabilityThresholds, default: crate::acg::stability::StabilityThresholds, }, + convergence => { + label: "convergence", + kind: Section, + optional: true, + nested: ConvergenceConfig, + default: ConvergenceConfig, + }, + } +} + +nemo_relay::editor_config! { + impl ConvergenceConfig { + enabled => { label: "enabled", kind: Boolean }, + epsilon => { label: "epsilon", kind: Float }, + stability_window => { label: "stability_window", kind: Integer }, } } diff --git a/crates/adaptive/src/lib.rs b/crates/adaptive/src/lib.rs index 9843a2e5..e92d4f56 100644 --- a/crates/adaptive/src/lib.rs +++ b/crates/adaptive/src/lib.rs @@ -36,8 +36,9 @@ pub mod trie; pub mod types; pub use config::{ - AcgComponentConfig, AdaptiveConfig, AdaptiveHintsComponentConfig, BackendSpec, StateConfig, - TelemetryComponentConfig, ToolParallelismComponentConfig, + AcgComponentConfig, AdaptiveConfig, AdaptiveHintsComponentConfig, BackendSpec, + ConvergenceConfig, DriftConfig, GovernorConfig, StateConfig, TelemetryComponentConfig, + ToolParallelismComponentConfig, }; pub use context_helpers::{ LATENCY_SENSITIVITY_POINTER, extract_scope_path, read_manual_latency_sensitivity, @@ -50,3 +51,9 @@ pub use runtime::features::AdaptiveRuntime; pub use storage::erased::AnyBackend; pub use storage::memory::InMemoryBackend; pub use storage::traits::{StorageBackend, StorageBackendDyn}; + +#[cfg(test)] +pub(crate) mod test_support { + pub(crate) static GLOBAL_RUNTIME_TEST_MUTEX: tokio::sync::Mutex<()> = + tokio::sync::Mutex::const_new(()); +} diff --git a/crates/adaptive/src/plugin_component.rs b/crates/adaptive/src/plugin_component.rs index 62ccfd4b..f1d1ccdf 100644 --- a/crates/adaptive/src/plugin_component.rs +++ b/crates/adaptive/src/plugin_component.rs @@ -182,6 +182,7 @@ fn validate_adaptive_plugin_config(plugin_config: &Map) -> Vec) -> Vec) -> Vec) -> Vec, acg_config: Option, + convergence: Option, ) -> Self { let subscriber_name = config .subscriber_name .unwrap_or_else(|| format!("adaptive_{runtime_id}_subscriber")); Self { - learners: build_learners(&agent_id, &config.learners, acg_config.as_ref()), + learners: build_learners( + &agent_id, + &config.learners, + tool_parallelism_config.as_ref(), + acg_config.as_ref(), + convergence.as_ref(), + ), agent_id, subscriber_name, } @@ -597,6 +607,7 @@ struct AdaptiveHintsFeature { break_chain: bool, hot_cache: Arc>, agent_id: String, + governor: Option, } impl AdaptiveHintsFeature { @@ -612,6 +623,7 @@ impl AdaptiveHintsFeature { break_chain: config.break_chain, hot_cache, agent_id, + governor: config.governor, } } } @@ -622,8 +634,11 @@ impl AdaptiveFeature for AdaptiveHintsFeature { ctx: &'a mut RegistrationContext<'_>, ) -> Pin> + Send + 'a>> { Box::pin(async move { - let adaptive_hints = - AdaptiveHintsIntercept::new(self.hot_cache.clone(), self.agent_id.clone()); + let adaptive_hints = AdaptiveHintsIntercept::with_governor( + self.hot_cache.clone(), + self.agent_id.clone(), + self.governor.clone(), + ); ctx.register_llm_request_intercept( &self.name, self.priority, @@ -770,7 +785,9 @@ impl AdaptiveFeature for AcgFeature { fn build_learners( agent_id: &str, learners: &[String], + tool_parallelism_config: Option<&ToolParallelismComponentConfig>, acg_config: Option<&AcgComponentConfig>, + convergence: Option<&crate::config::ConvergenceConfig>, ) -> Vec> { let mut built: Vec> = vec![]; for learner in learners { @@ -779,13 +796,21 @@ fn build_learners( agent_id, crate::trie::builder::SensitivityConfig::default(), ))), - "tool_parallelism" => built.push(Box::new(ToolParallelismLearner::new(agent_id))), + "tool_parallelism" => { + let drift = tool_parallelism_config.and_then(|config| config.drift.clone()); + built.push(Box::new(ToolParallelismLearner::new_with_drift( + agent_id, drift, + ))); + } "acg" => { if let Some(config) = acg_config { - built.push(Box::new(AcgLearner::new( + let profile_convergence = + config.convergence.clone().or_else(|| convergence.cloned()); + built.push(Box::new(AcgLearner::new_with_convergence( agent_id, config.observation_window, config.stability_thresholds.clone(), + profile_convergence, ))); } } diff --git a/crates/adaptive/src/runtime/validation.rs b/crates/adaptive/src/runtime/validation.rs index 8d039379..e3c93aa6 100644 --- a/crates/adaptive/src/runtime/validation.rs +++ b/crates/adaptive/src/runtime/validation.rs @@ -62,6 +62,29 @@ pub fn validate_config(config: &AdaptiveConfig) -> ConfigReport { ), ); } + if let Some(tool_parallelism) = &config.tool_parallelism + && let Some(drift) = &tool_parallelism.drift + { + validate_positive_finite( + &mut report, + &config.policy, + "tool_parallelism.drift", + "threshold", + drift.threshold, + ); + } + + if let Some(adaptive_hints) = &config.adaptive_hints + && let Some(governor) = &adaptive_hints.governor + { + validate_positive_finite( + &mut report, + &config.policy, + "adaptive_hints.governor", + "epsilon", + governor.epsilon, + ); + } if let Some(acg) = &config.acg && acg.provider != "anthropic" @@ -80,10 +103,60 @@ pub fn validate_config(config: &AdaptiveConfig) -> ConfigReport { ), ); } + if let Some(acg) = &config.acg + && let Some(convergence) = &acg.convergence + { + validate_convergence(&mut report, &config.policy, "acg.convergence", convergence); + } + if let Some(convergence) = &config.convergence { + validate_convergence(&mut report, &config.policy, "convergence", convergence); + } report } +fn validate_convergence( + report: &mut ConfigReport, + policy: &ConfigPolicy, + component: &str, + convergence: &crate::config::ConvergenceConfig, +) { + validate_positive_finite(report, policy, component, "epsilon", convergence.epsilon); + if convergence.stability_window < 3 { + push_policy_diag( + &mut report.diagnostics, + policy.unsupported_value, + "adaptive.unsupported_value", + Some(component.to_string()), + Some("stability_window".to_string()), + format!( + "{component} stability_window must be at least 3, got {}", + convergence.stability_window + ), + ); + } +} + +fn validate_positive_finite( + report: &mut ConfigReport, + policy: &ConfigPolicy, + component: &str, + field: &str, + value: f64, +) { + if value.is_finite() && value > 0.0 { + return; + } + push_policy_diag( + &mut report.diagnostics, + policy.unsupported_value, + "adaptive.unsupported_value", + Some(component.to_string()), + Some(field.to_string()), + format!("{component} {field} must be a positive finite number, got {value}"), + ); +} + fn validate_backend(report: &mut ConfigReport, policy: &ConfigPolicy, backend: &BackendSpec) { let kind = backend.kind.as_str(); match kind { diff --git a/crates/adaptive/src/tool_parallelism_learner.rs b/crates/adaptive/src/tool_parallelism_learner.rs index f4234073..d6b80526 100644 --- a/crates/adaptive/src/tool_parallelism_learner.rs +++ b/crates/adaptive/src/tool_parallelism_learner.rs @@ -10,9 +10,11 @@ use std::sync::{Arc, RwLock}; use crate::acg::canonicalize::sha256_hex; use chrono::{DateTime, Utc}; +use nemo_relay_adaptive_topology::DriftDetector; use serde_json::json; use uuid::Uuid; +use crate::config::DriftConfig; use crate::error::{AdaptiveError, Result}; use crate::learner::traits::Learner; use crate::storage::traits::StorageBackendDyn; @@ -24,6 +26,8 @@ use crate::types::records::{CallKind, RunRecord}; /// Learner that discovers tool fan-out groups from run telemetry. pub struct ToolParallelismLearner { agent_id: String, + drift: Option, + drift_detector: Arc>>, } impl ToolParallelismLearner { @@ -35,10 +39,40 @@ impl ToolParallelismLearner { /// # Returns /// A configured [`ToolParallelismLearner`]. pub fn new(agent_id: impl Into) -> Self { + Self::new_with_drift(agent_id, None) + } + + /// Create a new tool-parallelism learner with optional drift detection. + /// + /// # Parameters + /// - `agent_id`: Agent identifier whose execution plan should be updated. + /// - `drift`: Optional topology-aware drift detection settings. + /// + /// # Returns + /// A configured [`ToolParallelismLearner`]. + pub fn new_with_drift(agent_id: impl Into, drift: Option) -> Self { Self { agent_id: agent_id.into(), + drift, + drift_detector: Arc::new(RwLock::new(DriftDetector::new())), } } + + fn record_cohort_drift(&self, observed_cohorts: &[Vec]) -> Result { + let Some(config) = &self.drift else { + return Ok(false); + }; + if !config.enabled { + return Ok(false); + } + + let centroid = cohort_feature_vector(observed_cohorts); + let mut detector = self.drift_detector.write().map_err(|error| { + AdaptiveError::Internal(format!("tool drift detector lock poisoned: {error}")) + })?; + let drift = detector.update(¢roid); + Ok(drift > config.threshold) + } } impl Learner for ToolParallelismLearner { @@ -54,10 +88,15 @@ impl Learner for ToolParallelismLearner { return Ok(()); } - let mut plan = backend - .load_plan_dyn(&self.agent_id) - .await? - .unwrap_or_else(|| empty_execution_plan(&self.agent_id, run.id)); + let drifted = self.record_cohort_drift(&observed_cohorts)?; + let mut plan = if drifted { + empty_execution_plan(&self.agent_id, run.id) + } else { + backend + .load_plan_dyn(&self.agent_id) + .await? + .unwrap_or_else(|| empty_execution_plan(&self.agent_id, run.id)) + }; plan.agent_id = self.agent_id.clone(); merge_observed_cohorts(&mut plan, &observed_cohorts, run.id); @@ -113,6 +152,32 @@ fn derive_observed_cohorts(run: &RunRecord) -> Vec> { observed } +fn cohort_feature_vector(observed_cohorts: &[Vec]) -> [f64; 4] { + if observed_cohorts.is_empty() { + return [0.0; 4]; + } + + let mut unique_tools = BTreeSet::new(); + let mut total_tool_refs = 0usize; + let mut max_cohort_size = 0usize; + + for cohort in observed_cohorts { + total_tool_refs += cohort.len(); + max_cohort_size = max_cohort_size.max(cohort.len()); + for tool in cohort { + unique_tools.insert(tool); + } + } + + let duplicate_refs = total_tool_refs.saturating_sub(unique_tools.len()); + [ + observed_cohorts.len() as f64, + unique_tools.len() as f64, + duplicate_refs as f64 / total_tool_refs.max(1) as f64, + max_cohort_size as f64, + ] +} + fn merge_observed_cohorts( plan: &mut ExecutionPlan, observed_cohorts: &[Vec], diff --git a/crates/adaptive/tests/integration/runtime_integration_tests.rs b/crates/adaptive/tests/integration/runtime_integration_tests.rs index cdee3c05..b4017e80 100644 --- a/crates/adaptive/tests/integration/runtime_integration_tests.rs +++ b/crates/adaptive/tests/integration/runtime_integration_tests.rs @@ -675,6 +675,7 @@ async fn test_adaptive_plugin_rejects_unsupported_mode_with_strict_policy() { tool_parallelism: Some(ToolParallelismComponentConfig { priority: 100, mode: "broken".into(), + drift: None, }), ..AdaptiveConfig::default() }) diff --git a/crates/adaptive/tests/integration/tool_parallelism_plan_tests.rs b/crates/adaptive/tests/integration/tool_parallelism_plan_tests.rs index 7ecfa429..968fe800 100644 --- a/crates/adaptive/tests/integration/tool_parallelism_plan_tests.rs +++ b/crates/adaptive/tests/integration/tool_parallelism_plan_tests.rs @@ -9,14 +9,13 @@ use chrono::{Duration, Utc}; use serde_json::json; use uuid::Uuid; -use nemo_relay_adaptive::{ - InMemoryBackend, StorageBackend, StorageBackendDyn, ToolParallelismLearner, -}; use nemo_relay_adaptive::learner::traits::Learner; +use nemo_relay_adaptive::tool_parallelism_learner::ToolParallelismLearner; use nemo_relay_adaptive::types::cache::HotCache; use nemo_relay_adaptive::types::metadata::{MetadataEnvelope, ParallelHint}; use nemo_relay_adaptive::types::plan::{ExecutionPlan, ParallelGroup}; use nemo_relay_adaptive::types::records::{CallKind, CallRecord, RunRecord}; +use nemo_relay_adaptive::{InMemoryBackend, StorageBackend, StorageBackendDyn}; fn make_hot_cache() -> Arc> { Arc::new(RwLock::new(HotCache { @@ -27,10 +26,6 @@ fn make_hot_cache() -> Arc> { acg_profile_observation_counts: std::collections::HashMap::new(), acg_stability: None, acg_observation_count: 0, - acg_profiles: std::collections::HashMap::new(), - acg_profile_observation_counts: std::collections::HashMap::new(), - acg_stability: None, - acg_observation_count: 0, })) } @@ -51,10 +46,6 @@ fn make_tool_call( total_tokens: None, model_name: None, tool_call_count: None, - annotated_request: None, - annotated_response: None, - annotated_request: None, - annotated_response: None, annotated_request: None, annotated_response: None, } diff --git a/crates/adaptive/tests/integration/topology_convergence_tests.rs b/crates/adaptive/tests/integration/topology_convergence_tests.rs new file mode 100644 index 00000000..6e3e1537 --- /dev/null +++ b/crates/adaptive/tests/integration/topology_convergence_tests.rs @@ -0,0 +1,181 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Integration tests for topological convergence detection in the ACG learner. + +use std::sync::{Arc, RwLock}; + +use chrono::Utc; +use nemo_relay::codec::request::{AnnotatedLlmRequest, Message, MessageContent}; +use nemo_relay_adaptive::acg::stability::StabilityThresholds; +use nemo_relay_adaptive::acg_learner::AcgLearner; +use nemo_relay_adaptive::learner::traits::Learner; +use nemo_relay_adaptive::types::cache::HotCache; +use nemo_relay_adaptive::types::records::{CallKind, CallRecord, RunRecord}; +use nemo_relay_adaptive::{ConvergenceConfig, InMemoryBackend, StorageBackendDyn}; +use uuid::Uuid; + +fn identical_request() -> AnnotatedLlmRequest { + AnnotatedLlmRequest { + messages: vec![ + Message::System { + content: MessageContent::Text("You are a helpful assistant.".to_string()), + name: None, + }, + Message::User { + content: MessageContent::Text("Summarize this.".to_string()), + name: None, + }, + ], + model: Some("gpt-4o".to_string()), + params: None, + tools: None, + tool_choice: None, + store: None, + previous_response_id: None, + truncation: None, + reasoning: None, + include: None, + user: None, + metadata: None, + service_tier: None, + parallel_tool_calls: None, + max_output_tokens: None, + max_tool_calls: None, + top_logprobs: None, + stream: None, + extra: serde_json::Map::new(), + } +} + +fn run_with_requests(requests: Vec) -> RunRecord { + let now = Utc::now(); + RunRecord { + id: Uuid::now_v7(), + agent_id: "convergence-agent".to_string(), + calls: requests + .into_iter() + .map(|request| CallRecord { + kind: CallKind::Llm, + name: "planner".to_string(), + started_at: now, + ended_at: Some(now), + metadata_snapshot: None, + output_tokens: None, + prompt_tokens: None, + total_tokens: None, + model_name: None, + tool_call_count: None, + annotated_request: Some(request.into()), + annotated_response: None, + }) + .collect(), + started_at: now, + ended_at: Some(now), + } +} + +fn empty_cache() -> Arc> { + Arc::new(RwLock::new(HotCache { + plan: None, + trie: None, + agent_hints_default: None, + acg_profiles: std::collections::HashMap::new(), + acg_profile_observation_counts: std::collections::HashMap::new(), + acg_stability: None, + acg_observation_count: 0, + })) +} + +#[tokio::test(flavor = "current_thread")] +async fn acg_learner_declares_convergence_before_window_exhausted() { + let observation_window = 20; + let stability_window = 3; + let learner = AcgLearner::new_with_convergence( + "convergence-agent", + observation_window, + StabilityThresholds::default(), + Some(ConvergenceConfig { + enabled: true, + epsilon: 0.001, + stability_window, + }), + ); + let backend = InMemoryBackend::new(); + let hot_cache = empty_cache(); + let request = identical_request(); + + let mut converged_at = None; + let mut agent_observations_at_convergence = 0; + for iteration in 0..observation_window { + let run = run_with_requests(vec![request.clone()]); + learner + .process_run(&run, &backend, &hot_cache) + .await + .unwrap(); + + let stability = backend + .load_stability("convergence-agent") + .await + .unwrap() + .expect("stability should be stored"); + if stability.converged { + converged_at = Some(iteration + 1); + agent_observations_at_convergence = backend + .load_observations("convergence-agent") + .await + .unwrap() + .map(|observations| observations.len()) + .unwrap_or(0); + break; + } + } + + assert!( + converged_at.is_some(), + "expected convergence to be declared before exhausting the observation window" + ); + assert!( + converged_at.unwrap() < observation_window, + "convergence should be declared before the observation window is exhausted" + ); + assert!( + converged_at.unwrap() >= stability_window, + "convergence should require at least stability_window epochs" + ); + + // Continue running after convergence to verify the cached result is reused + // and observations are no longer updated. + for _ in 0..3 { + let run = run_with_requests(vec![request.clone()]); + learner + .process_run(&run, &backend, &hot_cache) + .await + .unwrap(); + } + + let final_stability = backend + .load_stability("convergence-agent") + .await + .unwrap() + .expect("stability should still be stored"); + assert!( + final_stability.converged, + "cached stability result should remain converged" + ); + + let final_agent_observations = backend + .load_observations("convergence-agent") + .await + .unwrap() + .expect("agent aggregate observations should remain stored after convergence"); + assert!( + !final_agent_observations.is_empty(), + "agent aggregate observations should be non-empty after convergence" + ); + assert_eq!( + final_agent_observations.len(), + agent_observations_at_convergence, + "agent aggregate observation storage should be skipped after convergence" + ); +} diff --git a/crates/adaptive/tests/unit/acg/economics_internal_tests.rs b/crates/adaptive/tests/unit/acg/economics_internal_tests.rs index 7a6a0136..bbcc3589 100644 --- a/crates/adaptive/tests/unit/acg/economics_internal_tests.rs +++ b/crates/adaptive/tests/unit/acg/economics_internal_tests.rs @@ -122,6 +122,7 @@ fn economics_internal_build_prefix_stats_stops_at_first_non_stable_block() { ], stable_prefix_length: 2, total_observations: 6, + converged: false, }; let stats = build_prefix_stats( diff --git a/crates/adaptive/tests/unit/acg/economics_policy_tests.rs b/crates/adaptive/tests/unit/acg/economics_policy_tests.rs index 1d4a0096..d9621016 100644 --- a/crates/adaptive/tests/unit/acg/economics_policy_tests.rs +++ b/crates/adaptive/tests/unit/acg/economics_policy_tests.rs @@ -85,6 +85,7 @@ fn stability_result(scores: &[(f64, f64)], observation_count: u32) -> StabilityA .collect(), stable_prefix_length: scores.len(), total_observations: observation_count, + converged: false, } } diff --git a/crates/adaptive/tests/unit/acg/multi_breakpoint_tests.rs b/crates/adaptive/tests/unit/acg/multi_breakpoint_tests.rs index f4c22848..7597539b 100644 --- a/crates/adaptive/tests/unit/acg/multi_breakpoint_tests.rs +++ b/crates/adaptive/tests/unit/acg/multi_breakpoint_tests.rs @@ -82,6 +82,7 @@ fn layered_stability(observation_count: u32, layers: usize) -> StabilityAnalysis .collect(), stable_prefix_length: layers, total_observations: observation_count, + converged: false, } } diff --git a/crates/adaptive/tests/unit/acg_component_tests.rs b/crates/adaptive/tests/unit/acg_component_tests.rs index cc4c2f7e..1da1e225 100644 --- a/crates/adaptive/tests/unit/acg_component_tests.rs +++ b/crates/adaptive/tests/unit/acg_component_tests.rs @@ -49,6 +49,7 @@ fn sample_hot_cache() -> Arc> { ], stable_prefix_length: 2, total_observations: 8, + converged: false, }), acg_observation_count: 8, })) @@ -233,6 +234,7 @@ fn stability_with_prefix(prefix_len: u32, observations: u32) -> StabilityAnalysi .collect(), stable_prefix_length: prefix_len as usize, total_observations: observations, + converged: false, } } @@ -263,6 +265,7 @@ fn layered_stability_result(observation_count: u32) -> StabilityAnalysisResult { ], stable_prefix_length: 3, total_observations: observation_count, + converged: false, } } @@ -692,6 +695,7 @@ fn acg_component_build_intent_bundle_requires_at_least_two_observations() { ], stable_prefix_length: 2, total_observations: 1, + converged: false, }; let intent_bundle = build_intent_bundle( diff --git a/crates/adaptive/tests/unit/adaptive_hints_intercept_tests.rs b/crates/adaptive/tests/unit/adaptive_hints_intercept_tests.rs index a7efa190..bf600ad0 100644 --- a/crates/adaptive/tests/unit/adaptive_hints_intercept_tests.rs +++ b/crates/adaptive/tests/unit/adaptive_hints_intercept_tests.rs @@ -316,6 +316,74 @@ fn test_adaptive_hints_intercept_uses_defaults_and_ignores_poisoned_cache() { reset_root_metadata(); } +#[test] +fn test_adaptive_hints_governor_sheds_low_sensitivity_hints_but_keeps_manual_override() { + let _guard = test_mutex().lock().unwrap(); + reset_root_metadata(); + + let defaults = AgentHints { + osl: 9, + iat: 12, + priority: 3, + latency_sensitivity: 2.0, + prefix_id: "defaults".into(), + total_requests: 11, + }; + let hot_cache = Arc::new(RwLock::new(HotCache { + plan: None, + trie: None, + agent_hints_default: Some(defaults), + acg_profiles: std::collections::HashMap::new(), + acg_profile_observation_counts: std::collections::HashMap::new(), + acg_stability: None, + acg_observation_count: 0, + })); + let governor = GovernorConfig { + enabled: true, + epsilon: 10.0, + }; + let req_fn = AdaptiveHintsIntercept::with_governor( + hot_cache.clone(), + "fallback-agent".to_string(), + Some(governor.clone()), + ) + .into_request_fn(); + + let (request, _) = req_fn( + "model", + LlmRequest { + headers: serde_json::Map::new(), + content: serde_json::json!({}), + }, + None, + ) + .unwrap(); + assert!(request.headers.get(AGENT_HINTS_HEADER_KEY).is_none()); + + crate::context_helpers::set_latency_sensitivity(11).unwrap(); + let manual_req_fn = AdaptiveHintsIntercept::with_governor( + hot_cache, + "fallback-agent".to_string(), + Some(governor), + ) + .into_request_fn(); + let (manual_request, _) = manual_req_fn( + "model", + LlmRequest { + headers: serde_json::Map::new(), + content: serde_json::json!({}), + }, + None, + ) + .unwrap(); + assert_eq!( + manual_request.content["nvext"]["agent_hints"]["latency_sensitivity"], + serde_json::json!(11.0) + ); + + reset_root_metadata(); +} + #[test] fn test_apply_manual_latency_override_and_inject_agent_hints_cover_manual_paths() { let base_hints = AgentHints { diff --git a/crates/adaptive/tests/unit/cache_diagnostics_tests.rs b/crates/adaptive/tests/unit/cache_diagnostics_tests.rs index b46c7b84..2d2507f8 100644 --- a/crates/adaptive/tests/unit/cache_diagnostics_tests.rs +++ b/crates/adaptive/tests/unit/cache_diagnostics_tests.rs @@ -83,6 +83,7 @@ fn make_hot_cache(stable_prefix_length: Option) -> HotCache { .collect(), stable_prefix_length, total_observations: 4, + converged: false, }), acg_observation_count: 4, } diff --git a/crates/adaptive/tests/unit/config_tests.rs b/crates/adaptive/tests/unit/config_tests.rs index 22f8ed6f..a2e488ae 100644 --- a/crates/adaptive/tests/unit/config_tests.rs +++ b/crates/adaptive/tests/unit/config_tests.rs @@ -25,9 +25,19 @@ fn test_typed_section_helpers_default() { let adaptive_hints = AdaptiveHintsComponentConfig::default(); assert_eq!(adaptive_hints.priority, 100); assert!(adaptive_hints.inject_header); + assert!(adaptive_hints.governor.is_none()); let tool_parallelism = ToolParallelismComponentConfig::default(); assert_eq!(tool_parallelism.mode, "observe_only"); + assert!(tool_parallelism.drift.is_none()); + + let governor = GovernorConfig::default(); + assert!(!governor.enabled); + assert_eq!(governor.epsilon, 1.0); + + let drift = DriftConfig::default(); + assert!(!drift.enabled); + assert_eq!(drift.threshold, 0.75); } #[test] @@ -66,11 +76,29 @@ fn test_component_configs_deserialize_with_default_helpers() { assert!(!adaptive_hints.break_chain); assert!(adaptive_hints.inject_header); assert_eq!(adaptive_hints.inject_body_path, "nvext.agent_hints"); + assert!(adaptive_hints.governor.is_none()); let tool_parallelism: ToolParallelismComponentConfig = serde_json::from_value(json!({})).unwrap(); assert_eq!(tool_parallelism.priority, 100); assert_eq!(tool_parallelism.mode, "observe_only"); + assert!(tool_parallelism.drift.is_none()); + + let adaptive_hints: AdaptiveHintsComponentConfig = serde_json::from_value(json!({ + "governor": {"enabled": true} + })) + .unwrap(); + let governor = adaptive_hints.governor.unwrap(); + assert!(governor.enabled); + assert_eq!(governor.epsilon, 1.0); + + let tool_parallelism: ToolParallelismComponentConfig = serde_json::from_value(json!({ + "drift": {"enabled": true} + })) + .unwrap(); + let drift = tool_parallelism.drift.unwrap(); + assert!(drift.enabled); + assert_eq!(drift.threshold, 0.75); } #[test] @@ -90,6 +118,7 @@ fn test_adaptive_editor_schema_covers_canonical_options() { "adaptive_hints", "tool_parallelism", "acg", + "convergence", "policy", ] ); @@ -105,6 +134,20 @@ fn test_adaptive_editor_schema_covers_canonical_options() { EditorFieldKind::Json ); + let adaptive_hints = schema.field("adaptive_hints").unwrap().schema().unwrap(); + let governor = adaptive_hints.field("governor").unwrap().schema().unwrap(); + assert_eq!( + governor.field("epsilon").unwrap().kind, + EditorFieldKind::Float + ); + + let tool_parallelism = schema.field("tool_parallelism").unwrap().schema().unwrap(); + let drift = tool_parallelism.field("drift").unwrap().schema().unwrap(); + assert_eq!( + drift.field("threshold").unwrap().kind, + EditorFieldKind::Float + ); + let acg = schema.field("acg").unwrap().schema().unwrap(); let thresholds = acg.field("stability_thresholds").unwrap().schema().unwrap(); assert_eq!( diff --git a/crates/adaptive/tests/unit/intercepts_tests.rs b/crates/adaptive/tests/unit/intercepts_tests.rs index 98fd1641..90e77fe3 100644 --- a/crates/adaptive/tests/unit/intercepts_tests.rs +++ b/crates/adaptive/tests/unit/intercepts_tests.rs @@ -51,6 +51,7 @@ fn make_hot_cache( scores: vec![], stable_prefix_length, total_observations: observation_count, + converged: false, }), acg_observation_count: observation_count, })) diff --git a/crates/adaptive/tests/unit/plugin_component_tests.rs b/crates/adaptive/tests/unit/plugin_component_tests.rs index 03fe3f00..1d840831 100644 --- a/crates/adaptive/tests/unit/plugin_component_tests.rs +++ b/crates/adaptive/tests/unit/plugin_component_tests.rs @@ -14,10 +14,10 @@ use nemo_relay::api::runtime::global_context; use nemo_relay::plugin::{DiagnosticLevel, UnsupportedBehavior, clear_plugin_configuration}; use nemo_relay::plugin::{Plugin, PluginRegistrationContext, rollback_registrations}; use serde_json::json; -use tokio::sync::Mutex as AsyncMutex; + +use crate::test_support::GLOBAL_RUNTIME_TEST_MUTEX; static TEST_MUTEX: OnceLock> = OnceLock::new(); -static ASYNC_TEST_MUTEX: AsyncMutex<()> = AsyncMutex::const_new(()); fn test_mutex() -> &'static Mutex<()> { TEST_MUTEX.get_or_init(|| Mutex::new(())) @@ -92,6 +92,7 @@ fn validate_adaptive_plugin_config_reports_unknown_fields_and_backend_errors() { #[test] fn register_adaptive_component_is_idempotent_and_deregisters_cleanly() { let _guard = test_mutex().lock().unwrap(); + let _runtime_guard = GLOBAL_RUNTIME_TEST_MUTEX.blocking_lock(); let _ = clear_plugin_configuration(); let _ = deregister_adaptive_component(); @@ -349,9 +350,40 @@ fn validate_adaptive_plugin_config_reports_component_specific_unknown_fields() { })); } +#[test] +fn validate_adaptive_plugin_config_accepts_topology_sections() { + let config = json!({ + "version": 1, + "adaptive_hints": { + "governor": {"enabled": true, "epsilon": 2.0} + }, + "tool_parallelism": { + "mode": "observe_only", + "drift": {"enabled": true, "threshold": 0.5} + }, + "acg": { + "provider": "anthropic", + "convergence": {"enabled": true, "epsilon": 0.01, "stability_window": 3} + }, + "convergence": {"enabled": true, "epsilon": 0.01, "stability_window": 3}, + "policy": { + "unknown_field": "error", + "unsupported_value": "error" + } + }); + + let diagnostics = validate_adaptive_plugin_config(config.as_object().unwrap()); + assert!( + diagnostics + .iter() + .all(|diag| diag.code != "adaptive.unknown_field"), + "topology config fields should not be reported as unknown: {diagnostics:?}" + ); +} + #[tokio::test(flavor = "current_thread")] async fn adaptive_plugin_registers_runtime_and_rolls_back_registration() { - let _guard = ASYNC_TEST_MUTEX.lock().await; + let _guard = GLOBAL_RUNTIME_TEST_MUTEX.lock().await; reset_global(); let plugin = AdaptivePlugin; diff --git a/crates/adaptive/tests/unit/runtime_features_tests.rs b/crates/adaptive/tests/unit/runtime_features_tests.rs index c6481860..6bca174e 100644 --- a/crates/adaptive/tests/unit/runtime_features_tests.rs +++ b/crates/adaptive/tests/unit/runtime_features_tests.rs @@ -7,6 +7,17 @@ use super::*; use std::sync::Arc; +use crate::acg::profile::{BlockStabilityScore, StabilityClass}; +use crate::acg::prompt_ir::SpanId; +use crate::acg::stability::StabilityAnalysisResult; +use crate::config::{BackendSpec, StateConfig}; +use crate::intercepts::AGENT_HINTS_HEADER_KEY; +use crate::test_support::GLOBAL_RUNTIME_TEST_MUTEX; +use crate::trie::accumulator::AccumulatorState; +use crate::trie::serialization::TrieEnvelope; +use crate::types::metadata::{AgentHints, MetadataEnvelope, ParallelHint}; +use crate::types::plan::{ExecutionPlan, ParallelGroup}; +use crate::types::records::RunRecord; use nemo_relay::api::llm::{ LlmCallExecuteParams, LlmRequest, LlmStreamCallExecuteParams, llm_call_execute, llm_request_intercepts, llm_stream_call_execute, @@ -28,22 +39,8 @@ use nemo_relay::error::FlowError; use nemo_relay::plugin::{ConfigPolicy, DiagnosticLevel, UnsupportedBehavior}; use nemo_relay::plugin::{clear_plugin_configuration, rollback_registrations}; use serde_json::json; -use tokio::sync::Mutex; - -use crate::acg::profile::{BlockStabilityScore, StabilityClass}; -use crate::acg::prompt_ir::SpanId; -use crate::acg::stability::StabilityAnalysisResult; -use crate::config::{BackendSpec, StateConfig}; -use crate::intercepts::AGENT_HINTS_HEADER_KEY; -use crate::trie::accumulator::AccumulatorState; -use crate::trie::serialization::TrieEnvelope; -use crate::types::metadata::{AgentHints, MetadataEnvelope, ParallelHint}; -use crate::types::plan::{ExecutionPlan, ParallelGroup}; -use crate::types::records::RunRecord; use tokio_stream::StreamExt; -static TEST_MUTEX: Mutex<()> = Mutex::const_new(()); - fn reset_global() { let _ = clear_plugin_configuration(); let ctx = global_context(); @@ -116,6 +113,7 @@ fn layered_acg_stability_result(observation_count: u32) -> StabilityAnalysisResu ], stable_prefix_length: 3, total_observations: observation_count, + converged: false, } } @@ -288,6 +286,8 @@ fn build_learners_filters_unknown_entries() { "agent-a", &["latency_sensitivity".to_string(), "unknown".to_string()], None, + None, + None, ); assert_eq!(learners.len(), 1); } @@ -427,7 +427,7 @@ async fn adaptive_runtime_new_rejects_invalid_configs_with_joined_errors() { #[tokio::test(flavor = "current_thread")] async fn registration_context_take_event_receiver_only_allows_one_consumer() { - let _lock = TEST_MUTEX.lock().await; + let _lock = GLOBAL_RUNTIME_TEST_MUTEX.lock().await; reset_global(); let mut runtime = AdaptiveRuntime::new(AdaptiveConfig::default()) @@ -444,7 +444,7 @@ async fn registration_context_take_event_receiver_only_allows_one_consumer() { #[tokio::test(flavor = "current_thread")] async fn telemetry_feature_registers_subscriber_and_starts_drain_task() { - let _lock = TEST_MUTEX.lock().await; + let _lock = GLOBAL_RUNTIME_TEST_MUTEX.lock().await; reset_global(); let mut runtime = AdaptiveRuntime::new(AdaptiveConfig { @@ -463,6 +463,8 @@ async fn telemetry_feature_registers_subscriber_and_starts_drain_task() { "agent-telemetry".into(), Uuid::now_v7(), None, + None, + None, ); let name = feature.subscriber_name.clone(); @@ -484,7 +486,7 @@ async fn telemetry_feature_registers_subscriber_and_starts_drain_task() { #[tokio::test(flavor = "current_thread")] async fn telemetry_feature_requires_backend() { - let _lock = TEST_MUTEX.lock().await; + let _lock = GLOBAL_RUNTIME_TEST_MUTEX.lock().await; reset_global(); let mut runtime = AdaptiveRuntime::new(AdaptiveConfig::default()) @@ -495,6 +497,8 @@ async fn telemetry_feature_requires_backend() { "agent-telemetry".into(), Uuid::now_v7(), None, + None, + None, ); let mut ctx = RegistrationContext::new(&mut runtime); @@ -506,7 +510,7 @@ async fn telemetry_feature_requires_backend() { #[tokio::test(flavor = "current_thread")] async fn adaptive_hints_feature_registers_request_intercept() { - let _lock = TEST_MUTEX.lock().await; + let _lock = GLOBAL_RUNTIME_TEST_MUTEX.lock().await; reset_global(); let mut runtime = AdaptiveRuntime::new(AdaptiveConfig::default()) @@ -562,7 +566,7 @@ async fn adaptive_hints_feature_registers_request_intercept() { #[tokio::test(flavor = "current_thread")] async fn tool_parallelism_feature_registers_execution_intercept() { - let _lock = TEST_MUTEX.lock().await; + let _lock = GLOBAL_RUNTIME_TEST_MUTEX.lock().await; reset_global(); let mut runtime = AdaptiveRuntime::new(AdaptiveConfig::default()) @@ -611,7 +615,7 @@ async fn tool_parallelism_feature_registers_execution_intercept() { #[tokio::test(flavor = "current_thread")] async fn adaptive_runtime_register_survives_hot_cache_seed_failures() { - let _lock = TEST_MUTEX.lock().await; + let _lock = GLOBAL_RUNTIME_TEST_MUTEX.lock().await; reset_global(); let config = AdaptiveConfig { @@ -653,7 +657,7 @@ async fn adaptive_runtime_register_survives_hot_cache_seed_failures() { #[tokio::test(flavor = "current_thread")] async fn adaptive_runtime_register_is_idempotent_for_active_features() { - let _lock = TEST_MUTEX.lock().await; + let _lock = GLOBAL_RUNTIME_TEST_MUTEX.lock().await; reset_global(); let mut runtime = AdaptiveRuntime::new(AdaptiveConfig { @@ -678,7 +682,7 @@ async fn adaptive_runtime_register_is_idempotent_for_active_features() { #[tokio::test(flavor = "current_thread")] async fn adaptive_runtime_register_rolls_back_when_telemetry_receiver_is_missing() { - let _lock = TEST_MUTEX.lock().await; + let _lock = GLOBAL_RUNTIME_TEST_MUTEX.lock().await; reset_global(); let mut runtime = AdaptiveRuntime::new(AdaptiveConfig { @@ -702,7 +706,7 @@ async fn adaptive_runtime_register_rolls_back_when_telemetry_receiver_is_missing #[tokio::test(flavor = "current_thread")] async fn registration_context_registers_all_supported_callback_types() { - let _lock = TEST_MUTEX.lock().await; + let _lock = GLOBAL_RUNTIME_TEST_MUTEX.lock().await; reset_global(); let mut runtime = AdaptiveRuntime::new(AdaptiveConfig::default()) @@ -781,7 +785,9 @@ async fn adaptive_runtime_helper_methods_cover_report_wait_for_idle_and_feature_ build_learners( "agent-a", &["tool_parallelism".to_string(), "acg".to_string()], + config.tool_parallelism.as_ref(), config.acg.as_ref(), + config.convergence.as_ref(), ) .len(), 2 @@ -811,7 +817,7 @@ async fn adaptive_runtime_helper_methods_cover_report_wait_for_idle_and_feature_ #[tokio::test(flavor = "current_thread")] async fn acg_feature_registers_execution_and_stream_intercepts() { - let _lock = TEST_MUTEX.lock().await; + let _lock = GLOBAL_RUNTIME_TEST_MUTEX.lock().await; reset_global(); let mut runtime = AdaptiveRuntime::new(AdaptiveConfig::default()) @@ -918,7 +924,7 @@ async fn acg_feature_registers_execution_and_stream_intercepts() { #[tokio::test(flavor = "current_thread")] async fn adaptive_runtime_register_feature_rolls_back_partial_registrations_and_abort_handle() { - let _lock = TEST_MUTEX.lock().await; + let _lock = GLOBAL_RUNTIME_TEST_MUTEX.lock().await; reset_global(); let mut runtime = AdaptiveRuntime::new(AdaptiveConfig::default()) diff --git a/crates/adaptive/tests/unit/runtime_tests.rs b/crates/adaptive/tests/unit/runtime_tests.rs index 5802a58a..628ac914 100644 --- a/crates/adaptive/tests/unit/runtime_tests.rs +++ b/crates/adaptive/tests/unit/runtime_tests.rs @@ -11,13 +11,15 @@ use nemo_relay::api::scope::{PopScopeParams, PushScopeParams, ScopeType, pop_sco use serde_json::{Map, Value as Json}; use crate::config::{ - AcgComponentConfig, AdaptiveConfig, BackendSpec, StateConfig, TelemetryComponentConfig, + AcgComponentConfig, AdaptiveConfig, AdaptiveHintsComponentConfig, BackendSpec, + ConvergenceConfig, DriftConfig, GovernorConfig, StateConfig, TelemetryComponentConfig, ToolParallelismComponentConfig, }; use crate::error::AdaptiveError; use crate::runtime::backend::build_backend; use crate::runtime::features::AdaptiveRuntime; use crate::runtime::validation::validate_config; +use crate::test_support::GLOBAL_RUNTIME_TEST_MUTEX; use nemo_relay::codec::request::{AnnotatedLlmRequest, Message, MessageContent}; use nemo_relay::plugin::{ConfigPolicy, UnsupportedBehavior}; @@ -317,6 +319,61 @@ fn validate_config_reports_unknown_backend_and_acg_provider_per_policy() { assert!(ignore_report.diagnostics.is_empty()); } +#[test] +fn validate_config_reports_invalid_topology_numeric_fields() { + let report = validate_config(&AdaptiveConfig { + adaptive_hints: Some(AdaptiveHintsComponentConfig { + governor: Some(GovernorConfig { + enabled: true, + epsilon: f64::NAN, + }), + ..AdaptiveHintsComponentConfig::default() + }), + tool_parallelism: Some(ToolParallelismComponentConfig { + drift: Some(DriftConfig { + enabled: true, + threshold: 0.0, + }), + ..ToolParallelismComponentConfig::default() + }), + acg: Some(AcgComponentConfig { + convergence: Some(ConvergenceConfig { + enabled: true, + epsilon: -1.0, + stability_window: 2, + }), + ..AcgComponentConfig::default() + }), + convergence: Some(ConvergenceConfig { + enabled: true, + epsilon: f64::INFINITY, + stability_window: 0, + }), + policy: ConfigPolicy { + unsupported_value: UnsupportedBehavior::Error, + ..ConfigPolicy::default() + }, + ..AdaptiveConfig::default() + }); + + assert!(report.has_errors()); + for component in [ + "adaptive_hints.governor", + "tool_parallelism.drift", + "acg.convergence", + "convergence", + ] { + assert!( + report + .diagnostics + .iter() + .any(|diag| diag.code == "adaptive.unsupported_value" + && diag.component.as_deref() == Some(component)), + "expected unsupported value diagnostic for {component}" + ); + } +} + #[tokio::test(flavor = "current_thread")] async fn adaptive_runtime_new_accepts_valid_in_memory_configuration() { let runtime = AdaptiveRuntime::new(AdaptiveConfig { @@ -581,6 +638,7 @@ async fn adaptive_runtime_build_cache_request_facts_keeps_missing_stability_sema #[tokio::test(flavor = "current_thread")] async fn adaptive_runtime_bind_scope_requires_registration_and_passes_through_without_state() { + let _guard = GLOBAL_RUNTIME_TEST_MUTEX.lock().await; reset_runtime_context(); let mut runtime = AdaptiveRuntime::new(AdaptiveConfig { agent_id: Some("agent-1".to_string()), diff --git a/crates/adaptive/tests/unit/storage_memory_internal_tests.rs b/crates/adaptive/tests/unit/storage_memory_internal_tests.rs index 311f007d..aa4373b1 100644 --- a/crates/adaptive/tests/unit/storage_memory_internal_tests.rs +++ b/crates/adaptive/tests/unit/storage_memory_internal_tests.rs @@ -85,6 +85,7 @@ fn sample_stability_record() -> StabilityAnalysisResult { }], stable_prefix_length: 1, total_observations: 1, + converged: false, } } diff --git a/crates/adaptive/tests/unit/storage_tests.rs b/crates/adaptive/tests/unit/storage_tests.rs index 955dc8c7..6e611b9a 100644 --- a/crates/adaptive/tests/unit/storage_tests.rs +++ b/crates/adaptive/tests/unit/storage_tests.rs @@ -90,6 +90,7 @@ fn sample_stability(agent_id: &str) -> StabilityAnalysisResult { }], stable_prefix_length: 1, total_observations: 3, + converged: false, } } diff --git a/crates/adaptive/tests/unit/tool_parallelism_learner_tests.rs b/crates/adaptive/tests/unit/tool_parallelism_learner_tests.rs index 5d28bacc..0aac5cd3 100644 --- a/crates/adaptive/tests/unit/tool_parallelism_learner_tests.rs +++ b/crates/adaptive/tests/unit/tool_parallelism_learner_tests.rs @@ -10,6 +10,7 @@ use serde_json::json; use uuid::Uuid; use super::*; +use crate::config::DriftConfig; use crate::storage::memory::InMemoryBackend; use crate::storage::traits::StorageBackend; use crate::types::cache::HotCache; @@ -299,6 +300,64 @@ async fn process_run_merges_new_cohorts_into_existing_plan() { ); } +#[tokio::test] +async fn process_run_invalidates_existing_plan_when_tool_cohort_topology_drifts() { + let backend = InMemoryBackend::new(); + let hot_cache = make_hot_cache(); + let learner = ToolParallelismLearner::new_with_drift( + "agent-drift", + Some(DriftConfig { + enabled: true, + threshold: 0.01, + }), + ); + let base = Utc::now(); + let first_run = make_run( + "agent-drift", + vec![ + make_tool_call("search", base, 0, Some(90)), + make_tool_call("fetch", base, 10, Some(100)), + ], + ); + let drifted_run = make_run( + "agent-drift", + vec![ + make_tool_call("compile", base, 0, Some(120)), + make_tool_call("test", base, 10, Some(130)), + make_tool_call("lint", base, 20, Some(140)), + ], + ); + + backend + .store_plan(&make_existing_plan("agent-drift")) + .unwrap(); + learner + .process_run(&first_run, &backend, &hot_cache) + .await + .unwrap(); + learner + .process_run(&drifted_run, &backend, &hot_cache) + .await + .unwrap(); + + let plan = backend.load_plan("agent-drift").await.unwrap().unwrap(); + assert!( + !plan + .parallel_groups + .iter() + .any(|group| group.group_id == "fanout:existing"), + "drifted cohort topology should invalidate stale plan groups" + ); + assert!(plan.parallel_groups.iter().any(|group| { + group.tool_names + == vec![ + "compile".to_string(), + "lint".to_string(), + "test".to_string(), + ] + })); +} + #[tokio::test] async fn process_run_reports_hot_cache_lock_poisoning() { let backend = InMemoryBackend::new(); diff --git a/crates/adaptive/tests/unit/types_tests.rs b/crates/adaptive/tests/unit/types_tests.rs index c31b0c58..8ec38bad 100644 --- a/crates/adaptive/tests/unit/types_tests.rs +++ b/crates/adaptive/tests/unit/types_tests.rs @@ -42,6 +42,7 @@ fn sample_stability_result() -> StabilityAnalysisResult { }], stable_prefix_length: 1, total_observations: 4, + converged: false, } } diff --git a/crates/node/adaptive.d.ts b/crates/node/adaptive.d.ts index a2ad4d30..4817719b 100644 --- a/crates/node/adaptive.d.ts +++ b/crates/node/adaptive.d.ts @@ -29,12 +29,33 @@ export interface AdaptiveHintsConfig { break_chain?: boolean; inject_header?: boolean; inject_body_path?: string; + governor?: GovernorConfig; } /** Built-in adaptive tool scheduling settings. */ export interface ToolParallelismConfig { priority?: number; mode?: 'observe_only' | 'inject_hints' | 'schedule' | string; + drift?: DriftConfig; +} + +/** Topology-aware hint load-shedding settings. */ +export interface GovernorConfig { + enabled?: boolean; + epsilon?: number; +} + +/** Topology-aware tool-plan drift detection settings. */ +export interface DriftConfig { + enabled?: boolean; + threshold?: number; +} + +/** Topological convergence detector settings. */ +export interface ConvergenceConfig { + enabled?: boolean; + epsilon?: number; + stability_window?: number; } /** ACG prompt-stability classification thresholds. */ @@ -50,6 +71,7 @@ export interface AcgConfig { observation_window?: number; priority?: number; stability_thresholds?: AcgStabilityThresholds; + convergence?: ConvergenceConfig; } /** Canonical config object for the top-level adaptive component. */ @@ -61,6 +83,7 @@ export interface Config { adaptive_hints?: AdaptiveHintsConfig; tool_parallelism?: ToolParallelismConfig; acg?: AcgConfig; + convergence?: ConvergenceConfig; policy?: ConfigPolicy; } @@ -208,6 +231,12 @@ export declare function redisBackend(url: string, keyPrefix?: string): BackendSp * append learner names without checking for initialization first. */ export declare function telemetryConfig(config?: TelemetryConfig): TelemetryConfig; +/** Create topology-aware hint load-shedding settings with defaults applied. */ +export declare function governorConfig(config?: GovernorConfig): GovernorConfig; +/** Create topology-aware tool-plan drift detection settings with defaults applied. */ +export declare function driftConfig(config?: DriftConfig): DriftConfig; +/** Create topological convergence detector settings with defaults applied. */ +export declare function convergenceConfig(config?: ConvergenceConfig): ConvergenceConfig; /** * Create adaptive hint-injection settings with defaults applied. * diff --git a/crates/node/adaptive.js b/crates/node/adaptive.js index 8392f46a..5bc5e205 100644 --- a/crates/node/adaptive.js +++ b/crates/node/adaptive.js @@ -80,6 +80,49 @@ function telemetryConfig(config = {}) { }; } +/** + * Create topology-aware hint load-shedding settings with defaults applied. + * + * @param {object} [config={}] - Partial governor settings to override. + * @returns {object} A normalized governor config object. + */ +function governorConfig(config = {}) { + return { + enabled: false, + epsilon: 1.0, + ...config, + }; +} + +/** + * Create topology-aware tool-plan drift detection settings with defaults applied. + * + * @param {object} [config={}] - Partial drift settings to override. + * @returns {object} A normalized drift config object. + */ +function driftConfig(config = {}) { + return { + enabled: false, + threshold: 0.75, + ...config, + }; +} + +/** + * Create topological convergence detector settings with defaults applied. + * + * @param {object} [config={}] - Partial convergence settings to override. + * @returns {object} A normalized convergence config object. + */ +function convergenceConfig(config = {}) { + return { + enabled: false, + epsilon: 0.001, + stability_window: 3, + ...config, + }; +} + /** * Create adaptive hint-injection settings with defaults applied. * @@ -202,6 +245,9 @@ module.exports = { inMemoryBackend, redisBackend, telemetryConfig, + governorConfig, + driftConfig, + convergenceConfig, adaptiveHintsConfig, toolParallelismConfig, acgConfig, diff --git a/crates/node/tests/adaptive_tests.mjs b/crates/node/tests/adaptive_tests.mjs index 540590fa..44d10055 100644 --- a/crates/node/tests/adaptive_tests.mjs +++ b/crates/node/tests/adaptive_tests.mjs @@ -203,4 +203,36 @@ describe('adaptive helpers', () => { }, ); }); + + it('builds topology-aware adaptive config helpers', () => { + assert.deepEqual(adaptive.governorConfig({ enabled: true }), { + enabled: true, + epsilon: 1.0, + }); + assert.deepEqual(adaptive.driftConfig({ enabled: true }), { + enabled: true, + threshold: 0.75, + }); + assert.deepEqual(adaptive.convergenceConfig({ enabled: true }), { + enabled: true, + epsilon: 0.001, + stability_window: 3, + }); + + const config = adaptive.defaultConfig(); + config.state = { backend: adaptive.inMemoryBackend() }; + config.adaptive_hints = adaptive.adaptiveHintsConfig({ + governor: adaptive.governorConfig({ enabled: true }), + }); + config.tool_parallelism = adaptive.toolParallelismConfig({ + drift: adaptive.driftConfig({ enabled: true }), + }); + config.acg = adaptive.acgConfig({ + provider: 'anthropic', + convergence: adaptive.convergenceConfig({ enabled: true }), + }); + config.convergence = adaptive.convergenceConfig({ enabled: true }); + + assert.equal(adaptive.validateConfig(config).diagnostics.length, 0); + }); }); diff --git a/crates/python/Cargo.toml b/crates/python/Cargo.toml index 1b7655c6..4f85ecdb 100644 --- a/crates/python/Cargo.toml +++ b/crates/python/Cargo.toml @@ -20,6 +20,7 @@ crate-type = ["cdylib", "rlib"] [dependencies] nemo-relay = { workspace = true, features = ["atof-streaming", "otel", "openinference"] } nemo-relay-adaptive = { workspace = true, features = ["redis-backend"] } +nemo-relay-adaptive-topology = { workspace = true, features = ["std", "serde"] } nemo-relay-pii-redaction.workspace = true pyo3 = { version = "0.28.2", features = ["abi3", "abi3-py311", "experimental-inspect", "macros"] } pyo3-async-runtimes = { version = "0.28.0", features = ["tokio-runtime"] } diff --git a/crates/python/src/lib.rs b/crates/python/src/lib.rs index ca103568..97a076d2 100644 --- a/crates/python/src/lib.rs +++ b/crates/python/src/lib.rs @@ -30,6 +30,8 @@ mod convert; #[doc(hidden)] pub mod py_adaptive; #[doc(hidden)] +pub mod py_adaptive_topology; +#[doc(hidden)] pub mod py_api; mod py_callable; mod py_context; @@ -63,6 +65,7 @@ fn _native(m: &Bound<'_, PyModule>) -> PyResult<()> { py_api::register(m)?; py_plugin::register(m)?; py_adaptive::register(m)?; + py_adaptive_topology::register(m)?; Ok(()) } diff --git a/crates/python/src/py_adaptive_topology.rs b/crates/python/src/py_adaptive_topology.rs new file mode 100644 index 00000000..cd5190c8 --- /dev/null +++ b/crates/python/src/py_adaptive_topology.rs @@ -0,0 +1,218 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Python-facing bindings for adaptive topology primitives. + +use nemo_relay_adaptive_topology::{ + BettiNumbers, ConvergenceDetector, DriftDetector, GeometricGovernor, +}; +use pyo3::prelude::*; +use pyo3::types::PyModule; + +/// Python wrapper for [`GeometricGovernor`]. +#[pyclass(name = "GeometricGovernor")] +pub struct PyGeometricGovernor { + inner: GeometricGovernor, +} + +#[pymethods] +impl PyGeometricGovernor { + /// Create a new governor with the default threshold and gains. + #[new] + #[pyo3(text_signature = "()")] + fn new() -> Self { + Self { + inner: GeometricGovernor::new(), + } + } + + /// Create a governor with a custom initial threshold. + #[staticmethod] + #[pyo3(text_signature = "(epsilon)")] + fn with_epsilon(epsilon: f64) -> Self { + Self { + inner: GeometricGovernor::with_epsilon(epsilon), + } + } + + /// Adapt epsilon based on the observed deviation over `dt` seconds. + #[pyo3(text_signature = "(deviation_delta, dt)")] + fn adapt(&mut self, deviation_delta: f64, dt: f64) -> f64 { + self.inner.adapt(deviation_delta, dt) + } + + /// Return true if `deviation` meets or exceeds the current threshold. + #[pyo3(text_signature = "(deviation)")] + fn should_trigger(&self, deviation: f64) -> bool { + self.inner.should_trigger(deviation) + } + + /// Return the current epsilon value. + #[getter] + fn epsilon(&self) -> f64 { + self.inner.epsilon() + } + + /// Return the number of adaptations performed so far. + #[getter] + fn adjustment_count(&self) -> u64 { + self.inner.adjustment_count() + } + + /// Return the error from the most recent adaptation. + #[getter] + fn last_error(&self) -> f64 { + self.inner.last_error() + } + + /// Reset the governor to its initial state. + #[pyo3(text_signature = "()")] + fn reset(&mut self) { + self.inner.reset(); + } + + /// Return a debug representation of the governor. + fn __repr__(&self) -> String { + format!( + "GeometricGovernor(epsilon={}, adjustment_count={})", + self.inner.epsilon(), + self.inner.adjustment_count() + ) + } +} + +/// Python wrapper for [`ConvergenceDetector`]. +#[pyclass(name = "ConvergenceDetector")] +pub struct PyConvergenceDetector { + inner: ConvergenceDetector, +} + +#[pymethods] +impl PyConvergenceDetector { + /// Create a new detector. + /// + /// `epsilon` is the error threshold. `stability_window` is the minimum + /// number of epochs required to judge stability. + #[new] + #[pyo3(text_signature = "(epsilon, stability_window)")] + fn new(epsilon: f64, stability_window: usize) -> Self { + Self { + inner: ConvergenceDetector::new(epsilon, stability_window), + } + } + + /// Record an epoch's metrics. + #[pyo3(text_signature = "(beta_0, beta_1, drift, error)")] + fn record_epoch(&mut self, beta_0: u32, beta_1: u32, drift: f64, error: f64) { + self.inner + .record_epoch(BettiNumbers::new(beta_0, beta_1), drift, error); + } + + /// Return true if convergence criteria are satisfied. + #[getter] + fn is_converged(&self) -> bool { + self.inner.is_converged() + } + + /// Return a score in `[0, 1]` indicating how close to converged the + /// detector is, where `1.0` means fully converged. + #[getter] + fn convergence_score(&self) -> f64 { + self.inner.convergence_score() + } + + /// Return the number of epochs recorded. + #[getter] + fn epoch(&self) -> u32 { + self.inner.epoch() + } + + /// Return the most recent Betti numbers as ``(beta_0, beta_1)``, or ``None``. + #[getter] + fn last_betti(&self) -> Option<(u32, u32)> { + self.inner.last_betti().map(|b| (b.beta_0, b.beta_1)) + } + + /// Return the most recent error, or ``None``. + #[getter] + fn last_error(&self) -> Option { + self.inner.last_error() + } + + /// Reset the detector to its initial state. + #[pyo3(text_signature = "()")] + fn reset(&mut self) { + self.inner.reset(); + } + + /// Return a debug representation of the detector. + fn __repr__(&self) -> String { + format!( + "ConvergenceDetector(epoch={}, is_converged={})", + self.inner.epoch(), + if self.inner.is_converged() { + "True" + } else { + "False" + } + ) + } +} + +/// Python wrapper for a 3-dimensional [`DriftDetector`]. +#[pyclass(name = "DriftDetector")] +pub struct PyDriftDetector { + inner: DriftDetector<3>, +} + +#[pymethods] +impl PyDriftDetector { + /// Create a new detector with no previous observation and zero velocity. + #[new] + #[pyo3(text_signature = "()")] + fn new() -> Self { + Self { + inner: DriftDetector::new(), + } + } + + /// Record a new centroid and return the drift from the predicted position. + #[pyo3(text_signature = "(centroid)")] + fn update(&mut self, centroid: [f64; 3]) -> f64 { + self.inner.update(¢roid) + } + + /// Return true if the current velocity magnitude exceeds `threshold`. + #[pyo3(text_signature = "(threshold)")] + fn is_drifting(&self, threshold: f64) -> bool { + self.inner.is_drifting(threshold) + } + + /// Return the magnitude of the current velocity vector. + #[pyo3(text_signature = "()")] + fn velocity_magnitude(&self) -> f64 { + self.inner.velocity_magnitude() + } + + /// Reset the detector to its initial state. + #[pyo3(text_signature = "()")] + fn reset(&mut self) { + self.inner.reset(); + } + + /// Return a debug representation of the detector. + fn __repr__(&self) -> String { + format!( + "DriftDetector(velocity_magnitude={})", + self.inner.velocity_magnitude() + ) + } +} + +/// Register the adaptive topology classes in the `_native` module. +pub fn register(m: &Bound<'_, PyModule>) -> PyResult<()> { + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + Ok(()) +} diff --git a/crates/python/tests/coverage/py_storage_coverage_tests.rs b/crates/python/tests/coverage/py_storage_coverage_tests.rs index 0661dcf9..beac7ae2 100644 --- a/crates/python/tests/coverage/py_storage_coverage_tests.rs +++ b/crates/python/tests/coverage/py_storage_coverage_tests.rs @@ -141,6 +141,7 @@ fn sample_stability_result() -> StabilityAnalysisResult { }], stable_prefix_length: 1, total_observations: 2, + converged: false, } } diff --git a/docs/adaptive-plugin/about.mdx b/docs/adaptive-plugin/about.mdx index b053c8dc..c1bf9a9c 100644 --- a/docs/adaptive-plugin/about.mdx +++ b/docs/adaptive-plugin/about.mdx @@ -22,6 +22,7 @@ The plugin can coordinate: - Adaptive hints injected into outgoing model requests. - Tool-parallelism observation or scheduling behavior. - Adaptive Cache Governor (ACG) prompt-cache planning. +- Topology-aware convergence, drift, and hint load-shedding controls. - Component-local validation policy. ## Use Adaptive When @@ -35,6 +36,8 @@ Start here when you need to: - Collect runtime signals before changing behavior. - Add model-request hints in a controlled way. - Plan prompt-cache breakpoints for supported providers. +- Stop adaptive learning once observed topology-aware signals stabilize. +- Invalidate stale tool parallelism plans when cohort shape drifts. - Evaluate tool parallelism opportunities. - Share adaptive state across workers when needed. - Roll out measured tuning as a configuration change. diff --git a/docs/adaptive-plugin/acg.mdx b/docs/adaptive-plugin/acg.mdx index 44783ebc..1923a6b4 100644 --- a/docs/adaptive-plugin/acg.mdx +++ b/docs/adaptive-plugin/acg.mdx @@ -221,6 +221,9 @@ runtime.shutdown().await?; | `provider` | `passthrough` | `passthrough`, `anthropic`, or `openai`. | | `observation_window` | `100` | Rolling Prompt IR sample window for stability analysis. | | `priority` | `50` | LLM execution intercept priority. Lower values run earlier. | +| `convergence.enabled` | `false` | Optional topology-aware convergence detection for ACG learning. | +| `convergence.epsilon` | `0.001` | Positive finite error threshold used by convergence detection. | +| `convergence.stability_window` | `3` | Minimum epochs required before convergence can be declared. | | `stability_thresholds.stable_threshold` | `0.95` | Minimum effective score classified as stable. | | `stability_thresholds.semi_stable_threshold` | `0.50` | Minimum effective score classified as semi-stable. | | `stability_thresholds.min_observations_for_full_confidence` | `20` | Observation count required for full confidence. | @@ -229,6 +232,10 @@ Use `passthrough` when you want ACG observations without provider-specific hint translation. Set `provider` to the backend API surface the agent actually calls when you are ready to apply cache planning. +ACG convergence uses deterministic topology-inspired stability signals derived +from observed prompt structure. It is an adaptive early-stop control for +learning, not an exact persistent-homology calculation. + ## Expected Output When ACG is active, instrumented LLM calls still return the same application @@ -244,5 +251,7 @@ production. - `provider` is not one of `passthrough`, `anthropic`, or `openai`. - Stability thresholds are outside the supported numeric range. +- `convergence.epsilon` is not positive and finite, or + `convergence.stability_window` is less than `3`. - ACG is enabled before the application emits managed LLM events. - The configured provider does not match the real model API surface. diff --git a/docs/adaptive-plugin/adaptive-hints.mdx b/docs/adaptive-plugin/adaptive-hints.mdx index d2fdec64..5bcc51f2 100644 --- a/docs/adaptive-plugin/adaptive-hints.mdx +++ b/docs/adaptive-plugin/adaptive-hints.mdx @@ -224,11 +224,17 @@ runtime.shutdown().await?; | `break_chain` | `false` | Whether this intercept stops later request intercepts. | | `inject_header` | `true` | Whether to add adaptive hints as request header metadata. | | `inject_body_path` | `nvext.agent_hints` | JSON body path for request-body hint injection. | +| `governor.enabled` | `false` | Enables topology-aware load shedding for learned hint injection. | +| `governor.epsilon` | `1.0` | Positive finite initial sensitivity threshold. | Disable `break_chain` unless the adaptive hint should be the final request transform. Adjust `priority` only when adaptive hints need to run before or after known application middleware. +When the governor is enabled, low-sensitivity learned hints may be skipped +under load. Manual latency-sensitivity overrides still force hint injection for +that request. + ## Expected Output Outgoing managed LLM requests receive adaptive hint metadata in the configured @@ -239,6 +245,7 @@ interpret the metadata before behavior changes. ## Common Validation Failures - Unknown adaptive hint fields when unknown fields are treated as errors. +- `governor.epsilon` is not positive and finite. - `inject_body_path` does not match the request shape expected by downstream provider adapters. - Hint injection is enabled before downstream model paths can consume or ignore diff --git a/docs/adaptive-plugin/configuration.mdx b/docs/adaptive-plugin/configuration.mdx index 55621aef..adad4bbe 100644 --- a/docs/adaptive-plugin/configuration.mdx +++ b/docs/adaptive-plugin/configuration.mdx @@ -32,6 +32,7 @@ The top-level adaptive object contains: | `adaptive_hints` | Request hint-injection behavior. | | `tool_parallelism` | Tool scheduling observation or scheduling behavior. | | `acg` | Adaptive Cache Governor prompt-cache planning. | +| `convergence` | Optional global topology-aware convergence settings used by adaptive learners. | | `policy` | Adaptive-local handling for unknown fields and unsupported values. | The requested area pages cover [Adaptive Cache Governor (ACG)](/adaptive-plugin/acg) and @@ -70,22 +71,40 @@ learners = ["tool_parallelism"] mode = "observe_only" priority = 100 +[components.config.tool_parallelism.drift] +enabled = false +threshold = 0.75 + [components.config.adaptive_hints] priority = 100 break_chain = false inject_header = true inject_body_path = "nvext.agent_hints" +[components.config.adaptive_hints.governor] +enabled = false +epsilon = 1.0 + [components.config.acg] provider = "passthrough" observation_window = 100 priority = 50 +[components.config.acg.convergence] +enabled = false +epsilon = 0.001 +stability_window = 3 + [components.config.acg.stability_thresholds] stable_threshold = 0.95 semi_stable_threshold = 0.50 min_observations_for_full_confidence = 20 +[components.config.convergence] +enabled = false +epsilon = 0.001 +stability_window = 3 + [components.config.policy] unknown_component = "warn" unknown_field = "warn" @@ -112,11 +131,19 @@ adaptive_config = nemo_relay.adaptive.AdaptiveConfig( subscriber_name="adaptive.telemetry", learners=["tool_parallelism"], ), - tool_parallelism=nemo_relay.adaptive.ToolParallelismConfig(mode="observe_only"), + tool_parallelism=nemo_relay.adaptive.ToolParallelismConfig( + mode="observe_only", + drift=nemo_relay.adaptive.DriftConfig(enabled=False), + ), adaptive_hints=nemo_relay.adaptive.AdaptiveHintsConfig( inject_body_path="nvext.agent_hints", + governor=nemo_relay.adaptive.GovernorConfig(enabled=False), ), - acg=nemo_relay.adaptive.AcgConfig(provider="passthrough"), + acg=nemo_relay.adaptive.AcgConfig( + provider="passthrough", + convergence=nemo_relay.adaptive.ConvergenceConfig(enabled=False), + ), + convergence=nemo_relay.adaptive.ConvergenceConfig(enabled=False), ) plugin_config = nemo_relay.plugin.PluginConfig( @@ -144,10 +171,16 @@ adaptiveConfig.telemetry = adaptive.telemetryConfig({ learners: ["tool_parallelism"], }); adaptiveConfig.tool_parallelism = adaptive.toolParallelismConfig({ mode: "observe_only" }); +adaptiveConfig.tool_parallelism.drift = adaptive.driftConfig({ enabled: false }); adaptiveConfig.adaptive_hints = adaptive.adaptiveHintsConfig({ inject_body_path: "nvext.agent_hints", + governor: adaptive.governorConfig({ enabled: false }), +}); +adaptiveConfig.acg = adaptive.acgConfig({ + provider: "passthrough", + convergence: adaptive.convergenceConfig({ enabled: false }), }); -adaptiveConfig.acg = adaptive.acgConfig({ provider: "passthrough" }); +adaptiveConfig.convergence = adaptive.convergenceConfig({ enabled: false }); const pluginConfig = plugin.defaultConfig(); pluginConfig.components = [adaptive.ComponentSpec(adaptiveConfig)]; @@ -166,13 +199,14 @@ const active = await plugin.initialize(pluginConfig); use nemo_relay::plugin::{initialize_plugins, validate_plugin_config, PluginConfig}; use nemo_relay_adaptive::plugin_component::ComponentSpec; use nemo_relay_adaptive::{ - AdaptiveConfig, + AcgComponentConfig, + AdaptiveConfig, AdaptiveHintsComponentConfig, BackendSpec, + ConvergenceConfig, + GovernorConfig, StateConfig, TelemetryComponentConfig, ToolParallelismComponentConfig, - AdaptiveHintsComponentConfig, - AcgComponentConfig, }; let mut adaptive = AdaptiveConfig::default(); @@ -187,12 +221,15 @@ adaptive.telemetry = Some(TelemetryComponentConfig { adaptive.tool_parallelism = Some(ToolParallelismComponentConfig::default()); adaptive.adaptive_hints = Some(AdaptiveHintsComponentConfig { inject_body_path: "nvext.agent_hints".into(), + governor: Some(GovernorConfig::default()), ..AdaptiveHintsComponentConfig::default() }); adaptive.acg = Some(AcgComponentConfig { provider: "passthrough".into(), + convergence: Some(ConvergenceConfig::default()), ..AcgComponentConfig::default() }); +adaptive.convergence = Some(ConvergenceConfig::default()); let mut plugin_config = PluginConfig::default(); plugin_config.components.push(ComponentSpec::new(adaptive).into()); @@ -206,6 +243,23 @@ let active = initialize_plugins(plugin_config).await?; +## Topology-Aware Controls + +Adaptive topology settings are optional and disabled by default. They provide +deterministic topology-inspired signals for convergence, stale-plan drift, and +hint load shedding; they do not claim exact persistent homology. + +| Field | Default | Notes | +|---|---|---| +| `convergence.enabled` | `false` | Enables global convergence detection for compatible adaptive learners. | +| `convergence.epsilon` | `0.001` | Positive finite error threshold. | +| `convergence.stability_window` | `3` | Minimum number of epochs required before convergence can be declared. Must be at least `3`. | +| `acg.convergence` | unset | Component-scoped convergence settings for ACG. Overrides the global convergence settings for ACG when present. | +| `tool_parallelism.drift.enabled` | `false` | Enables topology-aware invalidation of stale tool parallelism plans. | +| `tool_parallelism.drift.threshold` | `0.75` | Positive finite drift distance above which existing plans are discarded. | +| `adaptive_hints.governor.enabled` | `false` | Enables topology-aware load shedding for learned hint injection. | +| `adaptive_hints.governor.epsilon` | `1.0` | Positive finite initial sensitivity threshold. Manual latency-sensitivity overrides still take precedence. | + ## Manual API Use the manual runtime API when an integration needs to own adaptive lifecycle diff --git a/go/nemo_relay/adaptive.go b/go/nemo_relay/adaptive.go index eb7ce81f..65fffe7c 100644 --- a/go/nemo_relay/adaptive.go +++ b/go/nemo_relay/adaptive.go @@ -17,6 +17,7 @@ type AdaptiveConfig struct { AdaptiveHints *AdaptiveHintsConfig `json:"adaptive_hints,omitempty"` ToolParallelism *ToolParallelismConfig `json:"tool_parallelism,omitempty"` Acg *AcgConfig `json:"acg,omitempty"` + Convergence *ConvergenceConfig `json:"convergence,omitempty"` Policy *ConfigPolicy `json:"policy,omitempty"` } @@ -39,16 +40,37 @@ type TelemetryConfig struct { // AdaptiveHintsConfig configures built-in LLM request hint injection. type AdaptiveHintsConfig struct { - Priority int32 `json:"priority,omitempty"` - BreakChain bool `json:"break_chain,omitempty"` - InjectHeader bool `json:"inject_header,omitempty"` - InjectBodyPath string `json:"inject_body_path,omitempty"` + Priority int32 `json:"priority,omitempty"` + BreakChain bool `json:"break_chain,omitempty"` + InjectHeader bool `json:"inject_header,omitempty"` + InjectBodyPath string `json:"inject_body_path,omitempty"` + Governor *GovernorConfig `json:"governor,omitempty"` } // ToolParallelismConfig configures built-in adaptive tool scheduling. type ToolParallelismConfig struct { - Priority int32 `json:"priority,omitempty"` - Mode string `json:"mode,omitempty"` + Priority int32 `json:"priority,omitempty"` + Mode string `json:"mode,omitempty"` + Drift *DriftConfig `json:"drift,omitempty"` +} + +// GovernorConfig configures topology-aware hint load shedding. +type GovernorConfig struct { + Enabled bool `json:"enabled,omitempty"` + Epsilon float64 `json:"epsilon,omitempty"` +} + +// DriftConfig configures topology-aware stale-plan invalidation. +type DriftConfig struct { + Enabled bool `json:"enabled,omitempty"` + Threshold float64 `json:"threshold,omitempty"` +} + +// ConvergenceConfig configures topological convergence detection. +type ConvergenceConfig struct { + Enabled bool `json:"enabled,omitempty"` + Epsilon float64 `json:"epsilon,omitempty"` + StabilityWindow uint32 `json:"stability_window,omitempty"` } // AcgStabilityThresholds configures prompt stability classification thresholds. @@ -64,6 +86,7 @@ type AcgConfig struct { ObservationWindow uint32 `json:"observation_window,omitempty"` Priority int32 `json:"priority,omitempty"` StabilityThresholds *AcgStabilityThresholds `json:"stability_thresholds,omitempty"` + Convergence *ConvergenceConfig `json:"convergence,omitempty"` } // AdaptiveComponentSpec wraps one adaptive config as a top-level plugin component. @@ -101,6 +124,21 @@ func NewTelemetryConfig() TelemetryConfig { return TelemetryConfig{} } +// NewGovernorConfig returns default topology-aware hint load-shedding settings. +func NewGovernorConfig() GovernorConfig { + return GovernorConfig{Epsilon: 1.0} +} + +// NewDriftConfig returns default topology-aware stale-plan detection settings. +func NewDriftConfig() DriftConfig { + return DriftConfig{Threshold: 0.75} +} + +// NewConvergenceConfig returns default topological convergence detection settings. +func NewConvergenceConfig() ConvergenceConfig { + return ConvergenceConfig{Epsilon: 0.001, StabilityWindow: 3} +} + // NewAdaptiveHintsConfig returns default adaptive hints injection settings. func NewAdaptiveHintsConfig() AdaptiveHintsConfig { return AdaptiveHintsConfig{ diff --git a/go/nemo_relay/adaptive/adaptive.go b/go/nemo_relay/adaptive/adaptive.go index 49306422..44fd1ba8 100644 --- a/go/nemo_relay/adaptive/adaptive.go +++ b/go/nemo_relay/adaptive/adaptive.go @@ -46,6 +46,15 @@ type AdaptiveHintsConfig = nemo_relay.AdaptiveHintsConfig // ToolParallelismConfig configures built-in adaptive tool scheduling. type ToolParallelismConfig = nemo_relay.ToolParallelismConfig +// GovernorConfig configures topology-aware hint load shedding. +type GovernorConfig = nemo_relay.GovernorConfig + +// DriftConfig configures topology-aware stale-plan invalidation. +type DriftConfig = nemo_relay.DriftConfig + +// ConvergenceConfig configures topological convergence detection. +type ConvergenceConfig = nemo_relay.ConvergenceConfig + // AcgStabilityThresholds configures ACG prompt-stability classification. type AcgStabilityThresholds = nemo_relay.AcgStabilityThresholds @@ -93,6 +102,21 @@ func NewTelemetryConfig() TelemetryConfig { return nemo_relay.NewTelemetryConfig() } +// NewGovernorConfig returns default topology-aware hint load-shedding settings. +func NewGovernorConfig() GovernorConfig { + return nemo_relay.NewGovernorConfig() +} + +// NewDriftConfig returns default topology-aware stale-plan detection settings. +func NewDriftConfig() DriftConfig { + return nemo_relay.NewDriftConfig() +} + +// NewConvergenceConfig returns default topological convergence detection settings. +func NewConvergenceConfig() ConvergenceConfig { + return nemo_relay.NewConvergenceConfig() +} + // NewAdaptiveHintsConfig returns default adaptive hints injection settings. func NewAdaptiveHintsConfig() AdaptiveHintsConfig { return nemo_relay.NewAdaptiveHintsConfig() diff --git a/go/nemo_relay/adaptive_test.go b/go/nemo_relay/adaptive_test.go index fba86b6f..5d57e54e 100644 --- a/go/nemo_relay/adaptive_test.go +++ b/go/nemo_relay/adaptive_test.go @@ -19,7 +19,7 @@ func TestNewAdaptiveConfigDefaults(t *testing.T) { if config.Version != 1 { t.Fatalf("expected version 1, got %d", config.Version) } - if config.Telemetry != nil || config.AdaptiveHints != nil || config.ToolParallelism != nil || config.Acg != nil { + if config.Telemetry != nil || config.AdaptiveHints != nil || config.ToolParallelism != nil || config.Acg != nil || config.Convergence != nil { t.Fatal("expected adaptive feature sections to default to nil") } } @@ -31,6 +31,15 @@ func TestAdaptiveHelperConstructors(t *testing.T) { telemetry := NewTelemetryConfig() assertTelemetryDefaults(t, telemetry) + governor := NewGovernorConfig() + assertGovernorDefaults(t, governor) + + drift := NewDriftConfig() + assertDriftDefaults(t, drift) + + convergence := NewConvergenceConfig() + assertConvergenceDefaults(t, convergence) + hints := NewAdaptiveHintsConfig() assertAdaptiveHintsDefaults(t, hints) @@ -73,6 +82,27 @@ func assertTelemetryDefaults(t *testing.T, telemetry TelemetryConfig) { } } +func assertGovernorDefaults(t *testing.T, governor GovernorConfig) { + t.Helper() + if governor.Enabled || governor.Epsilon != 1.0 { + t.Fatalf("unexpected governor defaults: %#v", governor) + } +} + +func assertDriftDefaults(t *testing.T, drift DriftConfig) { + t.Helper() + if drift.Enabled || drift.Threshold != 0.75 { + t.Fatalf("unexpected drift defaults: %#v", drift) + } +} + +func assertConvergenceDefaults(t *testing.T, convergence ConvergenceConfig) { + t.Helper() + if convergence.Enabled || convergence.Epsilon != 0.001 || convergence.StabilityWindow != 3 { + t.Fatalf("unexpected convergence defaults: %#v", convergence) + } +} + func assertAdaptiveHintsDefaults(t *testing.T, hints AdaptiveHintsConfig) { t.Helper() if hints.Priority != 100 || !hints.InjectHeader || hints.InjectBodyPath != "nvext.agent_hints" { diff --git a/python/nemo_relay/__init__.py b/python/nemo_relay/__init__.py index a14e8c8a..46dab4b9 100644 --- a/python/nemo_relay/__init__.py +++ b/python/nemo_relay/__init__.py @@ -15,6 +15,7 @@ - ``nemo_relay.typed`` for codec-based typed wrappers - ``nemo_relay.plugin`` for global plugin configuration and custom plugin registration - ``nemo_relay.adaptive`` for adaptive component configuration helpers +- ``nemo_relay.adaptive_topology`` for adaptive topology primitives - ``nemo_relay.observability`` for observability component configuration helpers - ``nemo_relay.pii_redaction`` for PII redaction component configuration helpers - ``nemo_relay.pricing`` for pricing component configuration helpers @@ -187,6 +188,7 @@ async def main(): # intentionally not importing utils.py to avoid overhead of creating the ThreadPoolExecutor unless it is needed from nemo_relay import ( # noqa: E402 adaptive, + adaptive_topology, codecs, guardrails, intercepts, @@ -436,6 +438,7 @@ def worker() -> None: "typed", "plugin", "adaptive", + "adaptive_topology", "observability", "pii_redaction", "pricing", diff --git a/python/nemo_relay/__init__.pyi b/python/nemo_relay/__init__.pyi index 676a0a6c..64223c9a 100644 --- a/python/nemo_relay/__init__.pyi +++ b/python/nemo_relay/__init__.pyi @@ -26,6 +26,7 @@ from collections.abc import AsyncIterator, Awaitable, Callable from typing import Literal, Optional, TypeAlias from nemo_relay import adaptive as adaptive +from nemo_relay import adaptive_topology as adaptive_topology from nemo_relay import codecs as codecs from nemo_relay import guardrails as guardrails from nemo_relay import intercepts as intercepts diff --git a/python/nemo_relay/_native.pyi b/python/nemo_relay/_native.pyi index c30145a8..b1ca93e6 100644 --- a/python/nemo_relay/_native.pyi +++ b/python/nemo_relay/_native.pyi @@ -1126,6 +1126,128 @@ class PluginContext: for runtime registration callbacks. """ +class GeometricGovernor: + """Adaptive threshold controller using a PD control law. + + Summary: + Maintains a sensitivity threshold ``epsilon`` that adapts to the + observed deviation rate. + + Description: + The governor increases ``epsilon`` when the system wakes too often and + decreases it when the system is too sluggish. ``should_trigger`` compares + a deviation against the current threshold. + """ + + def __init__(self) -> None: + """Create a governor with the default threshold and gains.""" + ... + @staticmethod + def with_epsilon(epsilon: float) -> GeometricGovernor: + """Create a governor with a custom initial threshold.""" + ... + def adapt(self, deviation_delta: float, dt: float) -> float: + """Adapt epsilon based on the observed deviation over ``dt`` seconds.""" + ... + def should_trigger(self, deviation: float) -> bool: + """Return whether ``deviation`` meets or exceeds the threshold.""" + ... + @property + def epsilon(self) -> float: + """Return the current threshold.""" + ... + @property + def adjustment_count(self) -> int: + """Return the number of adaptations performed so far.""" + ... + @property + def last_error(self) -> float: + """Return the error from the most recent adaptation.""" + ... + def reset(self) -> None: + """Reset the governor to its initial state.""" + ... + def __repr__(self) -> str: + """Return a debug representation of the governor.""" + ... + +class ConvergenceDetector: + """Topological convergence detector. + + Summary: + Declares convergence when Betti numbers are stable, drift is + decreasing, and error falls below a threshold. + + Description: + ``record_epoch`` feeds topology metrics from each epoch. ``is_converged`` + and ``convergence_score`` read the current state. + """ + + def __init__(self, epsilon: float, stability_window: int) -> None: + """Create a detector with the given error threshold and stability window.""" + ... + def record_epoch(self, beta_0: int, beta_1: int, drift: float, error: float) -> None: + """Record an epoch's Betti numbers, drift, and error.""" + ... + @property + def is_converged(self) -> bool: + """Return whether convergence criteria are satisfied.""" + ... + @property + def convergence_score(self) -> float: + """Return a score in ``[0, 1]`` indicating nearness to convergence.""" + ... + @property + def epoch(self) -> int: + """Return the number of epochs recorded.""" + ... + @property + def last_betti(self) -> tuple[int, int] | None: + """Return the most recent ``(beta_0, beta_1)`` pair, if any.""" + ... + @property + def last_error(self) -> float | None: + """Return the most recent error, if any.""" + ... + def reset(self) -> None: + """Reset the detector to its initial state.""" + ... + def __repr__(self) -> str: + """Return a debug representation of the detector.""" + ... + +class DriftDetector: + """Centroid trajectory drift detector. + + Summary: + Tracks the velocity of a 3-dimensional centroid trajectory and reports + drift from the predicted position. + + Description: + ``update`` records a new centroid and returns the drift from the + predicted position. ``is_drifting`` compares the velocity magnitude + against a threshold. + """ + + def __init__(self) -> None: + """Create a detector with no previous observation and zero velocity.""" + ... + def update(self, centroid: Sequence[float]) -> float: + """Record a centroid and return drift from the predicted position.""" + ... + def is_drifting(self, threshold: float) -> bool: + """Return whether the velocity magnitude exceeds ``threshold``.""" + ... + def velocity_magnitude(self) -> float: + """Return the magnitude of the current velocity vector.""" + ... + def reset(self) -> None: + """Reset the detector to its initial state.""" + ... + def __repr__(self) -> str: + """Return a debug representation of the detector.""" + ... + def create_scope_stack() -> ScopeStack: """Create a fresh native scope stack. diff --git a/python/nemo_relay/adaptive.py b/python/nemo_relay/adaptive.py index e4f37545..c160f6a9 100644 --- a/python/nemo_relay/adaptive.py +++ b/python/nemo_relay/adaptive.py @@ -150,6 +150,65 @@ def to_dict(self) -> JsonObject: ) +@dataclass(slots=True) +class GovernorConfig: + """Topology-aware load-shedding settings for adaptive hints. + + Args: + enabled: Whether the governor is active. + epsilon: Initial sensitivity threshold. + """ + + enabled: bool = False + epsilon: float = 1.0 + + def to_dict(self) -> JsonObject: + """Serialize this governor config to the canonical JSON object shape.""" + return _normalize_object({"enabled": self.enabled, "epsilon": self.epsilon}) + + +@dataclass(slots=True) +class DriftConfig: + """Topology-aware drift detection settings for tool plans. + + Args: + enabled: Whether drift detection is active. + threshold: Drift distance above which existing plans are invalidated. + """ + + enabled: bool = False + threshold: float = 0.75 + + def to_dict(self) -> JsonObject: + """Serialize this drift config to the canonical JSON object shape.""" + return _normalize_object({"enabled": self.enabled, "threshold": self.threshold}) + + +@dataclass(slots=True) +class ConvergenceConfig: + """Topological convergence detection settings. + + Args: + enabled: Whether convergence detection is active. + epsilon: Error threshold below which convergence can be declared. + stability_window: Minimum number of epochs required for stability. + """ + + enabled: bool = False + epsilon: float = 0.001 + stability_window: int = 3 + + def to_dict(self) -> JsonObject: + """Serialize this convergence config to the canonical JSON object shape.""" + return _normalize_object( + { + "enabled": self.enabled, + "epsilon": self.epsilon, + "stability_window": self.stability_window, + } + ) + + @dataclass(slots=True) class AdaptiveHintsConfig: """Built-in adaptive hints injection settings. @@ -159,12 +218,14 @@ class AdaptiveHintsConfig: break_chain: Whether to stop later request intercepts after this one. inject_header: Whether to inject the adaptive hints HTTP header. inject_body_path: JSON body path used when injecting request-body hints. + governor: Optional topology-aware load-shedding settings. """ priority: int = 100 break_chain: bool = False inject_header: bool = True inject_body_path: str = "nvext.agent_hints" + governor: GovernorConfig | None = None def to_dict(self) -> JsonObject: """Serialize this adaptive-hints config to the canonical JSON object shape.""" @@ -174,6 +235,7 @@ def to_dict(self) -> JsonObject: "break_chain": self.break_chain, "inject_header": self.inject_header, "inject_body_path": self.inject_body_path, + "governor": _normalize(self.governor), } ) @@ -187,14 +249,16 @@ class ToolParallelismConfig: mode: Scheduling mode. ``"observe_only"`` records signals without changing behavior, while other modes enable stronger adaptive scheduling behavior. + drift: Optional topology-aware stale-plan invalidation settings. """ priority: int = 100 mode: Literal["observe_only", "inject_hints", "schedule"] = "observe_only" + drift: DriftConfig | None = None def to_dict(self) -> JsonObject: """Serialize this tool-parallelism config to the canonical JSON object shape.""" - return _normalize_object({"priority": self.priority, "mode": self.mode}) + return _normalize_object({"priority": self.priority, "mode": self.mode, "drift": _normalize(self.drift)}) @dataclass(slots=True) @@ -232,12 +296,14 @@ class AcgConfig: observation_window: Rolling PromptIR observation window size. priority: LLM execution intercept priority. stability_thresholds: Prompt-stability classification thresholds. + convergence: Optional component-scoped topological convergence settings. """ provider: Literal["anthropic", "openai", "passthrough"] = "passthrough" observation_window: int = 100 priority: int = 50 stability_thresholds: AcgStabilityThresholds | None = field(default_factory=AcgStabilityThresholds) + convergence: ConvergenceConfig | None = None def to_dict(self) -> JsonObject: """Serialize this ACG config to the canonical JSON object shape.""" @@ -247,6 +313,7 @@ def to_dict(self) -> JsonObject: "observation_window": self.observation_window, "priority": self.priority, "stability_thresholds": _normalize(self.stability_thresholds), + "convergence": _normalize(self.convergence), } ) @@ -263,6 +330,7 @@ class AdaptiveConfig: adaptive_hints: Built-in LLM hint-injection settings. tool_parallelism: Built-in tool scheduling settings. acg: Adaptive Cache Governor settings. + convergence: Global topological convergence settings. policy: Unsupported-config policy applied within the adaptive config. Behavior: @@ -277,6 +345,7 @@ class AdaptiveConfig: adaptive_hints: AdaptiveHintsConfig | None = None tool_parallelism: ToolParallelismConfig | None = None acg: AcgConfig | None = None + convergence: ConvergenceConfig | None = None policy: ConfigPolicy = field(default_factory=ConfigPolicy) def to_dict(self) -> JsonObject: @@ -289,6 +358,7 @@ def to_dict(self) -> JsonObject: "adaptive_hints": _normalize(self.adaptive_hints), "tool_parallelism": _normalize(self.tool_parallelism), "acg": _normalize(self.acg), + "convergence": _normalize(self.convergence), "policy": self.policy.to_dict(), } @@ -379,15 +449,21 @@ def set_latency_sensitivity(level: int) -> None: "AcgStabilityThresholds", "AdaptiveConfig", "AdaptiveHintsConfig", + "AdaptiveRuntime", "ADAPTIVE_PLUGIN_KIND", "BackendSpec", + "build_cache_telemetry_event", "ConfigDiagnostic", "ConfigPolicy", "ConfigReport", "ComponentSpec", + "ConvergenceConfig", + "DriftConfig", + "GovernorConfig", "StateConfig", "TelemetryConfig", "ToolParallelismConfig", "set_latency_sensitivity", "UnsupportedBehavior", + "validate_config", ] diff --git a/python/nemo_relay/adaptive.pyi b/python/nemo_relay/adaptive.pyi index 892f7260..454042f7 100644 --- a/python/nemo_relay/adaptive.pyi +++ b/python/nemo_relay/adaptive.pyi @@ -13,18 +13,18 @@ from typing import Literal, TypedDict from nemo_relay import JsonObject, ScopeHandle, UnsupportedBehavior -class ConfigDiagnostic(TypedDict, total=False): - """One adaptive configuration diagnostic. - - Fields mirror the runtime validation report produced by the Rust adaptive - validator. - """ +__all__: list[str] +class _ConfigDiagnosticRequired(TypedDict): level: Literal["warning", "error"] code: str + message: str + +class ConfigDiagnostic(_ConfigDiagnosticRequired, total=False): + """One adaptive configuration diagnostic.""" + component: str field: str - message: str class ConfigReport(TypedDict): """Validation report returned by adaptive configuration helpers.""" @@ -105,6 +105,40 @@ class TelemetryConfig: """Serialize this telemetry config to the canonical JSON object shape.""" ... +@dataclass(slots=True) +class GovernorConfig: + """Topology-aware load-shedding settings for adaptive hints.""" + + enabled: bool = ... + epsilon: float = ... + + def to_dict(self) -> JsonObject: + """Serialize this governor config to the canonical JSON object shape.""" + ... + +@dataclass(slots=True) +class DriftConfig: + """Topology-aware drift detection settings for tool plans.""" + + enabled: bool = ... + threshold: float = ... + + def to_dict(self) -> JsonObject: + """Serialize this drift config to the canonical JSON object shape.""" + ... + +@dataclass(slots=True) +class ConvergenceConfig: + """Topological convergence detection settings.""" + + enabled: bool = ... + epsilon: float = ... + stability_window: int = ... + + def to_dict(self) -> JsonObject: + """Serialize this convergence config to the canonical JSON object shape.""" + ... + @dataclass(slots=True) class AdaptiveHintsConfig: """Built-in adaptive hints injection settings. @@ -114,12 +148,14 @@ class AdaptiveHintsConfig: break_chain: Whether to stop later request intercepts after this one. inject_header: Whether to inject the adaptive hints HTTP header. inject_body_path: JSON body path used when injecting request-body hints. + governor: Optional topology-aware load-shedding settings. """ priority: int = ... break_chain: bool = ... inject_header: bool = ... inject_body_path: str = ... + governor: GovernorConfig | None = ... def to_dict(self) -> JsonObject: """Serialize this adaptive-hints config to the canonical JSON object shape.""" @@ -133,10 +169,12 @@ class ToolParallelismConfig: priority: Intercept priority. Lower values run first. mode: Scheduling mode. ``"observe_only"`` records signals without changing behavior, while stronger modes allow adaptive scheduling. + drift: Optional topology-aware stale-plan invalidation settings. """ priority: int = ... mode: Literal["observe_only", "inject_hints", "schedule"] = ... + drift: DriftConfig | None = ... def to_dict(self) -> JsonObject: """Serialize this tool-parallelism config to the canonical JSON object shape.""" @@ -168,14 +206,16 @@ class AcgConfig: Args: provider: Provider cache plugin name. observation_window: Rolling PromptIR observation window size. - priority: Request-intercept priority used by ACG. + priority: LLM execution intercept priority used by ACG. stability_thresholds: Prompt-stability classification thresholds. + convergence: Optional component-scoped topological convergence settings. """ provider: Literal["anthropic", "openai", "passthrough"] = ... observation_window: int = ... priority: int = ... stability_thresholds: AcgStabilityThresholds | None = ... + convergence: ConvergenceConfig | None = ... def to_dict(self) -> JsonObject: """Serialize this ACG config to the canonical JSON object shape.""" @@ -193,6 +233,7 @@ class AdaptiveConfig: adaptive_hints: Built-in adaptive request-hints configuration. tool_parallelism: Built-in adaptive tool-scheduling configuration. acg: Adaptive Cache Governor configuration. + convergence: Global topological convergence settings. policy: Policy for unsupported adaptive configuration. """ @@ -203,6 +244,7 @@ class AdaptiveConfig: adaptive_hints: AdaptiveHintsConfig | None = ... tool_parallelism: ToolParallelismConfig | None = ... acg: AcgConfig | None = ... + convergence: ConvergenceConfig | None = ... policy: ConfigPolicy = ... def to_dict(self) -> JsonObject: diff --git a/python/nemo_relay/adaptive_topology.py b/python/nemo_relay/adaptive_topology.py new file mode 100644 index 00000000..8bfb6664 --- /dev/null +++ b/python/nemo_relay/adaptive_topology.py @@ -0,0 +1,20 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +"""Adaptive topology primitives. + +This module exposes topology-aware helpers for threshold control, convergence +detection, and centroid drift tracking. +""" + +from __future__ import annotations + +from nemo_relay._native import ConvergenceDetector as ConvergenceDetector +from nemo_relay._native import DriftDetector as DriftDetector +from nemo_relay._native import GeometricGovernor as GeometricGovernor + +__all__ = [ + "ConvergenceDetector", + "DriftDetector", + "GeometricGovernor", +] diff --git a/python/nemo_relay/adaptive_topology.pyi b/python/nemo_relay/adaptive_topology.pyi new file mode 100644 index 00000000..b9d9e41c --- /dev/null +++ b/python/nemo_relay/adaptive_topology.pyi @@ -0,0 +1,26 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +"""Adaptive topology primitives. + +This module exposes topology-aware helpers for threshold control, convergence +detection, and centroid drift tracking. +""" + +from __future__ import annotations + +from nemo_relay._native import ( + ConvergenceDetector as ConvergenceDetector, +) +from nemo_relay._native import ( + DriftDetector as DriftDetector, +) +from nemo_relay._native import ( + GeometricGovernor as GeometricGovernor, +) + +__all__ = [ + "ConvergenceDetector", + "DriftDetector", + "GeometricGovernor", +] diff --git a/python/tests/test_adaptive.py b/python/tests/test_adaptive.py index f3fb9254..bd110f39 100644 --- a/python/tests/test_adaptive.py +++ b/python/tests/test_adaptive.py @@ -19,6 +19,9 @@ AdaptiveHintsConfig, BackendSpec, ComponentSpec, + ConvergenceConfig, + DriftConfig, + GovernorConfig, StateConfig, TelemetryConfig, ToolParallelismConfig, @@ -33,6 +36,16 @@ def test_file_covers_native_cache_request_facts_regression(self): assert runtime_call in source assert annotated_request in source + def test_public_exports_include_runtime_and_validation_helpers(self): + assert { + "AdaptiveRuntime", + "validate_config", + "build_cache_telemetry_event", + "ConvergenceConfig", + "DriftConfig", + "GovernorConfig", + }.issubset(set(adaptive_module.__all__)) + def test_backend_helpers(self): assert BackendSpec.in_memory().to_dict() == {"kind": "in_memory", "config": {}} assert BackendSpec.redis("redis://127.0.0.1:6379").to_dict() == { @@ -60,6 +73,14 @@ def test_section_helpers(self): assert TelemetryConfig(learners=["latency_sensitivity"]).to_dict() == {"learners": ["latency_sensitivity"]} assert AdaptiveHintsConfig().to_dict()["priority"] == 100 assert ToolParallelismConfig().to_dict()["mode"] == "observe_only" + assert AdaptiveHintsConfig(governor=GovernorConfig(enabled=True)).to_dict()["governor"] == { + "enabled": True, + "epsilon": 1.0, + } + assert ToolParallelismConfig(drift=DriftConfig(enabled=True)).to_dict()["drift"] == { + "enabled": True, + "threshold": 0.75, + } def test_adaptive_component_wraps_as_plugin_component(self): wrapped = ComponentSpec(AdaptiveConfig()).to_dict() @@ -71,6 +92,16 @@ def test_validate_adaptive_plugin_component_warns_missing_state(self): ) assert any(diag["code"] == "adaptive.section_disabled_missing_state" for diag in report["diagnostics"]) + def test_topology_helper_config_is_accepted_by_plugin_validation(self): + config = AdaptiveConfig( + adaptive_hints=AdaptiveHintsConfig(governor=GovernorConfig(enabled=True)), + tool_parallelism=ToolParallelismConfig(drift=DriftConfig(enabled=True)), + acg=AcgConfig(provider="anthropic", convergence=ConvergenceConfig(enabled=True)), + convergence=ConvergenceConfig(enabled=True), + ) + report = plugin.validate(plugin.PluginConfig(components=[ComponentSpec(config)])) + assert not any(diag["code"] == "adaptive.unknown_field" for diag in report["diagnostics"]) + def test_plugin_component_spec_normalizes_lists_of_dataclasses(self): @dataclass class ExampleConfig: @@ -95,6 +126,7 @@ def test_acg_config_exposes_canonical_threshold_shape(self): "observation_window", "priority", "stability_thresholds", + "convergence", ] assert AcgStabilityThresholds().to_dict() == { "stable_threshold": 0.95, @@ -111,6 +143,11 @@ def test_acg_config_exposes_canonical_threshold_shape(self): "min_observations_for_full_confidence": 20, }, } + assert AcgConfig(convergence=ConvergenceConfig(enabled=True)).to_dict()["convergence"] == { + "enabled": True, + "epsilon": 0.001, + "stability_window": 3, + } class TestAdaptivePluginConfiguration: diff --git a/python/tests/test_adaptive_config.py b/python/tests/test_adaptive_config.py index eec629c4..89b37e44 100644 --- a/python/tests/test_adaptive_config.py +++ b/python/tests/test_adaptive_config.py @@ -15,6 +15,7 @@ BackendSpec, ComponentSpec, ConfigPolicy, + ConvergenceConfig, StateConfig, TelemetryConfig, ToolParallelismConfig, @@ -143,6 +144,11 @@ def test_openai_acg_config_serializes_without_transport_fields(self): "min_observations_for_full_confidence": 20, }, } + assert AcgConfig(convergence=ConvergenceConfig(enabled=True)).to_dict()["convergence"] == { + "enabled": True, + "epsilon": 0.001, + "stability_window": 3, + } def test_acg_config_allows_threshold_overrides(self): assert AcgConfig( diff --git a/python/tests/test_adaptive_topology.py b/python/tests/test_adaptive_topology.py new file mode 100644 index 00000000..6fa62476 --- /dev/null +++ b/python/tests/test_adaptive_topology.py @@ -0,0 +1,62 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +"""Tests for adaptive topology primitives.""" + +from nemo_relay.adaptive_topology import ConvergenceDetector, DriftDetector, GeometricGovernor + + +class TestConvergenceDetector: + def test_converges_after_stable_epochs(self): + detector = ConvergenceDetector(epsilon=0.001, stability_window=3) + detector.record_epoch(1, 0, 0.1, 0.05) + detector.record_epoch(1, 0, 0.05, 0.04) + detector.record_epoch(1, 0, 0.001, 0.03) + + assert detector.is_converged + assert detector.convergence_score > 0.0 + assert detector.epoch == 3 + + def test_unstable_betti_numbers_do_not_converge(self): + detector = ConvergenceDetector(epsilon=0.001, stability_window=3) + detector.record_epoch(1, 0, 0.05, 0.04) + detector.record_epoch(2, 0, 0.03, 0.03) + detector.record_epoch(1, 0, 0.001, 0.02) + + assert not detector.is_converged + + +class TestGeometricGovernor: + def test_high_deviation_raises_epsilon(self): + governor = GeometricGovernor() + initial = governor.epsilon + governor.adapt(10_000.0, 0.001) + + assert governor.epsilon > initial + assert governor.adjustment_count == 1 + + def test_trigger_respects_epsilon(self): + governor = GeometricGovernor() + assert not governor.should_trigger(governor.epsilon - 0.001) + assert governor.should_trigger(governor.epsilon) + + +class TestDriftDetector: + def test_detects_sudden_drift(self): + detector = DriftDetector() + assert detector.update([0.0, 0.0, 0.0]) == 0.0 + detector.update([1.0, 0.0, 0.0]) + detector.update([2.0, 0.0, 0.0]) + + drift = detector.update([5.0, 0.0, 0.0]) + assert drift > 1.0 + assert detector.is_drifting(1.5) + assert not detector.is_drifting(10.0) + + def test_velocity_magnitude_tracks_steady_motion(self): + detector = DriftDetector() + detector.update([0.0, 0.0, 0.0]) + detector.update([1.0, 0.0, 0.0]) + detector.update([2.0, 0.0, 0.0]) + + assert detector.velocity_magnitude() > 0.9 diff --git a/scripts/docs/fern_cleanup.py b/scripts/docs/fern_cleanup.py index 28d1b013..2a44d94f 100644 --- a/scripts/docs/fern_cleanup.py +++ b/scripts/docs/fern_cleanup.py @@ -30,9 +30,9 @@ "[Node.js Library Reference](/reference/api/nodejs-library-reference), and\n" "[Rust Library Reference](/reference/api/rust-library-reference) for generated\n" "symbol-level documentation. The Rust reference includes `nemo-relay`,\n" - "`nemo-relay-adaptive`, `nemo-relay-pii-redaction`, and `nemo-relay-ffi`.\n" - "For Go and WebAssembly surfaces, use the source directories, tests, and\n" - "task-focused guides when you need exact behavior." + "`nemo-relay-adaptive`, and `nemo-relay-ffi`. For Go and WebAssembly surfaces, use\n" + "the source directories, tests, and task-focused guides when you need exact\n" + "behavior." ) ASSISTANT_SYMBOL_REFERENCE_TEXT = ( "For symbol-level work, assistants should use the source directories, tests, and\n" diff --git a/scripts/docs/generate_rust_library_reference.py b/scripts/docs/generate_rust_library_reference.py index 03565570..2a2b398c 100644 --- a/scripts/docs/generate_rust_library_reference.py +++ b/scripts/docs/generate_rust_library_reference.py @@ -23,14 +23,10 @@ CRATES = ( ("nemo-relay", "nemo_relay", "Core Rust runtime APIs for NeMo Relay."), ("nemo-relay-adaptive", "nemo_relay_adaptive", "Adaptive runtime primitives and plugin components."), - ("nemo-relay-pii-redaction", "nemo_relay_pii_redaction", "PII redaction plugin components for NeMo Relay."), ("nemo-relay-ffi", "nemo_relay_ffi", "C-compatible FFI surface for NeMo Relay."), ) BASE_URL = "/reference/api/rust-library-reference" -GENERATED_BY = ( - "Generated from `cargo doc --no-deps -p nemo-relay -p nemo-relay-adaptive " - "-p nemo-relay-pii-redaction -p nemo-relay-ffi`." -) +GENERATED_BY = "Generated from `cargo doc --no-deps -p nemo-relay -p nemo-relay-adaptive -p nemo-relay-ffi`." TRANSLATION_TABLE = str.maketrans( { "\xa0": " ", @@ -161,8 +157,6 @@ def _run_cargo_doc(repo_root: Path) -> None: "-p", "nemo-relay-adaptive", "-p", - "nemo-relay-pii-redaction", - "-p", "nemo-relay-ffi", ], cwd=repo_root,