@galadrim/galadmin 0.2.11 → 0.3.0-alpha.2.1

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 (233) hide show
  1. package/.agents/report/blockers.json +1 -0
  2. package/.agents/report/failures/2026-09-23-api-user-filter-contract.md +31 -0
  3. package/.agents/report/failures/2026-09-23-api-values-contract.md +25 -0
  4. package/.agents/report/failures/2026-10-01-cycle-02-create-callback-contract.md +17 -0
  5. package/.agents/report/failures/2026-10-01-cycle-06-delete-callback-id-contract.md +17 -0
  6. package/.agents/report/failures/2026-10-01-cycle-07-panel-delete-callback-id-contract.md +24 -0
  7. package/.agents/report/failures/2026-10-01-cycle-13-update-callback-id-contract.md +17 -0
  8. package/.agents/report/failures/2026-10-01-cycle-15-rich-text-upload-boundary-contract.md +24 -0
  9. package/.agents/report/failures/2026-10-03-cycle-06-record-import-parser-contract.md +11 -0
  10. package/.agents/report/failures/2026-10-03-cycle-07-panel-import-parser-contract.md +24 -0
  11. package/.agents/report/failures/2026-10-07-resume-cycle-02-api-assembly-contract.md +46 -0
  12. package/.agents/report/port/2026-09-23-api-config-enrichment.md +13 -0
  13. package/.agents/report/port/2026-09-23-api-file-upload.md +11 -0
  14. package/.agents/report/port/2026-09-23-api-query-authorization.md +14 -0
  15. package/.agents/report/port/2026-09-23-api-request-configuration.md +11 -0
  16. package/.agents/report/port/2026-09-23-database-manager.md +13 -0
  17. package/.agents/report/port/2026-10-01-api-adjacent-record-id.md +9 -0
  18. package/.agents/report/port/2026-10-01-cycle-01-api-config-route.md +9 -0
  19. package/.agents/report/port/2026-10-01-cycle-03-custom-action.md +9 -0
  20. package/.agents/report/port/2026-10-01-cycle-04-custom-component.md +7 -0
  21. package/.agents/report/port/2026-10-01-cycle-05-custom-query.md +7 -0
  22. package/.agents/report/port/2026-10-01-cycle-08-bulk-delete.md +9 -0
  23. package/.agents/report/port/2026-10-01-cycle-09-duplicate-record.md +9 -0
  24. package/.agents/report/port/2026-10-01-cycle-10-notification-badges.md +9 -0
  25. package/.agents/report/port/2026-10-01-cycle-11-record.md +7 -0
  26. package/.agents/report/port/2026-10-01-cycle-12-search-companies.md +11 -0
  27. package/.agents/report/port/2026-10-01-cycle-14-upload-file.md +7 -0
  28. package/.agents/report/port/2026-10-03-cycle-01-create-record.md +11 -0
  29. package/.agents/report/port/2026-10-03-cycle-02-delete-record.md +11 -0
  30. package/.agents/report/port/2026-10-03-cycle-03-panel-delete-record.md +11 -0
  31. package/.agents/report/port/2026-10-03-cycle-04-update-record.md +11 -0
  32. package/.agents/report/port/2026-10-03-cycle-05-api-values.md +11 -0
  33. package/.agents/report/port/2026-10-06-cycle-01-record-import.md +9 -0
  34. package/.agents/report/port/2026-10-06-cycle-03-rich-text-upload.md +7 -0
  35. package/.agents/report/port/2026-10-06-cycle-04-user-filters.md +11 -0
  36. package/.agents/report/port/2026-10-06-resume-cycle-01-panel-import.md +9 -0
  37. package/.agents/report/port/2026-10-07-cycle-01-api-assembly.md +16 -0
  38. package/.agents/report/port/2026-10-07-cycle-02-index-entry-point.md +13 -0
  39. package/.agents/report/remediation/2026-10-02-api-user-filter-remediation.md +71 -0
  40. package/.agents/report/remediation/2026-10-02-api-values-remediation.md +17 -0
  41. package/.agents/report/remediation/2026-10-03-callback-id-contract-remediation.md +36 -0
  42. package/.agents/report/remediation/2026-10-06-import-parser-remediation.md +41 -0
  43. package/.agents/report/remediation/2026-10-06-rich-text-upload-remediation.md +33 -0
  44. package/.agents/report/remediation/2026-10-07-api-assembly-remediation.md +32 -0
  45. package/.agents/skills/port-javascript-to-typescript/SKILL.md +42 -0
  46. package/.agents/skills/port-javascript-to-typescript/agents/openai.yaml +3 -0
  47. package/.agents/skills/port-javascript-to-typescript/references/blockers.md +31 -0
  48. package/.agents/skills/port-javascript-to-typescript/references/planning.md +43 -0
  49. package/.agents/skills/port-javascript-to-typescript/references/porting.md +9 -0
  50. package/.agents/skills/port-javascript-to-typescript/references/reporting.md +24 -0
  51. package/.agents/skills/port-javascript-to-typescript/references/rules.md +8 -0
  52. package/.agents/skills/port-javascript-to-typescript/references/selection.md +16 -0
  53. package/.agents/skills/port-javascript-to-typescript/references/tools.md +20 -0
  54. package/.agents/skills/port-javascript-to-typescript/scripts/check.sh +17 -0
  55. package/.agents/skills/port-javascript-to-typescript/scripts/graph.sh +30 -0
  56. package/.agents/skills/port-javascript-to-typescript/scripts/madge.json +12 -0
  57. package/.agents/skills/port-javascript-to-typescript/scripts/oxlint.json +14 -0
  58. package/.agents/skills/port-javascript-to-typescript/scripts/test-tools.cjs +76 -0
  59. package/.github/actions/version-bump/action.yml +41 -0
  60. package/.github/workflows/alpha.yml +53 -0
  61. package/.github/workflows/ci.yml +8 -9
  62. package/.github/workflows/main.yml +13 -14
  63. package/AGENTS.md +5 -0
  64. package/dist/api/authorization.d.ts +38 -0
  65. package/dist/api/authorization.js +74 -0
  66. package/dist/api/authorization.js.map +1 -0
  67. package/dist/api/config.d.ts +42 -0
  68. package/dist/api/config.js +105 -0
  69. package/dist/api/config.js.map +1 -0
  70. package/dist/api/filterUser.d.ts +2 -0
  71. package/dist/api/filterUser.js +24 -0
  72. package/dist/api/filterUser.js.map +1 -0
  73. package/dist/api/importRecords.d.ts +1 -0
  74. package/dist/api/importRecords.js +16 -0
  75. package/dist/api/importRecords.js.map +1 -0
  76. package/dist/api/queries.d.ts +48 -0
  77. package/dist/api/queries.js +139 -0
  78. package/dist/api/queries.js.map +1 -0
  79. package/dist/api/request.d.ts +29 -0
  80. package/dist/api/request.js +3 -0
  81. package/dist/api/request.js.map +1 -0
  82. package/dist/api/routes/adjacentRecordId.d.ts +10 -0
  83. package/dist/api/routes/adjacentRecordId.js +13 -0
  84. package/dist/api/routes/adjacentRecordId.js.map +1 -0
  85. package/dist/api/routes/config.d.ts +3 -0
  86. package/dist/api/routes/config.js +27 -0
  87. package/dist/api/routes/config.js.map +1 -0
  88. package/dist/api/routes/createRecord.d.ts +19 -0
  89. package/dist/api/routes/createRecord.js +93 -0
  90. package/dist/api/routes/createRecord.js.map +1 -0
  91. package/dist/api/routes/customAction.d.ts +17 -0
  92. package/dist/api/routes/customAction.js +35 -0
  93. package/dist/api/routes/customAction.js.map +1 -0
  94. package/dist/api/routes/customComponent.d.ts +3 -0
  95. package/dist/api/routes/customComponent.js +34 -0
  96. package/dist/api/routes/customComponent.js.map +1 -0
  97. package/dist/api/routes/customQuery.d.ts +7 -0
  98. package/dist/api/routes/customQuery.js +33 -0
  99. package/dist/api/routes/customQuery.js.map +1 -0
  100. package/dist/api/routes/deleteRecord.d.ts +9 -0
  101. package/dist/api/routes/deleteRecord.js +46 -0
  102. package/dist/api/routes/deleteRecord.js.map +1 -0
  103. package/dist/api/routes/deleteRecordFromPanel.d.ts +10 -0
  104. package/dist/api/routes/deleteRecordFromPanel.js +36 -0
  105. package/dist/api/routes/deleteRecordFromPanel.js.map +1 -0
  106. package/dist/api/routes/deleteRecords.d.ts +9 -0
  107. package/dist/api/routes/deleteRecords.js +12 -0
  108. package/dist/api/routes/deleteRecords.js.map +1 -0
  109. package/dist/api/routes/duplicateRecord.d.ts +17 -0
  110. package/dist/api/routes/duplicateRecord.js +55 -0
  111. package/dist/api/routes/duplicateRecord.js.map +1 -0
  112. package/dist/api/routes/foreignSelectRecords.d.ts +10 -0
  113. package/dist/api/routes/foreignSelectRecords.js +61 -0
  114. package/dist/api/routes/foreignSelectRecords.js.map +1 -0
  115. package/dist/api/routes/notificationBadges.d.ts +6 -0
  116. package/dist/api/routes/notificationBadges.js +31 -0
  117. package/dist/api/routes/notificationBadges.js.map +1 -0
  118. package/dist/api/routes/record.d.ts +7 -0
  119. package/dist/api/routes/record.js +32 -0
  120. package/dist/api/routes/record.js.map +1 -0
  121. package/dist/api/routes/records.d.ts +14 -0
  122. package/dist/api/routes/records.js +57 -0
  123. package/dist/api/routes/records.js.map +1 -0
  124. package/dist/api/routes/recordsExport.d.ts +13 -0
  125. package/dist/api/routes/recordsExport.js +67 -0
  126. package/dist/api/routes/recordsExport.js.map +1 -0
  127. package/dist/api/routes/recordsImport.d.ts +4 -0
  128. package/dist/api/routes/recordsImport.js +100 -0
  129. package/dist/api/routes/recordsImport.js.map +1 -0
  130. package/dist/api/routes/searchCompanies.d.ts +17 -0
  131. package/dist/api/routes/searchCompanies.js +72 -0
  132. package/dist/api/routes/searchCompanies.js.map +1 -0
  133. package/dist/api/routes/subrecordsImport.d.ts +4 -0
  134. package/dist/api/routes/subrecordsImport.js +94 -0
  135. package/dist/api/routes/subrecordsImport.js.map +1 -0
  136. package/dist/api/routes/updateRecord.d.ts +13 -0
  137. package/dist/api/routes/updateRecord.js +55 -0
  138. package/dist/api/routes/updateRecord.js.map +1 -0
  139. package/dist/api/routes/uploadFile.d.ts +3 -0
  140. package/dist/api/routes/uploadFile.js +13 -0
  141. package/dist/api/routes/uploadFile.js.map +1 -0
  142. package/dist/api/routes/uploadFileFromBetterRichTextInput.d.ts +3 -0
  143. package/dist/api/routes/uploadFileFromBetterRichTextInput.js +33 -0
  144. package/dist/api/routes/uploadFileFromBetterRichTextInput.js.map +1 -0
  145. package/dist/api/uploadFile.d.ts +4 -0
  146. package/dist/api/uploadFile.js +209 -0
  147. package/dist/api/uploadFile.js.map +1 -0
  148. package/dist/api/values.d.ts +6 -0
  149. package/dist/api/values.js +88 -0
  150. package/dist/api/values.js.map +1 -0
  151. package/dist/api.d.ts +8 -27
  152. package/dist/api.js +80 -1387
  153. package/dist/api.js.map +1 -1
  154. package/dist/index.d.ts +2 -2
  155. package/dist/index.js +8 -2
  156. package/dist/index.js.map +1 -1
  157. package/dist/tsconfig.strict.tsbuildinfo +1 -0
  158. package/dist/types/config.d.ts +15 -5
  159. package/dist/types/config.js +4 -0
  160. package/dist/types/config.js.map +1 -1
  161. package/dist/types/database.d.ts +1 -0
  162. package/dist/types/database.js +3 -0
  163. package/dist/types/database.js.map +1 -0
  164. package/dist/utils/dbManager.d.ts +32 -7
  165. package/dist/utils/dbManager.js +59 -7
  166. package/dist/utils/dbManager.js.map +1 -1
  167. package/package.json +12 -3
  168. package/src/api/authorization.ts +129 -0
  169. package/src/api/config.ts +152 -0
  170. package/src/api/filterUser.ts +28 -0
  171. package/src/api/importRecords.ts +16 -0
  172. package/src/api/queries.ts +194 -0
  173. package/src/api/request.ts +31 -0
  174. package/src/api/routes/adjacentRecordId.ts +20 -0
  175. package/src/api/routes/config.ts +15 -0
  176. package/src/api/routes/createRecord.ts +131 -0
  177. package/src/api/routes/customAction.ts +60 -0
  178. package/src/api/routes/customComponent.ts +44 -0
  179. package/src/api/routes/customQuery.ts +53 -0
  180. package/src/api/routes/deleteRecord.ts +59 -0
  181. package/src/api/routes/deleteRecordFromPanel.ts +58 -0
  182. package/src/api/routes/deleteRecords.ts +28 -0
  183. package/src/api/routes/duplicateRecord.ts +73 -0
  184. package/src/api/routes/foreignSelectRecords.ts +80 -0
  185. package/src/api/routes/notificationBadges.ts +47 -0
  186. package/src/api/routes/record.ts +48 -0
  187. package/src/api/routes/records.ts +91 -0
  188. package/src/api/routes/recordsExport.ts +92 -0
  189. package/src/api/routes/recordsImport.ts +115 -0
  190. package/src/api/routes/searchCompanies.ts +96 -0
  191. package/src/api/routes/subrecordsImport.ts +114 -0
  192. package/src/api/routes/updateRecord.ts +74 -0
  193. package/src/api/routes/uploadFile.ts +16 -0
  194. package/src/api/routes/uploadFileFromBetterRichTextInput.ts +41 -0
  195. package/src/api/uploadFile.ts +249 -0
  196. package/src/api/values.ts +96 -0
  197. package/src/api.ts +94 -1580
  198. package/src/front/ckeditor5-build/node_modules/semver/bin/semver.js +0 -0
  199. package/src/index.ts +42 -25
  200. package/src/types/config.ts +15 -5
  201. package/src/types/database.ts +2 -0
  202. package/src/utils/dbManager.ts +99 -14
  203. package/tests/api-helpers.test.ts +59 -0
  204. package/tests/dbManager.test.ts +16 -1
  205. package/tests/helpers/fakeDb.ts +9 -7
  206. package/tests/integration/authorizationBoundary.integration.test.ts +57 -0
  207. package/tests/integration/configEnrichment.integration.test.ts +79 -0
  208. package/tests/integration/customComponentBoundary.integration.test.ts +58 -0
  209. package/tests/integration/dbManager.integration.test.ts +105 -3
  210. package/tests/integration/importParserChild.cjs +55 -0
  211. package/tests/integration/indexRuntime.integration.test.ts +22 -0
  212. package/tests/integration/indexRuntimeChild.cjs +110 -0
  213. package/tests/integration/queries.integration.test.ts +88 -0
  214. package/tests/integration/requestConfig.integration.test.ts +118 -0
  215. package/tests/integration/routes.authorization.integration.test.ts +1 -0
  216. package/tests/integration/routes.config.integration.test.ts +39 -1
  217. package/tests/integration/routes.crud.integration.test.ts +233 -1
  218. package/tests/integration/routes.custom.integration.test.ts +119 -0
  219. package/tests/integration/routes.foreign.integration.test.ts +3 -2
  220. package/tests/integration/routes.importExport.integration.test.ts +308 -6
  221. package/tests/integration/routes.integration.test.ts +4 -0
  222. package/tests/integration/routes.records.integration.test.ts +82 -6
  223. package/tests/integration/routes.upload.integration.test.ts +123 -0
  224. package/tests/integration/userFilters.integration.test.ts +225 -0
  225. package/tsconfig.json +1 -1
  226. package/tsconfig.strict.json +45 -0
  227. package/dist/front/ckeditor5-build/src/ckeditor.d.ts +0 -43
  228. package/dist/front/ckeditor5-build/src/ckeditor.js +0 -130
  229. package/dist/front/ckeditor5-build/src/ckeditor.js.map +0 -1
  230. package/dist/tsconfig.tsbuildinfo +0 -1
  231. package/src/front/ckeditor5-build/node_modules/.bin/semver +0 -12
  232. package/src/front/ckeditor5-build/node_modules/.bin/semver.cmd +0 -17
  233. package/src/front/ckeditor5-build/node_modules/.bin/semver.ps1 +0 -28
