json-rest-api 1.0.22 → 1.0.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (290) hide show
  1. package/CLAUDE.md +1 -2
  2. package/JSKIT_BACKEND_MIGRATION_TRACKER.txt +180 -0
  3. package/README.md +22 -1
  4. package/SINGLE_VALIDATION_CONTRACT_TODO.txt +172 -0
  5. package/docs/API.md +196 -38
  6. package/docs/COMPARISON.md +2 -2
  7. package/docs/GUIDE/GUIDE_1_Initial_Setup.md +111 -5
  8. package/docs/GUIDE/GUIDE_2_2_Manipulating_And_Searching_Tables.md +5 -1
  9. package/docs/GUIDE/GUIDE_2_7_Pagination_And_Ordering.md +3 -1
  10. package/docs/GUIDE/GUIDE_2_8_Effects_of_PUT_and_PATCH.md +12 -60
  11. package/docs/GUIDE/GUIDE_2_Data_And_Relations.md +2 -2
  12. package/docs/GUIDE/GUIDE_3_Field_Transformations.md +5 -1
  13. package/docs/GUIDE/GUIDE_7_Hooks_Data_Management_And_Plugins.md +2 -0
  14. package/docs/GUIDE/GUIDE_X_Autofiltering.md +355 -0
  15. package/docs/GUIDE/GUIDE_X_Fastify.md +78 -0
  16. package/docs/GUIDE/GUIDE_X_Knex_Schema_And_Migrations.md +370 -0
  17. package/docs/GUIDE/GUIDE_X_Query_Projections.md +159 -0
  18. package/docs/GUIDE/GUIDE_X_Writing_Plugins.md +199 -0
  19. package/docs/GUIDE/index.md +18 -9
  20. package/docs/QUICKSTART.md +5 -1
  21. package/docs/index.md +1 -1
  22. package/index.js +3 -2
  23. package/lib/enhanced-logger.js +1 -1
  24. package/package.json +6 -2
  25. package/plugins/core/bulk-operations-plugin.js +26 -34
  26. package/plugins/core/connectors/express-plugin.js +97 -190
  27. package/plugins/core/connectors/fastify-plugin.js +206 -0
  28. package/plugins/core/connectors/lib/busboy-detector.js +4 -4
  29. package/plugins/core/connectors/lib/connector-core.js +195 -0
  30. package/plugins/core/connectors/lib/transport-http-helpers.js +122 -0
  31. package/plugins/core/connectors/lib/transport-route-schemas.js +92 -0
  32. package/plugins/core/lib/anyapi/schema-utils.js +43 -4
  33. package/plugins/core/lib/anyapi/utils/descriptor-helpers.js +4 -1
  34. package/plugins/core/lib/dbIntrospection.js +1078 -0
  35. package/plugins/core/lib/dbTablesOperations.js +1111 -160
  36. package/plugins/core/lib/querying/knex-cross-table-search.js +0 -7
  37. package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +5 -3
  38. package/plugins/core/lib/querying/knex-process-includes.js +3 -4
  39. package/plugins/core/lib/querying/knex-query-helpers.js +21 -76
  40. package/plugins/core/lib/querying/knex-relationship-includes.js +468 -215
  41. package/plugins/core/lib/querying/query-builder-utils.js +19 -0
  42. package/plugins/core/lib/querying/query-field-sort-helpers.js +135 -0
  43. package/plugins/core/lib/querying/sort-helpers.js +33 -0
  44. package/plugins/core/lib/querying/storage-adapter-utils.js +51 -0
  45. package/plugins/core/lib/querying/url-helpers.js +8 -2
  46. package/plugins/core/lib/querying-writing/compile-schemas.js +20 -5
  47. package/plugins/core/lib/querying-writing/knex-field-helpers.js +83 -14
  48. package/plugins/core/lib/querying-writing/knex-json-api-transformers.js +13 -12
  49. package/plugins/core/lib/querying-writing/query-field-helpers.js +88 -0
  50. package/plugins/core/lib/querying-writing/request-contracts.js +590 -0
  51. package/plugins/core/lib/querying-writing/resource-id-normalization.js +131 -0
  52. package/plugins/core/lib/querying-writing/schema-helpers.js +0 -2
  53. package/plugins/core/lib/querying-writing/simplified-helpers.js +4 -11
  54. package/plugins/core/lib/storage/canonical-storage-mapping.js +133 -0
  55. package/plugins/core/lib/storage/storage-adapter.js +82 -4
  56. package/plugins/core/lib/storage/storage-mapping.js +274 -0
  57. package/plugins/core/lib/writing/many-to-many-manipulations.js +4 -2
  58. package/plugins/core/rest-api-anyapi-knex-plugin.js +531 -312
  59. package/plugins/core/rest-api-autofilter-plugin.js +414 -0
  60. package/plugins/core/rest-api-knex-plugin.js +271 -226
  61. package/plugins/core/rest-api-plugin-hooks/register-relationship-routes.js +10 -5
  62. package/plugins/core/rest-api-plugin-hooks/register-scope-routes.js +12 -6
  63. package/plugins/core/rest-api-plugin-hooks/turn-scope-init-into-vars.js +1 -0
  64. package/plugins/core/rest-api-plugin-methods/apply-query-filters.js +41 -0
  65. package/plugins/core/rest-api-plugin-methods/common.js +148 -92
  66. package/plugins/core/rest-api-plugin-methods/delete-relationship.js +11 -2
  67. package/plugins/core/rest-api-plugin-methods/delete.js +6 -1
  68. package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +6 -1
  69. package/plugins/core/rest-api-plugin-methods/get-related.js +7 -2
  70. package/plugins/core/rest-api-plugin-methods/get-relationship.js +7 -2
  71. package/plugins/core/rest-api-plugin-methods/get.js +29 -14
  72. package/plugins/core/rest-api-plugin-methods/patch-relationship.js +10 -3
  73. package/plugins/core/rest-api-plugin-methods/patch.js +56 -12
  74. package/plugins/core/rest-api-plugin-methods/post-relationship.js +11 -2
  75. package/plugins/core/rest-api-plugin-methods/post.js +21 -8
  76. package/plugins/core/rest-api-plugin-methods/put.js +73 -21
  77. package/plugins/core/rest-api-plugin-methods/query.js +15 -53
  78. package/plugins/core/rest-api-plugin-methods/release.js +0 -2
  79. package/plugins/core/rest-api-plugin.js +6 -0
  80. package/plugins/core/rest-api-positioning-plugin.js +2 -5
  81. package/plugins/core/rest-api-query-projections-plugin.js +130 -0
  82. package/plugins/core/socketio-plugin.js +1 -4
  83. package/plugins/storage/local-storage.js +1 -1
  84. package/plugins/storage/s3-storage.js +5 -2
  85. package/quickTest.js +1 -0
  86. package/scripts/run-docs.js +80 -84
  87. package/test-debug.js +1 -1
  88. package/tests/README.md +7 -0
  89. package/tests/anyapi-basic.test.js +3 -0
  90. package/tests/autofilter.test.js +463 -0
  91. package/tests/custom-id-mysql-returning-fallback.test.js +128 -0
  92. package/tests/custom-id-simplified-post.test.js +75 -0
  93. package/tests/custom-idproperty-relationships.test.js +33 -0
  94. package/tests/db-introspection.test.js +521 -0
  95. package/tests/db-table-operations.test.js +786 -0
  96. package/tests/fastify-plugin.test.js +156 -0
  97. package/tests/field-getters.test.js +1 -2
  98. package/tests/field-setters.test.js +0 -4
  99. package/tests/fixtures/api-configs.js +278 -176
  100. package/tests/helpers/fake-fastify.js +99 -0
  101. package/tests/http-connectors-parity.test.js +235 -0
  102. package/tests/id-normalization.test.js +444 -0
  103. package/tests/logical-id-write-validation.test.js +151 -0
  104. package/tests/pagination-cursor-multifield.test.js +11 -11
  105. package/tests/projected-fields.test.js +319 -0
  106. package/tests/relationships.test.js +3 -3
  107. package/tests/searchschema-knex-behavior.test.js +187 -0
  108. package/tests/searchschema-merge.test.js +21 -69
  109. package/tests/storage-mapping.test.js +259 -0
  110. package/audit/00-charter.md +0 -103
  111. package/audit/01-scope-map.md +0 -84
  112. package/audit/02-coverage-matrix.csv +0 -174
  113. package/audit/03-invariants.md +0 -123
  114. package/audit/04-standards-rubric.md +0 -56
  115. package/audit/05-competitor-rubric.md +0 -77
  116. package/audit/06-findings.md +0 -160
  117. package/audit/07-risk-register.csv +0 -10
  118. package/audit/08-remediation-roadmap.md +0 -177
  119. package/audit/09-signoff-check.md +0 -23
  120. package/audit/10-final-synthesis.md +0 -29
  121. package/audit/evidence/code/all-files-json-rest-api.txt +0 -168
  122. package/audit/evidence/code/all-files-json-rest-schema.txt +0 -12
  123. package/audit/evidence/code/boundary-leak-checks.txt +0 -72
  124. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__bulk-operations-plugin.js.txt +0 -480
  125. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__express-plugin.js.txt +0 -532
  126. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__lib__busboy-detector.js.txt +0 -175
  127. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__lib__formidable-detector.js.txt +0 -138
  128. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__connectors__lib__request-helpers.js.txt +0 -222
  129. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__file-handling-plugin.js.txt +0 -342
  130. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__dbTablesOperations.js.txt +0 -304
  131. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__fractional-positioning.js.txt +0 -188
  132. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__compile-schemas.js.txt +0 -336
  133. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__connectors-query-parser.js.txt +0 -165
  134. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__database-capabilities.js.txt +0 -265
  135. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__database-value-normalizers.js.txt +0 -369
  136. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__default-data-helpers.js.txt +0 -72
  137. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__field-utils.js.txt +0 -139
  138. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__knex-constants.js.txt +0 -45
  139. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__knex-field-helpers.js.txt +0 -396
  140. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__knex-json-api-transformers.js.txt +0 -162
  141. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__payload-validators.js.txt +0 -1314
  142. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__schema-helpers.js.txt +0 -488
  143. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__scope-validations.js.txt +0 -484
  144. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying-writing__simplified-helpers.js.txt +0 -857
  145. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-cross-table-search.js.txt +0 -565
  146. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-json-api-transformers-querying.js.txt +0 -485
  147. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-pagination-helpers.js.txt +0 -560
  148. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-process-includes.js.txt +0 -167
  149. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-query-helpers-base.js.txt +0 -109
  150. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-query-helpers.js.txt +0 -1064
  151. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-relationship-includes.js.txt +0 -1983
  152. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__knex-window-queries.js.txt +0 -328
  153. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__querying__url-helpers.js.txt +0 -119
  154. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__storage__storage-adapter.js.txt +0 -160
  155. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__writing__many-to-many-manipulations.js.txt +0 -300
  156. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__lib__writing__relationship-processor.js.txt +0 -245
  157. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-access.js.txt +0 -459
  158. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-cors-plugin.js.txt +0 -237
  159. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-knex-plugin.js.txt +0 -1135
  160. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-multihome-plugin.js.txt +0 -314
  161. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__compile-resource-schemas.js.txt +0 -7
  162. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__register-relationship-routes.js.txt +0 -71
  163. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__register-scope-routes.js.txt +0 -102
  164. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__turn-scope-init-into-vars.js.txt +0 -49
  165. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-hooks__validate-include-configurations.js.txt +0 -39
  166. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__add-route.js.txt +0 -23
  167. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__check-permissions.js.txt +0 -13
  168. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__common.js.txt +0 -639
  169. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__delete-relationship.js.txt +0 -117
  170. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__delete.js.txt +0 -104
  171. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__enrich-attributes.js.txt +0 -199
  172. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__get-related.js.txt +0 -353
  173. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__get-relationship.js.txt +0 -61
  174. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__get.js.txt +0 -184
  175. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__patch-relationship.js.txt +0 -55
  176. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__patch.js.txt +0 -191
  177. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__post-relationship.js.txt +0 -110
  178. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__post.js.txt +0 -168
  179. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__put.js.txt +0 -253
  180. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__query.js.txt +0 -207
  181. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin-methods__release.js.txt +0 -12
  182. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-plugin.js.txt +0 -165
  183. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__rest-api-positioning-plugin.js.txt +0 -668
  184. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__core__socketio-plugin.js.txt +0 -621
  185. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__storage__local-storage.js.txt +0 -218
  186. package/audit/evidence/code/critical-pass1/json-rest-api__plugins__storage__s3-storage.js.txt +0 -124
  187. package/audit/evidence/code/critical-pass1/json-rest-schema__src__CorePlugin.js.txt +0 -269
  188. package/audit/evidence/code/critical-pass1/json-rest-schema__src__Schema.js.txt +0 -242
  189. package/audit/evidence/code/critical-pass1/json-rest-schema__src__index.js.txt +0 -77
  190. package/audit/evidence/code/critical-pass1-risk-keywords.txt +0 -238
  191. package/audit/evidence/code/critical-pass1-summary.csv +0 -67
  192. package/audit/evidence/code/critical-pass2-summary.csv +0 -67
  193. package/audit/evidence/code/early-silent-zones-no-test-token.txt +0 -57
  194. package/audit/evidence/code/error-model-signals.txt +0 -98
  195. package/audit/evidence/code/git-files-json-rest-api.txt +0 -171
  196. package/audit/evidence/code/git-files-json-rest-schema.txt +0 -27
  197. package/audit/evidence/code/hook-flow-signals.txt +0 -282
  198. package/audit/evidence/code/idproperty-signals.txt +0 -157
  199. package/audit/evidence/code/import-cycles-non-anyapi.txt +0 -3
  200. package/audit/evidence/code/import-hotspots-non-anyapi.txt +0 -96
  201. package/audit/evidence/code/imports-json-rest-api.txt +0 -354
  202. package/audit/evidence/code/imports-json-rest-schema.txt +0 -15
  203. package/audit/evidence/code/in-scope-files-json-rest-api.txt +0 -160
  204. package/audit/evidence/code/in-scope-files-json-rest-schema.txt +0 -13
  205. package/audit/evidence/code/non-anyapi-core-files.txt +0 -101
  206. package/audit/evidence/code/permission-signals.txt +0 -193
  207. package/audit/evidence/code/query-include-signals.txt +0 -687
  208. package/audit/evidence/code/transaction-signals.txt +0 -28
  209. package/audit/evidence/code/validation-signals.txt +0 -650
  210. package/audit/evidence/code/write-path-signals.txt +0 -61
  211. package/audit/evidence/docs/docs-claims-signals.txt +0 -1075
  212. package/audit/evidence/docs/schema-docs-claims-signals.txt +0 -179
  213. package/audit/evidence/external/corpus-freeze.md +0 -21
  214. package/audit/evidence/external/npm-competitor-metadata.txt +0 -70
  215. package/audit/evidence/external/npm-download-signals.txt +0 -23
  216. package/audit/evidence/external/npm-jsonapi-server.txt +0 -8
  217. package/audit/evidence/external/npm-modern-jsonapi-metadata.txt +0 -38
  218. package/audit/evidence/external/readme-fortune-signals.txt +0 -26
  219. package/audit/evidence/external/readme-fortune.md +0 -165
  220. package/audit/evidence/external/readme-json-api-serializer-signals.txt +0 -80
  221. package/audit/evidence/external/readme-json-api-serializer.md +0 -690
  222. package/audit/evidence/external/readme-jsonapi-serde-server-signals.txt +0 -0
  223. package/audit/evidence/external/readme-jsonapi-serde-server.md +0 -22
  224. package/audit/evidence/external/readme-jsonapi-serializer-signals.txt +0 -63
  225. package/audit/evidence/external/readme-jsonapi-serializer.md +0 -315
  226. package/audit/evidence/external/readme-jsonapi-server-signals.txt +0 -19
  227. package/audit/evidence/external/readme-jsonapi-server.md +0 -104
  228. package/audit/evidence/external/readme-nestjs-json-api-signals.txt +0 -4
  229. package/audit/evidence/external/readme-nestjs-json-api.md +0 -94
  230. package/audit/evidence/external/readme-yaser-json-api-nestjs-signals.txt +0 -47
  231. package/audit/evidence/external/readme-yaser-json-api-nestjs.md +0 -447
  232. package/audit/evidence/external/standard-jsonapi-snippets.txt +0 -84
  233. package/audit/evidence/external/standard-rfc-snippets.txt +0 -168
  234. package/audit/evidence/external/standards-sources.txt +0 -6
  235. package/audit/evidence/runtime/baseline-commits.txt +0 -2
  236. package/audit/evidence/runtime/db-adapter-assumptions.txt +0 -3
  237. package/audit/evidence/runtime/environment.txt +0 -4
  238. package/audit/evidence/runtime/invariant-runtime-mapping.md +0 -38
  239. package/audit/evidence/runtime/probe-patch-relationship-error.exitcode +0 -1
  240. package/audit/evidence/runtime/probe-patch-relationship-error.log +0 -76
  241. package/audit/evidence/runtime/probe-patch-relationship-error.mjs +0 -67
  242. package/audit/evidence/runtime/probe-patch-relationship-referenceerror.exitcode +0 -1
  243. package/audit/evidence/runtime/probe-patch-relationship-referenceerror.log +0 -62
  244. package/audit/evidence/runtime/probe-patch-relationship-referenceerror.mjs +0 -47
  245. package/audit/evidence/runtime/test-exitcodes.txt +0 -4
  246. package/audit/evidence/runtime/test-summary.md +0 -107
  247. package/audit/evidence/runtime/trace-anchors.txt +0 -61
  248. package/audit/evidence/tests/access-multitenancy-test-signals.txt +0 -125
  249. package/audit/evidence/tests/failing-tests-summary.txt +0 -25
  250. package/audit/evidence/tests/npm-test-json-rest-api.exitcode +0 -1
  251. package/audit/evidence/tests/npm-test-json-rest-api.log +0 -5885
  252. package/audit/evidence/tests/npm-test-json-rest-schema.exitcode +0 -1
  253. package/audit/evidence/tests/npm-test-json-rest-schema.log +0 -356
  254. package/audit/evidence/tests/query-include-test-signals.txt +0 -948
  255. package/audit/evidence/tests/relationship-test-signals.txt +0 -223
  256. package/audit/evidence/tests/skipped-tests.txt +0 -10
  257. package/audit/evidence/tests/test-suite-list-non-anyapi.txt +0 -30
  258. package/audit/evidence/tests/test-suite-list.txt +0 -32
  259. package/audit/subsystems/docs-drift.md +0 -49
  260. package/audit/subsystems/pass2-cross-review.md +0 -131
  261. package/audit/subsystems/plugins-access.md +0 -51
  262. package/audit/subsystems/plugins-bulk.md +0 -50
  263. package/audit/subsystems/plugins-cors.md +0 -48
  264. package/audit/subsystems/plugins-file.md +0 -53
  265. package/audit/subsystems/plugins-multihome.md +0 -50
  266. package/audit/subsystems/plugins-positioning.md +0 -54
  267. package/audit/subsystems/plugins-socketio.md +0 -50
  268. package/audit/subsystems/query-engine.md +0 -61
  269. package/audit/subsystems/relationships.md +0 -55
  270. package/audit/subsystems/rest-orchestration.md +0 -66
  271. package/audit/subsystems/schema-core.md +0 -64
  272. package/audit/subsystems/storage-knex.md +0 -57
  273. package/audit/subsystems/tests.md +0 -48
  274. package/audit/subsystems/transport-express.md +0 -55
  275. package/audit/traces/trace-read-get.md +0 -22
  276. package/audit/traces/trace-read-query.md +0 -25
  277. package/audit/traces/trace-relationship-endpoints.md +0 -31
  278. package/audit/traces/trace-write-delete.md +0 -17
  279. package/audit/traces/trace-write-patch.md +0 -26
  280. package/audit/traces/trace-write-post.md +0 -22
  281. package/audit/traces/trace-write-put.md +0 -23
  282. package/docs/GUIDE/GUIDE_4_Authentication_And_Permissions.md +0 -707
  283. package/docs/GUIDE/GUIDE_X_Multihome.md +0 -666
  284. package/plugins/core/lib/querying-writing/payload-validators.js +0 -1314
  285. package/plugins/core/rest-api-access.js +0 -459
  286. package/plugins/core/rest-api-multihome-plugin.js +0 -314
  287. package/tests/multihome.test.js +0 -553
  288. package/tests/multihome.test.js.bak +0 -550
  289. package/tests/ownership-optout.test.js +0 -76
  290. package/tests/rest-api-access.test.js +0 -206