@@ -0,0 +1,11 @@
1
+ # Configured user-filter contracts — cycle 4
2
+
3
+ Scope: `src/api/routes/foreignSelectRecords.ts`, `src/api/routes/records.ts`, `src/api/routes/recordsExport.ts` and shared user declarations/constructor. These routes scope foreign options, record lists and exports through configured callbacks. Outcome: accepted strict coverage, resolving the [prior user-filter failures](../failures/2026-09-23-api-user-filter-contract.md) with [revised identifier and session guidance](../remediation/2026-10-02-api-user-filter-remediation.md).
4
+
5
+ **type:** [src/types/database.ts:2](../../../src/types/database.ts#L2) defines `DatabaseId = string | number`, reused by `TrustedUser.userId`. [src/types/config.ts:5](../../../src/types/config.ts#L5) defines `RootUser`, `RegularUser` and `FilterUser`; `isRegularUser` narrows established callback users. All three configured `filtersFromUser` declarations now accept one `FilterUser` object. [src/api/filterUser.ts:7](../../../src/api/filterUser.ts#L7) checks unknown session input and constructs that domain object without assertions, coercion or session mutation. Routes use established local request-body and database/query contracts; erased lookup assertions preserve original string indexing and optional configuration behavior.
6
+
7
+ **attention:** the marked [session constructor](../../../src/api/filterUser.ts#L3) and filter branches in [foreign options](../../../src/api/routes/foreignSelectRecords.ts#L39), [record lists](../../../src/api/routes/records.ts#L36) and [exports](../../../src/api/routes/recordsExport.ts#L38) implement the authorized breaking callback change from `(userId, role)` to `(user)`. Root callbacks receive only `{ role: "root" }`; regular users retain exact string/numeric IDs, or receive `{ role }` for absent/undefined IDs. Invalid filtered sessions return HTTP 401 before callback/data query. Existing callbacks must adopt the object contract and explicitly handle root, missing IDs and string identifiers; affected repository fixtures are migrated. No legacy overload is introduced.
8
+
9
+ The constructor validates object/role/ID shapes only at a configured filter boundary. Root treatment ignores IDs; regular string/number values are preserved without finite, positive, formatting or normalization restrictions. Routes without filters do not inspect the session. Callbacks retain their receiver, getter/invocation count, failure propagation and placement after original preceding table/body/filter evaluation. Other view/subview/request filters, authorization order and query/render behavior remain covered. Real-database tests verify SQL string escaping and matching list/export/foreign scoping, frozen-session identity, zero data-query calls on invalid users, and callback/error/evaluation ordering. Original characterization passed 281 tests and failed only 102 named authorized policy assertions.
10
+
11
+ **checks:** ordinary build, strict `--noEmit`, compiler closure, 149 unit tests, 902 real-database integration tests across 17 suites and planner review pass; 4 preexisting skips excluded. Warning scan: 15 route non-null assertions reviewed against declarations/producers; 27 existing config `any` declarations unchanged; no added `any` or suppression. Complete plan, original/final test logs, diff, checked/reviewed hashes and review: `/tmp/ts-port-20261006/cycle04/` (session-local). The independent panel-roles blocker remains unresolved.
@@ -0,0 +1,9 @@
1
+ # Panel import — resumed cycle 1
2
+
3
+ Scope: `src/api/routes/subrecordsImport.ts`, which imports configured parser output into a parent record's panel table. Outcome: accepted strict coverage, resolving the [panel import failures](../failures/2026-10-03-cycle-07-panel-import-parser-contract.md) using the [approved parser and panel-role contracts](../remediation/2026-10-06-import-parser-remediation.md).
4
+
5
+ **type:** [src/types/config.ts:301](../../../src/types/config.ts#L301) shares `BaseTypeView`'s `roles?: string[]` declaration through `BaseTypePanel` and its request representation. The route reuses `DbManager` and the existing checked `Record<string, unknown>[]` parser boundary. Erased multipart/index, initialized-driver, and mutation-result assertions preserve original property access and response behavior; no new `any` or suppression is added.
6
+
7
+ **attention:** the marked [src/api/routes/subrecordsImport.ts:50](../../../src/api/routes/subrecordsImport.ts#L50) rejects non-array parser results and primitive, null, undefined, array, function, or sparse-hole elements with HTTP 400 before insertion. Shape validation is necessary to establish the approved record-access contract. Valid array/record/field identities, custom prototypes, inherited enumeration, getter timing, parser receiver and exact parent arguments remain unchanged. Authorization still checks view before panel and bypasses role restrictions for root; the roles declaration adds no runtime validation. Parser exceptions and database/insertion failures retain their prior behavior. PostgreSQL's existing panel SQL incompatibility remains characterized as HTTP 500.
8
+
9
+ **checks:** ordinary build, strict `--noEmit`, compiler closure, 149 unit tests, 989 real-database integration tests across 17 suites, warning assessment, and planner review pass; 4 preexisting skipped tests excluded. Original-source characterization passed 156 preservation tests and failed only 48 authorized sanitization assertions. Warning scan: 13 route non-null assertions justified against producers/guards; 27 existing configuration `any` declarations unchanged. Plan, original/final logs, complete diff, checked/reviewed hashes, and erased-runtime comparison: `/tmp/ts-port-resume-20261006/cycle01/` (session-local).
@@ -0,0 +1,16 @@
1
+ # API assembly — cycle 1
2
+
3
+ Scope: `src/api.ts`, which filters request configuration and registers API routes. Outcome: accepted strict coverage. This resolves the [previous API assembly failure](../failures/2026-10-07-resume-cycle-02-api-assembly-contract.md) under the [approved remediation](../remediation/2026-10-07-api-assembly-remediation.md).
4
+
5
+ **type:** `src/api.ts:56` gives the factory `DbManager` and `Config` parameters. `Column & StandardColumn` at [src/api.ts:103](../../../src/api.ts#L103) permits an optional name without requiring one. The read-only branch retains its literal `canCreate: false` type. Eight erased assertions preserve existing session and configuration access. The legacy Express session boundary remains unchanged; no new production `any` is added. The upstream `FakeDb` fix passes the typed factory without another adapter.
6
+
7
+ **attention:** the marker at [src/api.ts:105](../../../src/api.ts#L105) records the sole runtime change: exclude null and undefined from `__hiddenColumns`. The original optional-name producer could not establish the existing `string[]` contract. The approved filter establishes it without changing column enrichment or authorization helpers.
8
+
9
+ | Restricted column name | Hidden-name entry after the change | Effect |
10
+ | --- | --- | --- |
11
+ | `undefined` or `null` value | Removed | A missing name no longer strips or rejects a literal property named `"undefined"` or `"null"`. |
12
+ | Any string, including `""`, `"undefined"`, or `"null"` | Retained | Named restrictions keep their existing read and write behavior. |
13
+
14
+ The source column stays unchanged. Name getters still run at the original mapping point; the added filter reads mapped values only. Route registration, view filtering, read-only flags, session reads, import comparisons, and error behavior remain unchanged. Real-database tests check hidden metadata, GET responses, UPDATE status, and stored rows.
15
+
16
+ **checks:** build, strict `--noEmit`, compiler closure, warning assessment, 149 unit tests, 992 integration tests across 17 suites, and planner review pass; 4 preexisting skipped tests excluded. Original characterization passed 225 checks and failed only the two approved nullish-policy assertions. All eight scan warnings are the justified session/configuration assertions. Independent transpilation confirms only the nullish-name filter changes runtime code. Plan, original/final logs, diff, hashes, and review: `/tmp/ts-port-20261007/cycle01/` (session-local).
@@ -0,0 +1,13 @@
1
+ # Application entry point — cycle 2
2
+
3
+ Scope: `src/index.ts`, which creates the Express app, session store, authentication handlers, and static-file routes. Outcome: accepted strict coverage for one backend source file.
4
+
5
+ **type:** the local `MySQLSessionStoreConstructor` at [src/index.ts:22](../../../src/index.ts#L22) retains the declared callback constructor and adds the runtime-supported `mysql2/promise.Pool` overload, returning `session.Store`. The existing constructor call uses one narrow assertion; the actual store supports promise queries and real MySQL tests verify persistence and logout. The factory at [src/index.ts:27](../../../src/index.ts#L27) now infers `express.Express` instead of `any`. `passwordMatch` at [src/index.ts:93](../../../src/index.ts#L93) accepts the existing optional `boolean | undefined` flag. The login candidate at [src/index.ts:124](../../../src/index.ts#L124) is `DatabaseRow | undefined`, retaining the selected row object and configured ID value.
6
+
7
+ Eighteen erased non-null assertions preserve the existing session, configuration, and MIME accesses: five MySQL fields, one trusted-auth callback, nine session accesses, one role loop, and two MIME inputs. They preserve existing failures for invalid configuration and unknown MIME types. The legacy Express session input contract remains unchanged. No new production `any`, double assertion, suppression, or ambient shim is added.
8
+
9
+ **attention:** no runtime change and no new `#PORTING-EDIT` marker. Independent emitted-JavaScript comparison is identical. Existing authentication guards, configuration reads, callback receiver, registration order, object identity, static headers, and error behavior stay unchanged. The new real-MySQL characterization checks persisted sessions, logout deletion, trusted-auth revocation, text substitution, PNG bytes, and the existing unknown-MIME HTTP 500.
10
+
11
+ Exact development declarations are added for `@types/express-mysql-session` 3.0.8, `@types/connect-pg-simple` 7.0.3, and `@types/bcryptjs` 2.4.6. All existing dependency lock entries remain unchanged; all nine added packages are development dependencies. The isolated runtime test loader characterizes the original source despite its incomplete store declaration; ordinary build and strict compilation verify the final source separately.
12
+
13
+ **checks:** build, strict `--noEmit`, compiler closure, warning assessment, 149 unit tests, 993 integration tests across 18 suites, diff check, and planner review pass; four preexisting skipped tests excluded. Original characterization passed one focused integration test with no skips. All 18 scan warnings are the justified erased assertions. Plan, original/final logs, dependency comparison, runtime comparison, complete diff, hashes, and review: `/tmp/ts-port-20261007/cycle02/` (session-local).
@@ -0,0 +1,71 @@
1
+ # API user filter remediation
2
+
3
+ Scope: `src/api/routes/records.ts`, `src/api/routes/foreignSelectRecords.ts`, and `src/api/routes/recordsExport.ts`, which apply configured user filters to lists, foreign options, and exports. Supporting contracts are in `src/types/config.ts`; the shared identifier type belongs in `src/types/database.ts`.
4
+
5
+ Date: 2026-10-02; revised 2026-10-06. Decision: user-approved guidance for a migration retry. This revision supersedes the numeric-only regular-user policy and addresses the October 3 failed retry.
6
+
7
+ Failure: [API user filter contract, including the October 3 retry](../failures/2026-09-23-api-user-filter-contract.md).
8
+
9
+ **type:** introduce the shared database identifier type in `src/types/database.ts`:
10
+
11
+ ```ts
12
+ /** A supported database identifier: numeric, string, or UUID. */
13
+ export type DatabaseId = string | number;
14
+ ```
15
+
16
+ This type represents identifier values, not column names or array indices. Absence belongs to the consuming contract through an optional property or explicit union; do not include null or undefined in DatabaseId. Preserve numeric and string IDs exactly, including UUIDs and numeric strings. Do not convert, trim, parse, or fabricate IDs.
17
+
18
+ In `src/types/config.ts`, import DatabaseId with `import type`, reuse it for `TrustedUser.userId?: DatabaseId`, and define the filter types:
19
+
20
+ ```ts
21
+ export type RootUser = { role: "root" };
22
+ export type RegularUser = { role: string; userId?: DatabaseId };
23
+ export type FilterUser = RootUser | RegularUser;
24
+
25
+ export function isRegularUser(user: FilterUser): user is RegularUser {
26
+ return user.role !== "root";
27
+ }
28
+ ```
29
+
30
+ The runtime constructor must always give a "root" role root treatment; RegularUser.role is a string and does not statically exclude "root". The guard narrows an already established FilterUser; it does not validate unchecked session data.
31
+
32
+ The public callback contract becomes:
33
+
34
+ ```ts
35
+ filtersFromUser?: (user: FilterUser) => string;
36
+ ```
37
+
38
+ **policy:** invoke configured filters for both root and regular sessions.
39
+
40
+ - Root callbacks receive `{ role: "root" }`, even when the session also contains an ID. Each callback defines its root filter; returning `""` adds no user filter.
41
+ - Regular callbacks receive `{ role, userId }` when userId is a string or number, with the exact original value.
42
+ - A regular user with missing or undefined userId receives `{ role }`. This is supported by the existing TrustedUser contract and does not by itself invalidate authentication. The callback must explicitly decide whether its access policy can operate without an ID.
43
+ - Preserve other view, column, subview, and request filters. Never bypass a configured filter because an ID is absent or invalid.
44
+
45
+ An owner-scoped callback may explicitly deny access without an ID:
46
+
47
+ ```ts
48
+ filtersFromUser: (user) => {
49
+ if (!isRegularUser(user)) return "";
50
+ if (user.userId === undefined) return "1 = 0";
51
+ return ownerFilter(user.userId);
52
+ }
53
+ ```
54
+
55
+ Here ownerFilter is illustrative application code, not a new library helper. It must correctly escape supported string/numeric identifiers for the configured database. Do not reuse the previous raw numeric SQL interpolation for arbitrary string IDs. Applications may instead define role-based access for regular users without IDs.
56
+
57
+ **attention:** validate unchecked session input before constructing a FilterUser for a configured callback. Require a non-null, non-array object and a string role. A "root" role takes precedence over the ID. For a regular role, accept absent/undefined userId, string IDs, and numeric IDs; reject null, boolean, array, object, bigint, or other unsupported ID types. Do not impose integer, positive-number, UUID-format, or string-normalization requirements as part of this retry.
58
+
59
+ When a configured filter cannot receive a valid FilterUser, return HTTP 401 before invoking that filter or executing its data query. Do not silently omit the filter, invent a root identity, or pass invalid input through an assertion. Apply this behavior consistently to all three routes. Validate only at the configured filter boundary; retain existing authorization ordering and ordinary behavior for routes without configured user filters.
60
+
61
+ This revision explicitly authorizes that local rejection behavior. Place the required #PORTING-EDIT marker immediately before each runtime change, documenting the reason and changed response/query behavior. Do not destroy or mutate the stored session, change login or trustedAuth behavior, add global authentication validation, or redesign session revalidation in this retry.
62
+
63
+ **compatibility:** the user authorizes the breaking change from `(userId, role)` to one FilterUser argument. Update all three declarations, all three route calls, and affected repository test callbacks. Required-number consumers must migrate to the object argument, handle root and absent IDs explicitly, and narrow numeric versus string IDs when their application requires it. Do not add a legacy overload or infer callback signatures at runtime.
64
+
65
+ DatabaseId is reusable for other primary-key contracts, but this retry only introduces it and adopts it in the filter and TrustedUser contracts. Do not replace generic DatabaseRow values, column-name fields such as primaryId, request view indices, or unrelated callback contracts. The known create/edit/delete callback mismatches and PostgreSQL's absent insertion ID still require their own policy; this document does not remove the issue #45 exceptions.
66
+
67
+ **retry:** use a shared, checked session-to-FilterUser constructor for the three routes, with unknown confined to that boundary. Validate every promised property and construct the approved domain object through normal narrowing. Preserve callback receiver and existing invocation/error behavior for valid users. Do not add any, unchecked assertions, suppression comments, or weaken compiler settings.
68
+
69
+ Set this document as the user-filter group's remediationReport in [the blocker index](../blockers.json). The entire three-route/declaration/test group may be retried; its failed files and blocked dependents remain blocked until acceptance. Other blocker entries remain unchanged.
70
+
71
+ **checks:** report-only revision; no production source changes and no migration checks rerun. The retry must pass strict compilation, compiler closure, ordinary build, applicable integration tests, and required review. Use real databases with minimal mocks, following repository test rules. Cover root invocation (including root with an ID), numeric IDs (including zero), string/UUID IDs without coercion, regular trusted users without IDs, malformed users/roles and invalid IDs, HTTP 401 before callback/query on invalid filtered requests, unchanged sessions, unchanged authorization order, callback receiver/error behavior, and matching list/export scoping. Verify SQL handling for string IDs. Keep the blocker until the entire group passes these checks.
@@ -0,0 +1,17 @@
1
+ # API expression result remediation
2
+
3
+ Scope: `src/api/values.ts`, which evaluates configured expressions and formats export and insertion values.
4
+
5
+ Date: 2026-10-02. Decision: user-approved guidance for a migration retry.
6
+
7
+ Failure: [API expression result contract](../failures/2026-09-23-api-values-contract.md).
8
+
9
+ **accepted:** try `evalExpression(expression: string, data: Record<string, unknown>): unknown`. Annotate the direct `eval` result as `unknown`. `Record<string, unknown>` covers the string keys read by `for...in`; symbol keys are not enumerated.
10
+
11
+ For this retry, the expression evaluator is an unchecked-value boundary. The user accepts `unknown` for its input field values and result, and for those results passed through formatting to CSV concatenation and JSON serialization. `getFormattedValue` may return `Promise<unknown>`. This is an explicit exception to the migration rule that internal interfaces use domain types. It does not authorize replacing unrelated domain types with `unknown`.
12
+
13
+ **preserve:** keep direct `eval` in its current scope, including access to `data`, `statement`, and `varString`. Do not validate or restrict expression results. Preserve getter reads, object identity, CSV coercion, JSON serialization, null/undefined handling, the record's `options` assignment, and existing error behavior. Do not normalize, clone, or pre-serialize results to make them fit a narrower type.
14
+
15
+ **retry:** try these annotations and ordinary narrowing first. Do not add `any`, assertions that claim a checked result, or suppression comments. If another compiler or migration-rule conflict remains, report its exact location and explain which `unknown` approach was tried and why it failed.
16
+
17
+ **checks:** a strict compiler probe accepted the proposed signature, string-value narrowing, and string concatenation of an `unknown` result. This was not a full module migration. The retry must pass the required compiler, build, and applicable tests before this blocker is removed.
@@ -0,0 +1,36 @@
1
+ # Callback ID contract remediation
2
+
3
+ Scope: `src/api/routes/createRecord.ts`, `src/api/routes/deleteRecord.ts`, `src/api/routes/deleteRecordFromPanel.ts`, and `src/api/routes/updateRecord.ts`, which forward record IDs to configured callbacks.
4
+
5
+ Date: 2026-10-03. Decision: user-approved temporary type assertions for migration retries.
6
+
7
+ Issue: [Callback ID types do not match current runtime values #45](https://github.com/galadrimteam/galadmin/issues/45).
8
+
9
+ Failures covered:
10
+
11
+ - [Create callback result contract](../failures/2026-10-01-cycle-02-create-callback-contract.md).
12
+ - [Delete callback ID contract](../failures/2026-10-01-cycle-06-delete-callback-id-contract.md).
13
+ - [Panel delete callback ID contract](../failures/2026-10-01-cycle-07-panel-delete-callback-id-contract.md).
14
+ - [Edit callback ID contract](../failures/2026-10-01-cycle-13-update-callback-id-contract.md).
15
+
16
+ **accepted:** preserve the existing public `id: number` callback contracts and runtime behavior. The user authorizes narrow `as number` assertions at the callback ID assignments for these four routes. This is an explicit exception to the migration's assertion restrictions for these known mismatches only. The assertions are not runtime validation and must not be described as proof that the IDs are numbers.
17
+
18
+ Create example, after the insert ID has been read from the database result without changing its value:
19
+
20
+ ```ts
21
+ // TODO: https://github.com/galadrimteam/galadmin/issues/45 — PostgreSQL supplies undefined.
22
+ id: insertId as number,
23
+ ```
24
+
25
+ Edit and delete example:
26
+
27
+ ```ts
28
+ // TODO: https://github.com/galadrimteam/galadmin/issues/45 — Primary keys can be strings.
29
+ id: primaryValue as number,
30
+ ```
31
+
32
+ **preserve:** PostgreSQL create callbacks continue to receive `undefined`; MySQL/mysql2 insertion IDs remain unchanged. Edit and delete callbacks receive the original supplied key, including UUID strings and string route parameters. Preserve other payload fields, callback execution, error handling, HTTP callback payloads, and route responses. Do not add RETURNING, retrieve or fabricate IDs, convert keys with Number/parseInt, change public signatures, or suppress callbacks.
33
+
34
+ **retry:** add a TODO with the issue URL beside each temporary ID assertion. Keep assertions limited to the ID expression; do not cast a whole request, database result, or callback payload. Use normal narrowing to read the database result: successful PostgreSQL row arrays have no insertId and yield `undefined`; mutation results expose their existing insertId. Report any additional shape conflict rather than hiding it behind an assertion. Remove the temporary assertions when issue #45 resolves the contracts.
35
+
36
+ **checks:** the current real-database create test at `tests/integration/routes.crud.integration.test.ts:434` records successful insertion and `id: undefined` on PostgreSQL. The other failure reports record historical UUID edit/delete tests; those temporary tests were removed. No tests were rerun for this report-only change. Each migration retry must pass strict compilation, build, applicable integration tests, and required review. Keep every blocker until its own group passes those checks; this report permits retries, not automatic acceptance.
@@ -0,0 +1,41 @@
1
+ # Import parser-element remediation
2
+
3
+ Scope: `src/api/routes/recordsImport.ts` and `src/api/routes/subrecordsImport.ts`, which import configured parser results into a view or panel table.
4
+
5
+ Date: 2026-10-06. Decision: user-approved parser shape validation, unchecked field-value boundary, and shared panel-roles declaration for migration retries.
6
+
7
+ Failures:
8
+ - [Record import parser-element contract](../failures/2026-10-03-cycle-06-record-import-parser-contract.md).
9
+ - [Panel import parser-element contract](../failures/2026-10-03-cycle-07-panel-import-parser-contract.md).
10
+
11
+ **accepted:** keep the public parser declarations unchanged. View parsers retain `(file: FormDataFile) => Promise<any[]>`; panel parsers retain `(file: FormDataFile, id?: any) => Promise<any[]>`. This preserves existing declarations; it does not authorize adding new any types.
12
+
13
+ **panel roles:** extend `BaseTypePanel` with `Pick<BaseTypeView, "roles">` in `src/types/config.ts` to share the existing `roles?: string[]` contract. `RequestPanel` inherits this property through `ViewPanel`; reuse that declaration instead of adding a separate request-only roles type.
14
+
15
+ Trust the host application's configuration. Supported panel roles are absent or a string array. String, numeric, boolean, and null values are unsupported configuration; their accidental behavior, including substring matching, need not be preserved. Add no runtime roles validation and keep `canWriteView`, its root bypass, and the existing view-then-panel authorization order unchanged.
16
+
17
+ This declaration resolves the panel-roles blocker reported in the 2026-10-06 retry. Check absent roles, empty arrays, allowed and denied array roles, root access, and authorization rejection before parser invocation with real-database integration tests.
18
+
19
+ Receive each configured parser's result as unknown internally. Validate that it is an array and that every element is a non-null, non-array object before using it as a record. Reject primitive, null, undefined, array, and function elements. Custom object instances remain supported; do not require a plain prototype.
20
+
21
+ The approved internal record shape is `Record<string, unknown>`. The parser output, its record fields, and values passed to the existing insertion formatter are an explicitly permitted unchecked-value boundary. This exception does not authorize unrelated internal interfaces to use unknown. A checked helper may establish the string-indexed property-access shape through normal narrowing; it must not claim that fields are validated database/domain values or use unchecked assertions to claim a valid parser result.
22
+
23
+ **policy:** if the result is not an array or any element is invalid, reject the entire import with HTTP 400 before building or executing its insertion query. Use `res.sendStatus(400)`; do not skip invalid rows, perform a partial import, or convert invalid elements into objects. Validate every indexed element, including sparse-array holes as undefined; Array.every alone skips holes and is insufficient.
24
+
25
+ An empty array retains HTTP 200 with `{ affectedRows: 0 }`. Preserve existing view/panel authorization and panel configuration checks before invoking the parser. Preserve parser arguments, callback receiver, and invocation count.
26
+
27
+ **preserve:** retain the existing for-in column enumeration, including inherited enumerable keys. Do not replace it with own-key enumeration. Validate only array and element shapes, without recursively inspecting field values, cloning records, reading field getters early, normalizing values, or restricting prototypes. Keep object and field identity and existing getter/property-read timing during column enumeration and insertion formatting.
28
+
29
+ Preserve field values exactly and pass them through the existing formatValueForInsertion behavior, including numeric/string/boolean/date/object handling. Missing fields in a row continue to produce undefined through indexed access and receive the formatter's current handling. Do not normalize missing fields to null, add defaults, coerce IDs, or fabricate columns.
30
+
31
+ **attention:** the user authorizes rejecting non-array results and invalid elements with HTTP 400. This changes historical behavior where string elements exposed character-index columns or null entries failed later during value access. Place the required #PORTING-EDIT marker immediately before each runtime change, explaining the shape requirement and rejection before insertion.
32
+
33
+ Only malformed resolved parser output receives this new 400 behavior. Parser exceptions/rejections remain outside this remediation; do not move parser invocation into a catch or alter those failures. Retain existing database/insertion error responses. Panel parent-ID parsing/interpolation, PostgreSQL panel SQL compatibility, and insertion-result/affectedRows contracts remain outside scope.
34
+
35
+ **retry:** introduce or reuse one shared shape validator for both routes, keeping unknown at the approved parser/formatter boundary. Preserve the original array and record instances when validation succeeds. Use normal narrowing; do not add unchecked assertions, suppression comments, or weakened compiler settings. If strict typing reveals another conflict, report it instead of extending this exception.
36
+
37
+ Link this report from both import entries in [the blocker index](../blockers.json). This guidance permits retries of both failed groups; each route still requires its own acceptance checks and review. Keep failed files and blocked dependents in the index until their corresponding group is accepted. Preserve unrelated blockers and remediation links.
38
+
39
+ **checks:** report-only decision; production source/config interfaces are unchanged and migration tests have not been rerun. Each retry must pass strict compilation, compiler closure, ordinary build, applicable integration tests, warning assessment, and required review. Follow repository test rules with real databases and minimal mocks.
40
+
41
+ Cover both routes: valid object rows and mixed field types; empty-array success; non-array results; primitive/null/undefined/array/function elements; sparse holes; invalid elements after valid rows returning 400 without insertion; preserved inherited keys, custom prototypes, getters, object/field identity, and missing-field behavior; authorization rejection before parser invocation; unchanged panel parent-ID arguments; and unchanged parser-exception and database-error behavior. Reuse valid existing evidence and keep preexisting PostgreSQL panel failures characterized rather than fixing them in this retry.
@@ -0,0 +1,33 @@
1
+ # Rich-text upload boundary remediation
2
+
3
+ Scope: `src/api/routes/uploadFileFromBetterRichTextInput.ts`, which authorizes a selected rich-text column and passes its server-configured upload settings to the shared uploader. The client identifies the column through `viewIndex` and `columnId` query parameters.
4
+
5
+ Date: 2026-10-06. Decision: user-supplied production fix reviewed as guidance for a migration retry.
6
+
7
+ Failure: [Rich-text upload header contract](../failures/2026-10-01-cycle-15-rich-text-upload-boundary-contract.md).
8
+
9
+ **accepted:** the production fix [277ed9f — resolve rich-text upload settings on the server](https://github.com/galadrimteam/galadmin/commit/277ed9f1704173d06c7c426ef4886519cc8371f4) replaces client-supplied JSON settings with server-side column lookup. Current master is cb372254abb766fdcb608ebd2cdaf15f3c998ddb; the migration branch includes it (comparison reports master as the merge base, zero commits behind). The extracted migration route and frontend contain the fix.
10
+
11
+ This supersedes the old request for primitive normalization and invalid JSON-field policies. The route no longer parses the file-upload-properties header, so header values such as 0, malformed JSON, or numeric pathTransform cannot become upload settings. Missing and arbitrary legacy headers are ignored; do not restore a header fallback.
12
+
13
+ **type:** reuse FileUploadProperties and the existing configured column/request types. Upload settings originate in server configuration, where pathTransform can remain a function. Query parameters remain an external boundary and require ordinary string narrowing. Resolve a betterRichText column with configured fileUploadProperties before calling uploadFile. Do not claim JSON can contain callable transforms, introduce any, or broaden the uploader contract.
14
+
15
+ **preserve:** use the exact server-configured settings object, including callable S3/GCP transforms, storage destinations, and existing uploader behavior. Do not serialize, clone, normalize, or reconstruct those settings. Preserve client query construction through URLSearchParams and removal of the legacy settings header.
16
+
17
+ Retain the fixed route's target resolution and response behavior:
18
+ - Require string viewIndex containing only digits and a string columnId; malformed queries return 403.
19
+ - Resolve viewIndex against the request's role-filtered views. Missing or non-writable views return 403 before uploader invocation.
20
+ - Search view columns and panel createConfig columns for the configured column ID.
21
+ - Missing or role-restricted columns return 403.
22
+ - A column that is not betterRichText or has no fileUploadProperties returns 400 with `{ error: "Invalid rich-text upload column" }`.
23
+ - Valid authorized targets call uploadFile(settings, "upload", req, res). Target checks occur before the shared uploader parses multipart data or contacts storage.
24
+
25
+ The historical broad check for any writable view is superseded by authorization of the selected view and column. These runtime changes are already in the user-supplied baseline; the strict retry must preserve them, not reproduce the old header behavior. Do not add new server-configuration validation, storage policies, index normalization, authorization redesign, or legacy-client compatibility behavior in this retry.
26
+
27
+ **retry:** the original failure's unchecked-JSON versus callable-field conflict is resolved by the production fix. Retry the route against the current rebased source, narrow query/configuration lookups, and add its strict entry only after compiler closure and checks pass. Any new runtime change requires separate justification under the migration rules and the required #PORTING-EDIT marker. Report unrelated compiler or configuration conflicts rather than hiding them behind assertions.
28
+
29
+ Set this report as the rich-text upload group's remediationReport in [the blocker index](../blockers.json). Keep the failed file and blocked dependents until the group passes acceptance review and required checks. Preserve other remediation links and blocker entries.
30
+
31
+ **checks:** source review covered the master fix, extracted route, client query construction, configuration enrichment, uploader signature/transform calls, and added frontend/integration coverage. Twelve focused route probes passed using the current route and authorization helper: server settings identity and callable transform; ignored malformed/primitive legacy headers; panel creation-column lookup; malformed/missing/out-of-range targets; read-only views; missing/restricted columns; wrong column type; and absent settings. An uploader call recorder verified no calls on rejected requests. These were isolated handler probes with no database or real storage execution; TypeScript transpilation was used to execute them and is not strict compilation. Local probe: /tmp/rich-upload-review/probe.cjs.
32
+
33
+ The committed regression tests cover S3/GCP transforms with mocked storage SDKs, ignored legacy headers, role-filtered indexes, panel columns, target authorization, and client URL/header construction. Their presence was reviewed; they were not rerun in this workspace. Full ordinary build, strict compilation, and integration/frontend suites were not run for this report-only change and no strict acceptance is claimed. The retry must pass strict compilation, compiler closure, build, applicable real-database upload/authorization tests, warning assessment, and required review. Actual remote storage behavior remains unverified.
@@ -0,0 +1,32 @@
1
+ # API assembly remediation
2
+
3
+ Date: 2026-10-07. Scope: retry strict typing of `src/api.ts` after the [failed attempt](../failures/2026-10-07-resume-cycle-02-api-assembly-contract.md).
4
+
5
+ The user approved the proposed `DbManager` typing, an update to the existing `FakeDb`, and filtering nullish column names from `__hiddenColumns`.
6
+
7
+ ## Database test helper
8
+
9
+ The user permits updating this existing database mock despite the repository's general rule against database mocks. Tests need not become strict; test-side assertions are permitted. Production contracts and compiler checks must remain intact.
10
+
11
+ This fix is complete: [FakeDb](../../../tests/helpers/fakeDb.ts#L20) implements `DbManager`, provides a no-op `init`, and derives its query return type from `DbManager`. Query results contain `err`, `rows`, and `fields`. Existing fixture inputs remain flexible. All 149 unit tests passed with `npm run test:unit -- --runInBand` after the change.
12
+
13
+ ## Hidden column names
14
+
15
+ Keep [column names optional](../../../src/types/config.ts#L38). When [the API collects restricted column names](../../../src/api.ts#L99), remove null and undefined values:
16
+
17
+ ```ts
18
+ __hiddenColumns: view.columns
19
+ .filter((column) => !allowed(column))
20
+ .map((column) => column.name)
21
+ .filter((name): name is string => name != null),
22
+ ```
23
+
24
+ This approved behavior change keeps `__hiddenColumns` as `string[]` in request and authorization types. Preserve empty strings and all other string names. Do not require a name, invent one, or change column enrichment.
25
+
26
+ An unnamed restricted column will no longer cause [read stripping](../../../src/api/authorization.ts#L118) or [write checks](../../../src/api/authorization.ts#L128) to treat it as a property named `"undefined"`. Keep these helpers and the import route's string comparison unchanged. Place the required `#PORTING-EDIT` marker at the filter change.
27
+
28
+ ## Retry checks
29
+
30
+ Check that named restricted columns still lose their fields in read responses and reject writes with HTTP 403. Check that unnamed restricted columns produce no hidden-name entry and no longer remove or reject a property named `"undefined"`. Use real-database integration tests under repository test rules.
31
+
32
+ The production filter is approved for the retry but has not been applied. Run the build, strict compilation, compiler closure, applicable tests, warning assessment, and required review before accepting the group. Keep the blocker and its dependents listed until acceptance. Report any new issue instead of expanding this remediation.
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: port-javascript-to-typescript
3
+ description: Migrate JavaScript or loosely typed TypeScript to strict TypeScript.
4
+ ---
5
+
6
+ # Port JavaScript to TypeScript
7
+
8
+ Port the smallest eligible dependency group per batch. Complete one batch unless continued migration is requested. Default to backend source; frontend and test typing require explicit scope.
9
+
10
+ Follow the [shared rules](references/rules.md) throughout the migration.
11
+
12
+ ## Agents
13
+
14
+ Each agent reads its role reference and supplied inputs. Spawn with `fork_turns: "none"` and explicit `model` / `reasoning_effort`:
15
+
16
+ | Role | Model | Reasoning |
17
+ |---|---|---|
18
+ | Selector | `gpt-6-luna` | medium |
19
+ | Planner | `gpt-6-astra` | high |
20
+ | Implementer | `gpt-6-luna` | medium |
21
+
22
+ Report unavailable models or delegation before using a fallback.
23
+
24
+ ## Prepare
25
+
26
+ Read repository instructions. Establish scope and record commands/working directories for the compiler, build, unit/integration tests, and [CLI tools](references/tools.md). Use disposable test services.
27
+
28
+ Preserve initial source/tests/configuration and user edits. Establish passing build, test, and existing strict baselines. Without a strict configuration, record no strict coverage; extend the source configuration with `strict` and replace inherited file lists for the selected group. An empty program is not a baseline. Resolve missing tooling within scope; required build migrations block the attempt.
29
+
30
+ Read relevant reports for prior type decisions and failures, checking them against current source. Reuse unchanged evidence.
31
+
32
+ ## Run a batch
33
+
34
+ 1. Run the recorded graph command and collect compiler file lists and diagnostics, using the source project if no strict project exists. Refresh blockers and approve retries according to [blockers.md](references/blockers.md).
35
+ 2. Spawn the [selector](references/selection.md). Supply its reference, area, owned-source scope, accepted files, CLI output paths, and blockers with approved retries.
36
+ 3. Verify selection and compiler closure; add explicit strict entries without removing accepted files. Resolve omitted dependencies; send type errors to the planner.
37
+ 4. Spawn the [planner](references/planning.md) with the group, diagnostics, original code, relevant reports, retry guidance, and commands.
38
+ 5. Spawn the [implementer](references/porting.md) with that plan and its linked evidence. Send plan blockers back to the same planner.
39
+ 6. Return the complete attempt diff and check evidence to the same planner for review. Send findings to the same implementer. Abort after three unsuccessful review rounds, or earlier when the rules cannot be met.
40
+ 7. Follow [reporting.md](references/reporting.md) to finish or restore the attempt. Finish the report and any authorized commit before selecting again. Stop when no eligible group remains.
41
+
42
+ Use Git and commit only when authorized. Never push. Return the area, newly strict file count, check results, report path, and actual commit identifier if committed.
@@ -0,0 +1,3 @@
1
+ interface:
2
+ display_name: "Port Javascript to Typescript"
3
+ short_description: "Port minimal dependency groups to strict TypeScript"
@@ -0,0 +1,31 @@
1
+ # Blockers
2
+
3
+ The master maintains `.agents/report/blockers.json`, an array of failed dependency groups:
4
+
5
+ ```json
6
+ [
7
+ {
8
+ "failedFiles": ["src/example.ts"],
9
+ "failureReport": ".agents/report/failures/example.md",
10
+ "blockedDependents": ["src/service.ts"],
11
+ "remediationReport": null
12
+ }
13
+ ]
14
+ ```
15
+
16
+ Use repository-relative paths and sorted, unique lists. `blockedDependents` contains all reverse transitive local dependents outside the failed group.
17
+
18
+ ## Before selection
19
+
20
+ Reconcile missing entries from unresolved failure reports, consulting success reports to avoid restoring resolved blockers. An absent index does not mean no failures. Preserve existing entries during reconciliation.
21
+
22
+ Refresh only dependent lists from the current graph. Approve a failed group's retry only when its externally supplied `remediationReport` exists and gives sufficient guidance within authorized scope. Read it with the latest failure evidence; pass approved retries to the selector and implementation guidance to the planner. Preserve the link during assessment. Approval does not unblock dependents or authorize behavior changes.
23
+
24
+ Store externally supplied remediation documents in `.agents/report/remediation/` with unique `YYYY-MM-DD-area.md` names. Set `remediationReport` to the repository-relative document path.
25
+
26
+ Migration agents never create, edit, or link remediation documents.
27
+
28
+ ## After an attempt
29
+
30
+ - Failure: create the index if needed, add/update the failed group and report link, and compute dependents from restored source. Always reset `remediationReport` to `null`, including on retries. Leave unrelated entries unchanged.
31
+ - Success: remove a blocker only after its entire group passes planner review and required checks. Retain the failure report as history and link it from the success report.
@@ -0,0 +1,43 @@
1
+ # Plan and review
2
+
3
+ Follow the [shared rules](rules.md). Read selected code, callers, declarations, schemas, tests, and retry evidence. Establish behavior and contracts. Send new dependencies to the master before expanding scope.
4
+
5
+ ## Prepare the handoff
6
+
7
+ Reuse existing coverage. Add only missing unit or integration tests for meaningful behavior, following repository test rules. Run characterization tests against the original implementation. For approved sanitization, identify the intended failing assertion; unrelated failures block handoff.
8
+
9
+ Hand off only implementation decisions: paths/renames, reused types, definitions/owners of new complex types, guards, and justified behavior changes. Link tests, baseline results, and check commands. Hand off when every selected file has resolved type decisions and characterization tests pass, except documented sanitization assertions. Link evidence instead of repeating source or logs.
10
+
11
+ ## Types and boundaries
12
+
13
+ Keep types near their owner; share them when meaning or use is shared. Use generics only for input/output relationships. Discriminants must exist at runtime. Do not make required fields optional to hide incompatible contracts.
14
+
15
+ Plan `import type` for type-only symbols without losing side-effect imports. Avoid typing constructs that add runtime behavior.
16
+
17
+ Prefer trustworthy declarations and existing parsers. Boundary helpers must validate every promised property and return domain types. Reject unchecked generic results and casts disguised as guards. Error helpers must preserve logging, response, and rethrow behavior.
18
+
19
+ Prefer narrowing. Assertions must be narrow, local, and justified against real producers and consumers; non-null assertions need the same evidence.
20
+
21
+ ## Sanitization exception
22
+
23
+ Permit minimal input/result sanitization only when accurate types and existing helpers cannot establish a coherent contract. Trace caller effects, including identity, coercions, property reads, mutations, and exceptions. Unrelated fixes and refactoring are outside scope.
24
+
25
+ Immediately before each behavior change, retain this marker with its reason:
26
+
27
+ ```ts
28
+ /*
29
+ #PORTING-EDIT
30
+ Explain why sanitization is necessary and what behavior changes.
31
+ */
32
+ ```
33
+
34
+ Test the change and surrounding behavior. Change expectations only for documented sanitization, preserving other coverage. Justify necessity and minimality in planning and review. Return `ABORT` with evidence if contracts require broader changes.
35
+
36
+ ## Review the implementation
37
+
38
+ Follow repository review-tool requirements. Compare original/current code, the complete diff, callers, and retry evidence against the shared rules. Question the plan's assumptions. Return source fixes to the implementer; change tests only to correct the contract.
39
+
40
+ - Verify compiler closure, strict entries, renames, and JavaScript coverage. Imported files can enter despite `exclude`; inclusion alone does not establish accepted coverage.
41
+ - Inspect check logs and warning decisions for the reviewed state. Reuse valid results; add targeted probes for unresolved behavior or uncertain evidence.
42
+
43
+ Return `ACCEPT`, `CHANGES_REQUIRED`, or `ABORT` with evidence and the reviewed state. Findings need a location, violated rule, and resolution criterion. Acceptance requires all checks passing, no unresolved findings, and justified marked changes. Changes to relevant source, tests, or configuration require renewed checks and review.
@@ -0,0 +1,9 @@
1
+ # Implement
2
+
3
+ Follow the [shared rules](rules.md) and the planner's handoff. Read the selected code and linked types/tests, then apply the specified renames, types, and guards. Preserve runtime imports, module format, output paths, and public imports. Update strict entries for approved renames/helpers; preserve accepted entries and compiler settings.
4
+
5
+ If the plan cannot resolve a type error or preserve behavior, return the exact diagnostic, path, and conflicting contract to the planner. Do not invent contracts, expand scope, or edit tests.
6
+
7
+ Run every recorded deterministic check: compiler closure and strict compilation, build, [warning scan](tools.md), applicable unit tests, the integration suite, and focused behavior checks. Inspect diagnostics and confirm intended tests ran. Fix implementation failures; send environment blockers to the master.
8
+
9
+ Return `READY_FOR_REVIEW` only when all checks pass. Link the diff and check logs; identify the checked state, warning decisions, and plan deviations. Otherwise return a specific blocker or `ABORT`. Apply planner findings and rerun affected checks before returning.
@@ -0,0 +1,24 @@
1
+ # Reports and completion
2
+
3
+ The master stores success reports in `.agents/report/port/` and failure reports in `.agents/report/failures/`. Use unique `YYYY-MM-DD-area.md` names. On a failed retry, append a dated attempt to the existing report, retaining earlier evidence. Exclude secrets and full private payloads.
4
+
5
+ Use Rust compiler style: neutral messages with exact symbols, types, values, code examples and visual help. Use ASD-STE100 language : the report should be helpfull and enable the reviewer to make an informed decision.
6
+
7
+ Start with scope (selected files) and module responsibility in one or two sentences. Show repository-root-relative `file:line` labels; link to paths relative to the report file's directory with `#L<number>` line anchors.
8
+
9
+ Link detailed evidence instead of repeating logs or workflow history.
10
+
11
+ ## Success
12
+
13
+ - `type`: each new important domain or shared-contract type, its location, and what it represents.
14
+ - `attention`: each runtime change, its `#PORTING-EDIT` location, why a type-only port was insufficient, the chosen behavior, caller effects, and test evidence.
15
+ - `checks`: one line with results and limits.
16
+
17
+ Report-only edits need no rerun. For authorized commits, inspect exact contents: only reviewed, owned changes, the report, and blocker updates. Stop if user edits cannot be separated safely. Report the actual commit identifier; otherwise leave changes uncommitted.
18
+
19
+ ## Abort
20
+
21
+ 1. Preserve diagnostics and behavior evidence. Restore only the failed attempt's source, tests, renames, helpers, and configuration; preserve user work and earlier accepted groups. Report any cleanup conflict.
22
+ 2. Write one `error` per root cause: source location, conflicting contracts, and a concrete call that exposes the conflict. Distinguish type errors from observed runtime failures. End with `help`: the required decision or fix for retry; label optional suggestions. For environment failures, give the failed command and cause. Link preserved evidence.
23
+ 3. Update the [blocker index](blockers.md). An authorized failure commit contains only the failure report and index changes. Keep earlier accepted work separate.
24
+ 4. Return `ABORT` with report paths and cleanup state. Never bypass failing commit hooks. Continue to another group only when requested.
@@ -0,0 +1,8 @@
1
+ # Shared rules
2
+
3
+ - Preserve signatures, defaults, return values, side effects, errors, and runtime module behavior. Only the rare, minimal [sanitization exception](planning.md#sanitization-exception) permits behavior changes.
4
+ - Keep `unknown` at external boundaries and their parsing/error helpers. Internal interfaces use domain types.
5
+ - Use one absence representation per contract unless callers depend on distinct states. Normalize only under the sanitization exception.
6
+ - Prefer inference and existing types. No added `any`, double assertions, broad ambient declarations, suppression comments, or weakened compiler settings. Inspect existing escape hatches in selected code too.
7
+ - Preserve the ordinary build and runtime target. Check migration source through a separate strict configuration with the installed compiler and `--noEmit`; retain compiler-cache settings. Never weaken tests to pass. Skipped suites and environment failures are not passes.
8
+ - Only one agent writes at a time. The planner writes tests; the implementer edits production source and approved strict entries; the master owns other configuration and reports. Any `ABORT` ends the attempt.
@@ -0,0 +1,16 @@
1
+ # Select
2
+
3
+ Read only this reference and the supplied CLI evidence, scope, accepted strict files, and blocker list. Make no edits or contract decisions.
4
+
5
+ 1. Report incomplete scope, failed tools, or unresolved imports as `SELECTION_BLOCKED`. Expected type errors in unported files do not block selection.
6
+ 2. For each unaccepted source file in the requested area, form its transitive local dependency group, excluding accepted files and external declarations. Keep cycles intact. Dependencies outside authorized scope need a master decision.
7
+ 3. Exclude groups containing `blockedDependents` or failed files without a master-approved retry. A retry includes the entire failed group and its dependency closure; its dependents remain blocked until acceptance.
8
+ 4. Select the group with the fewest newly strict owned files. Break ties by sorted repository-relative paths.
9
+
10
+ Return:
11
+
12
+ - `SELECTED`: group, count, accepted dependencies, direct callers, and relevant evidence/blocker references.
13
+ - `NO_SELECTION`: area complete or all groups blocked, with blocker references.
14
+ - `SELECTION_BLOCKED`: missing evidence or required scope decision.
15
+
16
+ Link CLI output instead of copying it.
@@ -0,0 +1,20 @@
1
+ # CLI tools
2
+
3
+ Run the bundled scripts from the repository root. They use pinned npm tools and require Bash, npm, and Node.js 22.12+. First use may need network access. Use `--help` for arguments.
4
+
5
+ ```sh
6
+ bash /path/to/skill/scripts/graph.sh tsconfig.json <source-roots-or-entry-files>
7
+ bash /path/to/skill/scripts/check.sh <selected-and-supporting-source-files>
8
+ ```
9
+
10
+ ## Graph
11
+
12
+ `graph.sh` emits a JSON map of repository-relative file paths to imports. Record and reuse the verified source scope, including dependencies and callers but excluding vendored/generated candidates. Read stderr for unresolved imports and skipped files; resolve gaps before selection. Computed imports and runtime-loaded modules require separate inspection.
13
+
14
+ The graph includes type-only and literal dynamic imports and mixed module formats. It establishes static dependencies, not strict acceptance. Verify compiler closure with the installed compiler's `--noEmit --listFilesOnly` and confirm renamed JavaScript receives strict coverage.
15
+
16
+ ## Warnings
17
+
18
+ `check.sh` checks explicit `any`, non-null assertions, and suppression comments. It emits JSON without fixes and ignores repository ignore files. Warnings normally exit zero: inspect each diagnostic and lint-disable comment. Parse/setup/execution errors are failures. This scan does not replace strict compilation, build, or integration tests.
19
+
20
+ When modifying these scripts, run `node /path/to/skill/scripts/test-tools.cjs`.
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ if [[ ${1:-} == --help || ${1:-} == help ]]; then
5
+ printf '%s\n' 'Usage: check.sh <source-file-or-directory> [...]' \
6
+ 'Print Oxlint warnings as JSON. This does not replace the strict compiler or tests.' \
7
+ 'Requires Bash, Node.js 22.12+ and npm; npx may download the pinned tool.'
8
+ exit 0
9
+ fi
10
+ if (( $# == 0 )); then
11
+ printf '%s\n' 'Usage: check.sh <source-file-or-directory> [...]' >&2
12
+ exit 2
13
+ fi
14
+
15
+ script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
16
+ exec npx --yes --package=oxlint@1.85.0 -- oxlint \
17
+ --config "$script_dir/oxlint.json" --no-ignore --format json -- "$@"
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ if [[ ${1:-} == --help || ${1:-} == help ]]; then
5
+ printf '%s\n' 'Usage: graph.sh <tsconfig.json> <source-file-or-directory> [...]' \
6
+ 'Print the Madge dependency graph as JSON. Inspect stderr for skipped files.' \
7
+ 'Run from the target repository. Requires Bash, Node.js and npm; npx may download the pinned tool.'
8
+ exit 0
9
+ fi
10
+ if (( $# < 2 )); then
11
+ printf '%s\n' 'Usage: graph.sh <tsconfig.json> <source-file-or-directory> [...]' >&2
12
+ exit 2
13
+ fi
14
+
15
+ script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
16
+ repo_dir=$PWD
17
+ paths=()
18
+ for path in "$@"; do
19
+ case "$path" in
20
+ /*) paths+=("$path") ;;
21
+ *) paths+=("$repo_dir/$path") ;;
22
+ esac
23
+ done
24
+ cd -- "$script_dir"
25
+ export madge_config="$script_dir/madge.json"
26
+ command=(npx --yes --package=madge@8.0.0 -- madge --no-color --no-spinner
27
+ --basedir "$repo_dir" --ts-config "${paths[0]}")
28
+ # Madge omits skipped-file warnings in JSON mode.
29
+ "${command[@]}" --warning -- "${paths[@]:1}" >&2
30
+ exec "${command[@]}" --json -- "${paths[@]:1}"
@@ -0,0 +1,12 @@
1
+ {
2
+ "fileExtensions": ["js", "jsx", "ts", "tsx", "mjs", "cjs", "mts", "cts"],
3
+ "includeNpm": false,
4
+ "excludeRegExp": [],
5
+ "webpackConfig": null,
6
+ "requireConfig": null,
7
+ "detectiveOptions": {
8
+ "es6": { "mixedImports": true },
9
+ "ts": { "mixedImports": true, "skipTypeImports": false, "skipAsyncImports": false },
10
+ "tsx": { "mixedImports": true, "skipTypeImports": false, "skipAsyncImports": false }
11
+ }
12
+ }