@@ -0,0 +1,187 @@
1
+ import { describe, it, before, beforeEach, after } from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+ import knexLib from 'knex'
4
+ import {
5
+ cleanTables,
6
+ createJsonApiDocument,
7
+ } from './helpers/test-utils.js'
8
+ import { storageMode } from './helpers/storage-mode.js'
9
+ import { createSearchSchemaMergeApi } from './fixtures/api-configs.js'
10
+
11
+ const maybeDescribe = storageMode.isAnyApi() ? describe.skip : describe
12
+
13
+ // Create Knex instance for tests - always use SQLite in-memory
14
+ const knex = knexLib({
15
+ client: 'better-sqlite3',
16
+ connection: {
17
+ filename: ':memory:'
18
+ },
19
+ useNullAsDefault: true
20
+ })
21
+
22
+ maybeDescribe('SearchSchema Merge Behavior (Knex execution)', () => {
23
+ let api
24
+
25
+ before(async () => {
26
+ api = await createSearchSchemaMergeApi(knex)
27
+ })
28
+
29
+ after(async () => {
30
+ await knex.destroy()
31
+ })
32
+
33
+ beforeEach(async () => {
34
+ await cleanTables(knex, ['searchmerge_products', 'searchmerge_users', 'searchmerge_orders'])
35
+ })
36
+
37
+ it('should use exact matching for search:true strings unless filterOperator is explicit', async () => {
38
+ const context = {}
39
+
40
+ await api.resources.users.post({
41
+ inputRecord: createJsonApiDocument('users', {
42
+ username: 'ann',
43
+ email: 'ann@example.com',
44
+ bio: 'Writes API guides'
45
+ })
46
+ }, context)
47
+
48
+ await api.resources.users.post({
49
+ inputRecord: createJsonApiDocument('users', {
50
+ username: 'anna',
51
+ email: 'anna@example.com',
52
+ bio: 'Writing API tutorials'
53
+ })
54
+ }, context)
55
+
56
+ const usernameResults = await api.resources.users.query({
57
+ queryParams: {
58
+ filters: {
59
+ username: 'ann'
60
+ }
61
+ }
62
+ }, context)
63
+
64
+ assert.equal(usernameResults.data.length, 1, 'search:true username should use exact matching')
65
+ assert.equal(usernameResults.data[0].attributes.username, 'ann')
66
+
67
+ const bioResults = await api.resources.users.query({
68
+ queryParams: {
69
+ filters: {
70
+ bio: 'Writ'
71
+ }
72
+ }
73
+ }, context)
74
+
75
+ assert.equal(bioResults.data.length, 2, 'explicit like operator should still support partial matching')
76
+ })
77
+
78
+ it('should allow filtering with merged searchSchema fields', async () => {
79
+ const context = {}
80
+
81
+ await api.resources.products.post({
82
+ inputRecord: createJsonApiDocument('products', {
83
+ name: 'Widget A',
84
+ description: 'A great widget',
85
+ price: 50,
86
+ sku: 'WGT-001',
87
+ status: 'active'
88
+ })
89
+ }, context)
90
+
91
+ await api.resources.products.post({
92
+ inputRecord: createJsonApiDocument('products', {
93
+ name: 'Widget B',
94
+ description: 'Another widget',
95
+ price: 150,
96
+ sku: 'WGT-002',
97
+ status: 'inactive'
98
+ })
99
+ }, context)
100
+
101
+ const nameResults = await api.resources.products.query({
102
+ queryParams: {
103
+ filters: {
104
+ name: 'Widget A'
105
+ }
106
+ }
107
+ }, context)
108
+ assert.equal(nameResults.data.length, 1, 'Should find one product by name')
109
+ assert.equal(nameResults.data[0].attributes.name, 'Widget A')
110
+
111
+ const priceResults = await api.resources.products.query({
112
+ queryParams: {
113
+ filters: {
114
+ price: [40, 60]
115
+ }
116
+ }
117
+ }, context)
118
+ assert.equal(priceResults.data.length, 1, 'Should find one product in price range')
119
+ assert.equal(priceResults.data[0].attributes.price, 50)
120
+
121
+ const statusResults = await api.resources.products.query({
122
+ queryParams: {
123
+ filters: {
124
+ status: ['active']
125
+ }
126
+ }
127
+ }, context)
128
+ assert.equal(statusResults.data.length, 1, 'Should find one active product')
129
+ assert.equal(statusResults.data[0].attributes.status, 'active')
130
+
131
+ const skuResults = await api.resources.products.query({
132
+ queryParams: {
133
+ filters: {
134
+ sku: 'WGT-002'
135
+ }
136
+ }
137
+ }, context)
138
+ assert.equal(skuResults.data.length, 1, 'Should find one product by SKU')
139
+ assert.equal(skuResults.data[0].attributes.sku, 'WGT-002')
140
+ })
141
+
142
+ it('should support arbitrary public filter keys when searchSchema maps them intentionally', async () => {
143
+ const context = {}
144
+
145
+ await api.resources.products.post({
146
+ inputRecord: createJsonApiDocument('products', {
147
+ name: 'Widget Alpha',
148
+ description: 'The great all-purpose widget',
149
+ price: 50,
150
+ sku: 'WGT-101',
151
+ status: 'active'
152
+ })
153
+ }, context)
154
+
155
+ await api.resources.products.post({
156
+ inputRecord: createJsonApiDocument('products', {
157
+ name: 'Widget Beta',
158
+ description: 'A quiet replacement unit',
159
+ price: 60,
160
+ sku: 'WGT-102',
161
+ status: 'inactive'
162
+ })
163
+ }, context)
164
+
165
+ const aliasResults = await api.resources.products.query({
166
+ queryParams: {
167
+ filters: {
168
+ term: 'great'
169
+ }
170
+ }
171
+ }, context)
172
+
173
+ assert.equal(aliasResults.data.length, 1, 'term should be resolved by backend search mapping')
174
+ assert.equal(aliasResults.data[0].attributes.name, 'Widget Alpha')
175
+
176
+ const customResults = await api.resources.products.query({
177
+ queryParams: {
178
+ filters: {
179
+ availability: true
180
+ }
181
+ }
182
+ }, context)
183
+
184
+ assert.equal(customResults.data.length, 1, 'availability should be interpreted by backend custom filter logic')
185
+ assert.equal(customResults.data[0].attributes.status, 'active')
186
+ })
187
+ })
@@ -3,8 +3,6 @@ import assert from 'node:assert/strict'
3
3
  import knexLib from 'knex'
4
4
  import {
5
5
  cleanTables,
6
- createJsonApiDocument,
7
- createRelationship
8
6
  } from './helpers/test-utils.js'
9
7
  import { createSearchSchemaMergeApi } from './fixtures/api-configs.js'
10
8
 
@@ -63,11 +61,18 @@ describe('SearchSchema Merge Behavior', () => {
63
61
  assert.ok(searchSchema.structure.price, 'price field should be searchable')
64
62
  assert.equal(searchSchema.structure.price.filterOperator, 'between', 'price should use between operator from searchSchema')
65
63
 
64
+ // Check that arbitrary public filter keys are allowed when defined intentionally
65
+ assert.ok(searchSchema.structure.term, 'term alias should be searchable')
66
+ assert.deepEqual(searchSchema.structure.term.oneOf, ['name', 'description'], 'term should map to multiple fields')
67
+
66
68
  // Check that virtual fields from searchSchema are present
67
69
  assert.ok(searchSchema.structure.category_name, 'category_name virtual field should be searchable')
68
70
  assert.equal(searchSchema.structure.category_name.filterOperator, 'like', 'category_name should use like operator')
69
71
  assert.equal(searchSchema.structure.category_name.actualField, 'category.name', 'category_name should map to category.name')
70
72
 
73
+ assert.ok(searchSchema.structure.availability, 'availability custom filter should be searchable')
74
+ assert.equal(typeof searchSchema.structure.availability.applyFilter, 'function', 'availability should use custom backend logic')
75
+
71
76
  // Check explicit searchSchema field not marked with search:true
72
77
  assert.ok(searchSchema.structure.status, 'status field should be searchable from searchSchema')
73
78
  assert.equal(searchSchema.structure.status.filterOperator, 'in', 'status should use in operator')
@@ -111,72 +116,19 @@ describe('SearchSchema Merge Behavior', () => {
111
116
  assert.ok(!searchSchema.structure.total, 'total should not be searchable')
112
117
  })
113
118
 
114
- it('should allow filtering with merged searchSchema fields', async () => {
115
- const context = {}
116
-
117
- // Create some test data using API methods
118
- const product1 = await api.resources.products.post({
119
- inputRecord: createJsonApiDocument('products', {
120
- name: 'Widget A',
121
- description: 'A great widget',
122
- price: 50,
123
- sku: 'WGT-001',
124
- status: 'active'
125
- })
126
- }, context)
127
-
128
- const product2 = await api.resources.products.post({
129
- inputRecord: createJsonApiDocument('products', {
130
- name: 'Widget B',
131
- description: 'Another widget',
132
- price: 150,
133
- sku: 'WGT-002',
134
- status: 'inactive'
135
- })
136
- }, context)
137
-
138
- // Test filtering with field from search:true
139
- const nameResults = await api.resources.products.query({
140
- queryParams: {
141
- filters: {
142
- name: 'Widget A'
143
- }
144
- }
145
- }, context)
146
- assert.equal(nameResults.data.length, 1, 'Should find one product by name')
147
- assert.equal(nameResults.data[0].attributes.name, 'Widget A')
148
-
149
- // Test filtering with field from explicit searchSchema (between operator)
150
- const priceResults = await api.resources.products.query({
151
- queryParams: {
152
- filters: {
153
- price: [40, 60] // Between 40 and 60
154
- }
155
- }
156
- }, context)
157
- assert.equal(priceResults.data.length, 1, 'Should find one product in price range')
158
- assert.equal(priceResults.data[0].attributes.price, 50)
159
-
160
- // Test filtering with explicit searchSchema field (in operator)
161
- const statusResults = await api.resources.products.query({
162
- queryParams: {
163
- filters: {
164
- status: ['active']
165
- }
166
- }
167
- }, context)
168
- assert.equal(statusResults.data.length, 1, 'Should find one active product')
169
- assert.equal(statusResults.data[0].attributes.status, 'active')
170
-
171
- // Test filtering with search:true field that wasn't overridden
172
- const skuResults = await api.resources.products.query({
173
- queryParams: {
174
- filters: {
175
- sku: 'WGT-002'
176
- }
177
- }
178
- }, context)
179
- assert.equal(skuResults.data.length, 1, 'Should find one product by SKU')
180
- assert.equal(skuResults.data[0].attributes.sku, 'WGT-002')
119
+ it('should reject invalid filter keys that are not part of the public searchSchema contract', async () => {
120
+ await assert.rejects(
121
+ async () => {
122
+ await api.resources.products.query({
123
+ queryParams: {
124
+ filters: {
125
+ invalid_field: 'nope'
126
+ }
127
+ }
128
+ })
129
+ },
130
+ (error) => error?.code === 'REST_API_VALIDATION',
131
+ 'Should reject fields that are not defined in searchSchema'
132
+ )
181
133
  })
182
134
  })
@@ -0,0 +1,259 @@
1
+ import { describe, it, before, after, beforeEach } from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+ import knexLib from 'knex'
4
+ import { Api } from 'hooked-api'
5
+ import { RestApiPlugin } from '../plugins/core/rest-api-plugin.js'
6
+ import { RestApiKnexPlugin } from '../plugins/core/rest-api-knex-plugin.js'
7
+ import {
8
+ cleanTables,
9
+ createJsonApiDocument,
10
+ createRelationship,
11
+ resourceIdentifier,
12
+ assertResourceAttributes,
13
+ assertResourceRelationship,
14
+ validateJsonApiStructure,
15
+ } from './helpers/test-utils.js'
16
+
17
+ const knex = knexLib({
18
+ client: 'better-sqlite3',
19
+ connection: {
20
+ filename: ':memory:'
21
+ },
22
+ useNullAsDefault: true
23
+ })
24
+
25
+ let api
26
+
27
+ const serializeDateTimeForSql = (value) => {
28
+ if (value == null) return null
29
+ if (!(value instanceof Date)) {
30
+ throw new Error('serializeDateTimeForSql expects a Date value after schema normalization')
31
+ }
32
+
33
+ return value.toISOString().replace('T', ' ').slice(0, 19)
34
+ }
35
+
36
+ describe('Storage mapping', () => {
37
+ before(async () => {
38
+ api = new Api({
39
+ name: 'storage-mapping-test',
40
+ })
41
+
42
+ await api.use(RestApiPlugin, {
43
+ simplifiedApi: false,
44
+ simplifiedTransport: false,
45
+ returnRecordApi: {
46
+ post: 'full',
47
+ put: 'full',
48
+ patch: 'full'
49
+ },
50
+ returnRecordTransport: {
51
+ post: 'full',
52
+ put: 'full',
53
+ patch: 'full'
54
+ }
55
+ })
56
+ await api.use(RestApiKnexPlugin, { knex })
57
+
58
+ await api.addResource('countries', {
59
+ schema: {
60
+ id: { type: 'id' },
61
+ name: { type: 'string', required: true }
62
+ },
63
+ relationships: {
64
+ profiles: { type: 'hasMany', target: 'profiles', foreignKey: 'country_id' }
65
+ },
66
+ tableName: 'mapped_countries'
67
+ })
68
+ await api.resources.countries.createKnexTable()
69
+
70
+ await api.addResource('profiles', {
71
+ schema: {
72
+ id: { type: 'id' },
73
+ displayName: { type: 'string', required: true, search: true },
74
+ loginCount: { type: 'number', defaultTo: 0 },
75
+ lastSeenAt: {
76
+ type: 'dateTime',
77
+ nullable: true,
78
+ storage: {
79
+ serialize: serializeDateTimeForSql
80
+ }
81
+ },
82
+ countryId: {
83
+ type: 'id',
84
+ nullable: true,
85
+ belongsTo: 'countries',
86
+ as: 'country'
87
+ },
88
+ externalRef: { type: 'string', nullable: true, search: true, storage: { column: 'legacy_ref' } },
89
+ confirmationToken: { type: 'string', virtual: true }
90
+ },
91
+ tableName: 'mapped_profiles'
92
+ })
93
+ await api.resources.profiles.createKnexTable()
94
+
95
+ await api.addResource('verbatim_profiles', {
96
+ storage: { naming: 'exact' },
97
+ schema: {
98
+ id: { type: 'id' },
99
+ displayName: { type: 'string', required: true },
100
+ loginCount: { type: 'number', defaultTo: 0 }
101
+ },
102
+ tableName: 'verbatim_profiles'
103
+ })
104
+ await api.resources.verbatim_profiles.createKnexTable()
105
+ })
106
+
107
+ after(async () => {
108
+ await knex.destroy()
109
+ })
110
+
111
+ beforeEach(async () => {
112
+ await cleanTables(knex, ['mapped_profiles', 'mapped_countries', 'verbatim_profiles'])
113
+ })
114
+
115
+ it('persists mapped columns while exposing logical field names', async () => {
116
+ const country = await api.resources.countries.post({
117
+ inputRecord: createJsonApiDocument('countries', {
118
+ name: 'Australia'
119
+ })
120
+ })
121
+
122
+ const createResult = await api.resources.profiles.post({
123
+ inputRecord: createJsonApiDocument(
124
+ 'profiles',
125
+ {
126
+ displayName: 'Mercury',
127
+ loginCount: 7,
128
+ lastSeenAt: '2026-01-02T03:04:05Z',
129
+ externalRef: 'legacy-001',
130
+ confirmationToken: 'secret-token'
131
+ },
132
+ {
133
+ country: createRelationship(resourceIdentifier('countries', country.data.id))
134
+ }
135
+ )
136
+ })
137
+
138
+ validateJsonApiStructure(createResult)
139
+ assertResourceAttributes(createResult.data, {
140
+ displayName: 'Mercury',
141
+ loginCount: 7
142
+ })
143
+ assert.equal(createResult.data.attributes.confirmationToken, 'secret-token')
144
+ assert.ok(createResult.data.attributes.lastSeenAt instanceof Date)
145
+ assert.equal(createResult.data.attributes.lastSeenAt.toISOString(), '2026-01-02T03:04:05.000Z')
146
+ assert.ok(!('display_name' in createResult.data.attributes))
147
+ assert.ok(!('country_id' in createResult.data.attributes))
148
+
149
+ const dbRecord = await knex('mapped_profiles').first()
150
+ assert.equal(dbRecord.display_name, 'Mercury')
151
+ assert.equal(dbRecord.login_count, 7)
152
+ assert.equal(dbRecord.last_seen_at, '2026-01-02 03:04:05')
153
+ assert.equal(String(dbRecord.country_id), country.data.id)
154
+ assert.equal(dbRecord.legacy_ref, 'legacy-001')
155
+ assert.ok(!('displayName' in dbRecord))
156
+ assert.ok(!('countryId' in dbRecord))
157
+ assert.ok(!('confirmationToken' in dbRecord))
158
+
159
+ const getResult = await api.resources.profiles.get({
160
+ id: createResult.data.id,
161
+ queryParams: {
162
+ include: ['country']
163
+ }
164
+ })
165
+
166
+ validateJsonApiStructure(getResult)
167
+ assertResourceAttributes(getResult.data, {
168
+ displayName: 'Mercury',
169
+ loginCount: 7
170
+ })
171
+ assert.ok(getResult.data.attributes.lastSeenAt instanceof Date)
172
+ assert.equal(getResult.data.attributes.lastSeenAt.toISOString(), '2026-01-02T03:04:05.000Z')
173
+ assert.ok(!('display_name' in getResult.data.attributes))
174
+ assertResourceRelationship(
175
+ getResult.data,
176
+ 'country',
177
+ resourceIdentifier('countries', country.data.id)
178
+ )
179
+
180
+ const queryResult = await api.resources.profiles.query({
181
+ queryParams: {
182
+ filters: {
183
+ displayName: 'Mercury',
184
+ externalRef: 'legacy-001'
185
+ }
186
+ }
187
+ })
188
+
189
+ validateJsonApiStructure(queryResult, true)
190
+ assert.equal(queryResult.data.length, 1)
191
+ assertResourceAttributes(queryResult.data[0], {
192
+ displayName: 'Mercury',
193
+ externalRef: 'legacy-001'
194
+ })
195
+ })
196
+
197
+ it('applies storage mapping on PATCH updates and sparse fieldsets', async () => {
198
+ const created = await api.resources.profiles.post({
199
+ inputRecord: createJsonApiDocument('profiles', {
200
+ displayName: 'Before',
201
+ loginCount: 1,
202
+ lastSeenAt: '2026-01-01T00:00:00Z'
203
+ })
204
+ })
205
+
206
+ const patchResult = await api.resources.profiles.patch({
207
+ id: created.data.id,
208
+ inputRecord: {
209
+ data: {
210
+ type: 'profiles',
211
+ id: created.data.id,
212
+ attributes: {
213
+ displayName: 'After',
214
+ lastSeenAt: '2026-02-03T04:05:06Z',
215
+ confirmationToken: 'updated-token'
216
+ }
217
+ }
218
+ },
219
+ queryParams: {
220
+ fields: {
221
+ profiles: 'displayName,lastSeenAt,confirmationToken'
222
+ }
223
+ }
224
+ })
225
+
226
+ validateJsonApiStructure(patchResult)
227
+ assert.deepEqual(Object.keys(patchResult.data.attributes).sort(), ['confirmationToken', 'displayName', 'lastSeenAt'])
228
+ assert.equal(patchResult.data.attributes.displayName, 'After')
229
+ assert.equal(patchResult.data.attributes.confirmationToken, 'updated-token')
230
+ assert.ok(patchResult.data.attributes.lastSeenAt instanceof Date)
231
+ assert.equal(patchResult.data.attributes.lastSeenAt.toISOString(), '2026-02-03T04:05:06.000Z')
232
+
233
+ const dbRecord = await knex('mapped_profiles').where('id', created.data.id).first()
234
+ assert.equal(dbRecord.display_name, 'After')
235
+ assert.equal(dbRecord.last_seen_at, '2026-02-03 04:05:06')
236
+ assert.ok(!('displayName' in dbRecord))
237
+ })
238
+
239
+ it('can opt out of snake_case translation for an entire resource', async () => {
240
+ const created = await api.resources.verbatim_profiles.post({
241
+ inputRecord: createJsonApiDocument('verbatim_profiles', {
242
+ displayName: 'Exact Mode',
243
+ loginCount: 3
244
+ })
245
+ })
246
+
247
+ validateJsonApiStructure(created)
248
+ assertResourceAttributes(created.data, {
249
+ displayName: 'Exact Mode',
250
+ loginCount: 3
251
+ })
252
+
253
+ const dbRecord = await knex('verbatim_profiles').where('id', created.data.id).first()
254
+ assert.equal(dbRecord.displayName, 'Exact Mode')
255
+ assert.equal(dbRecord.loginCount, 3)
256
+ assert.equal(Object.hasOwn(dbRecord, 'display_name'), false)
257
+ assert.equal(Object.hasOwn(dbRecord, 'login_count'), false)
258
+ })
259
+ })
@@ -1,103 +0,0 @@
1
- # Technical Audit Charter
2
-
3
- ## Mission
4
- Produce a formal, evidence-driven audit of architecture quality, code quality, standards alignment, competitive positioning, and operational risk for:
5
- - `/home/merc/Development/current/json-rest-api`
6
- - `/home/merc/Development/current/json-rest-schema`
7
-
8
- ## Scope
9
- ### Included
10
- - Runtime architecture, data/control flow, and plugin interactions for non-`anyapi` code paths.
11
- - Schema compilation/validation behavior in `json-rest-schema` and its integration surface in `json-rest-api`.
12
- - Test and documentation alignment for critical behavior.
13
- - Runtime/test corroboration for risk classification.
14
-
15
- ### Explicit Exclusions
16
- - `anyapi` implementation and behavior are fully out-of-scope for conclusions, scoring, and recommendations.
17
- - Excluded path classes (json-rest-api):
18
- - `plugins/core/lib/anyapi/**`
19
- - `plugins/core/rest-api-anyapi-knex-plugin.js`
20
- - `tests/anyapi-*.test.js`
21
- - `scripts/*anyapi*`
22
-
23
- ## Baseline Freeze
24
- - Baseline commits: `audit/evidence/runtime/baseline-commits.txt`
25
- - Environment metadata: `audit/evidence/runtime/environment.txt`
26
- - DB adapter assumptions: `audit/evidence/runtime/db-adapter-assumptions.txt`
27
- - Standards/competitor corpus freeze: `audit/evidence/external/corpus-freeze.md`
28
-
29
- ## Evidence Policy
30
- 1. No claim without file-level and/or runtime/test evidence reference.
31
- 2. No high-severity risk without corroborating runtime/test signal.
32
- 3. Critical files require dual-pass review (pass 1 + cross-review pass 2).
33
- 4. Assertions must be tagged as:
34
- - `Verified`: directly confirmed by code/runtime/test evidence.
35
- - `Inferred`: logically derived from verified evidence.
36
- - `Unknown`: evidence missing or inconclusive.
37
- 5. Unknowns are tracked explicitly in subsystem reports and findings.
38
-
39
- ## Severity Model
40
- - Inputs:
41
- - Impact: `1-5`
42
- - Likelihood: `1-5`
43
- - Detectability: `1-5` (higher means easier to detect)
44
- - Formula:
45
- - `severity_score = impact * likelihood * (6 - detectability)`
46
- - Range: `1..125`
47
- - Bands:
48
- - `High`: `>= 60`
49
- - `Medium`: `30-59`
50
- - `Low`: `< 30`
51
-
52
- ## Confidence Model
53
- - `C1 Very Low`: weak signal, mostly inferred.
54
- - `C2 Low`: limited direct evidence.
55
- - `C3 Medium`: direct code evidence + partial corroboration.
56
- - `C4 High`: direct code evidence + test/runtime corroboration.
57
- - `C5 Very High`: repeated corroboration across code, runtime, and tests.
58
-
59
- ## Scoring Model
60
- Each major dimension scored `1-5`, evidence-backed:
61
- - Correctness
62
- - Security
63
- - Resilience
64
- - Performance
65
- - Maintainability
66
- - Observability
67
- - Test quality
68
-
69
- Aggregate score is reported as profile (not single opaque number) plus weighted composite:
70
- - Correctness `20%`
71
- - Security `20%`
72
- - Resilience `15%`
73
- - Performance `15%`
74
- - Maintainability `15%`
75
- - Observability `5%`
76
- - Test quality `10%`
77
-
78
- ## Deliverables
79
- - `audit/00-charter.md`
80
- - `audit/01-scope-map.md`
81
- - `audit/02-coverage-matrix.csv`
82
- - `audit/03-invariants.md`
83
- - `audit/04-standards-rubric.md`
84
- - `audit/05-competitor-rubric.md`
85
- - `audit/06-findings.md`
86
- - `audit/07-risk-register.csv`
87
- - `audit/08-remediation-roadmap.md`
88
- - `audit/subsystems/*.md`
89
- - `audit/traces/*.md`
90
- - `audit/evidence/**`
91
-
92
- ## Signoff Criteria
93
- 1. 100% critical-file dual-pass coverage.
94
- 2. 100% invariants not left unknown in final state.
95
- 3. 100% high-severity risks have mitigation + verification test.
96
- 4. Standards and competitor matrices complete with evidence.
97
- 5. Prioritized remediation roadmap with exit criteria.
98
- 6. Final synthesis includes residual risk and confidence summary.
99
-
100
- ## Reproducibility Commands (Baseline)
101
- - `git rev-parse HEAD` in each repo.
102
- - `node -v && npm -v && uname -a`
103
- - `git ls-files` inventories captured under `audit/evidence/code/`.