@cldmv/slothlet 2.10.0 → 3.0.0

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 (188) hide show
  1. package/AGENT-USAGE.md +365 -294
  2. package/README.md +556 -233
  3. package/dist/lib/builders/api-assignment.mjs +605 -0
  4. package/dist/lib/builders/api_builder.mjs +1073 -0
  5. package/dist/lib/builders/builder.mjs +94 -0
  6. package/dist/lib/builders/modes-processor.mjs +1816 -0
  7. package/dist/lib/errors.mjs +227 -0
  8. package/dist/lib/factories/component-base.mjs +96 -0
  9. package/dist/lib/factories/context.mjs +38 -0
  10. package/dist/lib/handlers/api-cache-manager.mjs +216 -0
  11. package/dist/lib/handlers/api-manager.mjs +2364 -0
  12. package/dist/lib/handlers/context-async.mjs +184 -0
  13. package/dist/lib/handlers/context-live.mjs +184 -0
  14. package/dist/lib/handlers/hook-manager.mjs +789 -0
  15. package/dist/lib/handlers/lifecycle-token.mjs +44 -0
  16. package/dist/lib/handlers/lifecycle.mjs +131 -0
  17. package/dist/lib/handlers/materialize-manager.mjs +64 -0
  18. package/dist/lib/handlers/metadata.mjs +500 -0
  19. package/dist/lib/handlers/ownership.mjs +338 -0
  20. package/dist/lib/handlers/unified-wrapper.mjs +3031 -0
  21. package/dist/lib/helpers/class-instance-wrapper.mjs +125 -0
  22. package/dist/lib/helpers/config.mjs +343 -0
  23. package/dist/lib/helpers/eventemitter-context.mjs +365 -0
  24. package/dist/lib/helpers/hint-detector.mjs +63 -0
  25. package/dist/lib/helpers/modes-utils.mjs +53 -0
  26. package/dist/lib/helpers/resolve-from-caller.mjs +125 -85
  27. package/dist/lib/helpers/sanitize.mjs +247 -168
  28. package/dist/lib/helpers/utilities.mjs +46 -81
  29. package/dist/lib/i18n/languages/de-de.json +377 -0
  30. package/dist/lib/i18n/languages/en-gb.json +377 -0
  31. package/dist/lib/i18n/languages/en-us.json +377 -0
  32. package/dist/lib/i18n/languages/es-mx.json +377 -0
  33. package/dist/lib/i18n/languages/fr-fr.json +377 -0
  34. package/dist/lib/i18n/languages/hi-in.json +377 -0
  35. package/dist/lib/i18n/languages/ja-jp.json +377 -0
  36. package/dist/lib/i18n/languages/ko-kr.json +377 -0
  37. package/dist/lib/i18n/languages/pt-br.json +377 -0
  38. package/dist/lib/i18n/languages/ru-ru.json +377 -0
  39. package/dist/lib/i18n/languages/zh-cn.json +377 -0
  40. package/dist/lib/i18n/translations.mjs +140 -0
  41. package/dist/lib/modes/eager.mjs +75 -0
  42. package/dist/lib/modes/lazy.mjs +97 -0
  43. package/dist/lib/processors/flatten.mjs +453 -0
  44. package/dist/lib/processors/loader.mjs +355 -0
  45. package/dist/lib/processors/type-generator.mjs +291 -0
  46. package/dist/lib/processors/typescript.mjs +188 -0
  47. package/dist/lib/runtime/runtime-asynclocalstorage.mjs +80 -522
  48. package/dist/lib/runtime/runtime-livebindings.mjs +45 -390
  49. package/dist/lib/runtime/runtime.mjs +39 -159
  50. package/dist/slothlet.mjs +529 -700
  51. package/docs/API-RULES.md +497 -617
  52. package/index.cjs +4 -4
  53. package/index.mjs +82 -45
  54. package/package.json +139 -26
  55. package/types/dist/lib/builders/api-assignment.d.mts +97 -0
  56. package/types/dist/lib/builders/api-assignment.d.mts.map +1 -0
  57. package/types/dist/lib/builders/api_builder.d.mts +96 -0
  58. package/types/dist/lib/builders/api_builder.d.mts.map +1 -0
  59. package/types/dist/lib/builders/builder.d.mts +60 -0
  60. package/types/dist/lib/builders/builder.d.mts.map +1 -0
  61. package/types/dist/lib/builders/modes-processor.d.mts +32 -0
  62. package/types/dist/lib/builders/modes-processor.d.mts.map +1 -0
  63. package/types/dist/lib/errors.d.mts +118 -0
  64. package/types/dist/lib/errors.d.mts.map +1 -0
  65. package/types/dist/lib/factories/component-base.d.mts +182 -0
  66. package/types/dist/lib/factories/component-base.d.mts.map +1 -0
  67. package/types/dist/lib/factories/context.d.mts +26 -0
  68. package/types/dist/lib/factories/context.d.mts.map +1 -0
  69. package/types/dist/lib/handlers/api-cache-manager.d.mts +208 -0
  70. package/types/dist/lib/handlers/api-cache-manager.d.mts.map +1 -0
  71. package/types/dist/lib/handlers/api-manager.d.mts +392 -0
  72. package/types/dist/lib/handlers/api-manager.d.mts.map +1 -0
  73. package/types/dist/lib/handlers/context-async.d.mts +66 -0
  74. package/types/dist/lib/handlers/context-async.d.mts.map +1 -0
  75. package/types/dist/lib/handlers/context-live.d.mts +65 -0
  76. package/types/dist/lib/handlers/context-live.d.mts.map +1 -0
  77. package/types/dist/lib/handlers/hook-manager.d.mts +199 -0
  78. package/types/dist/lib/handlers/hook-manager.d.mts.map +1 -0
  79. package/types/dist/lib/handlers/lifecycle-token.d.mts +49 -0
  80. package/types/dist/lib/handlers/lifecycle-token.d.mts.map +1 -0
  81. package/types/dist/lib/handlers/lifecycle.d.mts +90 -0
  82. package/types/dist/lib/handlers/lifecycle.d.mts.map +1 -0
  83. package/types/dist/lib/handlers/materialize-manager.d.mts +75 -0
  84. package/types/dist/lib/handlers/materialize-manager.d.mts.map +1 -0
  85. package/types/dist/lib/handlers/metadata.d.mts +215 -0
  86. package/types/dist/lib/handlers/metadata.d.mts.map +1 -0
  87. package/types/dist/lib/handlers/ownership.d.mts +170 -0
  88. package/types/dist/lib/handlers/ownership.d.mts.map +1 -0
  89. package/types/dist/lib/handlers/unified-wrapper.d.mts +250 -0
  90. package/types/dist/lib/handlers/unified-wrapper.d.mts.map +1 -0
  91. package/types/dist/lib/helpers/class-instance-wrapper.d.mts +54 -0
  92. package/types/dist/lib/helpers/class-instance-wrapper.d.mts.map +1 -0
  93. package/types/dist/lib/helpers/config.d.mts +96 -0
  94. package/types/dist/lib/helpers/config.d.mts.map +1 -0
  95. package/types/dist/lib/helpers/eventemitter-context.d.mts +31 -0
  96. package/types/dist/lib/helpers/eventemitter-context.d.mts.map +1 -0
  97. package/types/dist/lib/helpers/hint-detector.d.mts +20 -0
  98. package/types/dist/lib/helpers/hint-detector.d.mts.map +1 -0
  99. package/types/dist/lib/helpers/modes-utils.d.mts +35 -0
  100. package/types/dist/lib/helpers/modes-utils.d.mts.map +1 -0
  101. package/types/dist/lib/helpers/resolve-from-caller.d.mts +29 -145
  102. package/types/dist/lib/helpers/resolve-from-caller.d.mts.map +1 -1
  103. package/types/dist/lib/helpers/sanitize.d.mts +95 -94
  104. package/types/dist/lib/helpers/sanitize.d.mts.map +1 -1
  105. package/types/dist/lib/helpers/utilities.d.mts +53 -116
  106. package/types/dist/lib/helpers/utilities.d.mts.map +1 -1
  107. package/types/dist/lib/i18n/translations.d.mts +39 -0
  108. package/types/dist/lib/i18n/translations.d.mts.map +1 -0
  109. package/types/dist/lib/modes/eager.d.mts +36 -0
  110. package/types/dist/lib/modes/eager.d.mts.map +1 -0
  111. package/types/dist/lib/modes/lazy.d.mts +49 -0
  112. package/types/dist/lib/modes/lazy.d.mts.map +1 -0
  113. package/types/dist/lib/processors/flatten.d.mts +114 -0
  114. package/types/dist/lib/processors/flatten.d.mts.map +1 -0
  115. package/types/dist/lib/processors/loader.d.mts +47 -0
  116. package/types/dist/lib/processors/loader.d.mts.map +1 -0
  117. package/types/dist/lib/processors/type-generator.d.mts +19 -0
  118. package/types/dist/lib/processors/type-generator.d.mts.map +1 -0
  119. package/types/dist/lib/processors/typescript.d.mts +55 -0
  120. package/types/dist/lib/processors/typescript.d.mts.map +1 -0
  121. package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts +47 -42
  122. package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts.map +1 -1
  123. package/types/dist/lib/runtime/runtime-livebindings.d.mts +34 -65
  124. package/types/dist/lib/runtime/runtime-livebindings.d.mts.map +1 -1
  125. package/types/dist/lib/runtime/runtime.d.mts +39 -9
  126. package/types/dist/lib/runtime/runtime.d.mts.map +1 -1
  127. package/types/dist/slothlet.d.mts +186 -105
  128. package/types/dist/slothlet.d.mts.map +1 -1
  129. package/types/index.d.mts +1 -3
  130. package/dist/lib/engine/README.md +0 -21
  131. package/dist/lib/engine/slothlet_child.mjs +0 -59
  132. package/dist/lib/engine/slothlet_engine.mjs +0 -372
  133. package/dist/lib/engine/slothlet_esm.mjs +0 -230
  134. package/dist/lib/engine/slothlet_helpers.mjs +0 -455
  135. package/dist/lib/engine/slothlet_worker.mjs +0 -149
  136. package/dist/lib/helpers/als-eventemitter.mjs +0 -256
  137. package/dist/lib/helpers/api_builder/add_api.mjs +0 -292
  138. package/dist/lib/helpers/api_builder/analysis.mjs +0 -532
  139. package/dist/lib/helpers/api_builder/construction.mjs +0 -457
  140. package/dist/lib/helpers/api_builder/decisions.mjs +0 -737
  141. package/dist/lib/helpers/api_builder/metadata.mjs +0 -248
  142. package/dist/lib/helpers/api_builder.mjs +0 -41
  143. package/dist/lib/helpers/auto-wrap.mjs +0 -62
  144. package/dist/lib/helpers/hooks.mjs +0 -389
  145. package/dist/lib/helpers/instance-manager.mjs +0 -111
  146. package/dist/lib/helpers/metadata-api.mjs +0 -201
  147. package/dist/lib/helpers/multidefault.mjs +0 -216
  148. package/dist/lib/modes/slothlet_eager.mjs +0 -126
  149. package/dist/lib/modes/slothlet_lazy.mjs +0 -513
  150. package/docs/API-RULES-CONDITIONS.md +0 -508
  151. package/types/dist/lib/engine/slothlet_child.d.mts +0 -2
  152. package/types/dist/lib/engine/slothlet_child.d.mts.map +0 -1
  153. package/types/dist/lib/engine/slothlet_engine.d.mts +0 -31
  154. package/types/dist/lib/engine/slothlet_engine.d.mts.map +0 -1
  155. package/types/dist/lib/engine/slothlet_esm.d.mts +0 -19
  156. package/types/dist/lib/engine/slothlet_esm.d.mts.map +0 -1
  157. package/types/dist/lib/engine/slothlet_helpers.d.mts +0 -25
  158. package/types/dist/lib/engine/slothlet_helpers.d.mts.map +0 -1
  159. package/types/dist/lib/engine/slothlet_worker.d.mts +0 -2
  160. package/types/dist/lib/engine/slothlet_worker.d.mts.map +0 -1
  161. package/types/dist/lib/helpers/als-eventemitter.d.mts +0 -56
  162. package/types/dist/lib/helpers/als-eventemitter.d.mts.map +0 -1
  163. package/types/dist/lib/helpers/api_builder/add_api.d.mts +0 -76
  164. package/types/dist/lib/helpers/api_builder/add_api.d.mts.map +0 -1
  165. package/types/dist/lib/helpers/api_builder/analysis.d.mts +0 -189
  166. package/types/dist/lib/helpers/api_builder/analysis.d.mts.map +0 -1
  167. package/types/dist/lib/helpers/api_builder/construction.d.mts +0 -107
  168. package/types/dist/lib/helpers/api_builder/construction.d.mts.map +0 -1
  169. package/types/dist/lib/helpers/api_builder/decisions.d.mts +0 -213
  170. package/types/dist/lib/helpers/api_builder/decisions.d.mts.map +0 -1
  171. package/types/dist/lib/helpers/api_builder/metadata.d.mts +0 -99
  172. package/types/dist/lib/helpers/api_builder/metadata.d.mts.map +0 -1
  173. package/types/dist/lib/helpers/api_builder.d.mts +0 -6
  174. package/types/dist/lib/helpers/api_builder.d.mts.map +0 -1
  175. package/types/dist/lib/helpers/auto-wrap.d.mts +0 -49
  176. package/types/dist/lib/helpers/auto-wrap.d.mts.map +0 -1
  177. package/types/dist/lib/helpers/hooks.d.mts +0 -342
  178. package/types/dist/lib/helpers/hooks.d.mts.map +0 -1
  179. package/types/dist/lib/helpers/instance-manager.d.mts +0 -41
  180. package/types/dist/lib/helpers/instance-manager.d.mts.map +0 -1
  181. package/types/dist/lib/helpers/metadata-api.d.mts +0 -132
  182. package/types/dist/lib/helpers/metadata-api.d.mts.map +0 -1
  183. package/types/dist/lib/helpers/multidefault.d.mts +0 -90
  184. package/types/dist/lib/helpers/multidefault.d.mts.map +0 -1
  185. package/types/dist/lib/modes/slothlet_eager.d.mts +0 -65
  186. package/types/dist/lib/modes/slothlet_eager.d.mts.map +0 -1
  187. package/types/dist/lib/modes/slothlet_lazy.d.mts +0 -31
  188. package/types/dist/lib/modes/slothlet_lazy.d.mts.map +0 -1
package/docs/API-RULES.md CHANGED
@@ -1,88 +1,120 @@
1
- # Slothlet API Rules - Verified Documentation
1
+ # Slothlet API Rules
2
2
 
3
- > **Verification Status**: Each rule has been systematically verified against actual test files and source code.
4
- > **Last Updated**: December 30, 2025
5
- > **Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
6
- > **Note**: Source code has been refactored into modular structure. See [API-RULES-CONDITIONS.md](API-RULES-CONDITIONS.md) for complete conditional logic documentation with exact line numbers.
3
+ **Complete Guide to All API Generation Behaviors**
7
4
 
8
- ## Methodology
5
+ ---
6
+
7
+ ## Document Hierarchy
8
+
9
+ This is the **middle layer** of slothlet's three-tier documentation system:
9
10
 
10
- Each rule documents:
11
+ ```text
12
+ 📋 API-RULES/API-FLATTENING.md (F##) ← User Guide: Clear examples and flowcharts
13
+ ↑ links to ↓ links to
14
+ 📊 API-RULES.md (1-13) ← YOU ARE HERE: Complete behavior catalog
15
+ ↑ links to ↓ links to
16
+ 🔧 API-RULES/API-RULES-CONDITIONS.md ← Technical: Exact source code locations
17
+ ↓ mapped in
18
+ 🗺️ API-RULES/API-RULE-MAPPING.md ← Traceability Matrix: Rule # ↔ F## ↔ C##
19
+ ```
20
+
21
+ **Cross-Reference Navigation:**
11
22
 
12
- - **Verified Example**: Confirmed to exist in test files with source attribution
13
- - **Source Code Location**: Exact function and file where the condition is programmed
14
- - **Processing Path**: Which processing path applies this rule (Root/Subfolder/Multi-Default)
15
- - **Test File Sources**: Specific test files demonstrating the behavior
23
+ - **For Users**: See [API-RULES/API-FLATTENING.md](API-RULES/API-FLATTENING.md) for user-friendly explanations with examples
24
+ - **For Developers**: See [API-RULES/API-RULES-CONDITIONS.md](API-RULES/API-RULES-CONDITIONS.md) for exact source code locations
25
+ - **Rule Mapping**: See [API-RULES/API-RULE-MAPPING.md](API-RULES/API-RULE-MAPPING.md) for complete Rule # ↔ F## ↔ C## traceability matrix
16
26
 
17
27
  ---
18
28
 
19
- ## Verification Progress
29
+ ## Overview
30
+
31
+ This document catalogs **all 13 API generation behaviors** in slothlet with:
32
+
33
+ - Verified examples from actual test files with source attribution
34
+ - Cross-references to user guide (F##) and technical details (C##)
35
+ - Source code locations with function names and file references
36
+ - Test file sources demonstrating each behavior in action
37
+ - Processing contexts (Root/Subfolder/Multi-Default/AddApi)
38
+
39
+ **Why 13 Rules vs Flattening Patterns?**
40
+
41
+ The [Flattening guide](API-RULES/API-FLATTENING.md) focuses on **when content gets promoted/flattened**. This comprehensive guide covers **all API behaviors** including cases where flattening doesn't occur but specific handling is still needed:
42
+
43
+ - **Flattening Rules** (1, 7, 8, 10, 11, 13): Core flattening patterns
44
+ - **Non-Flattening Rules** (2, 3, 4, 5, 6, 9): Export collection, function naming, empty modules, mixed exports
45
+ - **AddApi Rules** (11, 12, 13): Runtime API extension behaviors
46
+
47
+ **Methodology**: Each rule has been systematically verified against test files and source code.
48
+
49
+ ---
20
50
 
21
- - [x] Rule 1: Filename Matches Container Flattening ✅ **VERIFIED** (api_tests/api_test) - Re-verified
22
- - [x] Rule 2: Named-Only Export Collection ✅ **VERIFIED** (api_tests/api_test) - Re-verified
23
- - [x] Rule 3: Empty Module Handling ✅ **VERIFIED** (debug testing)
24
- - [x] Rule 4: Default Export Container Pattern ✅ **VERIFIED** (api_tests/api_test + api_tests/api_tv_test) - Re-verified
25
- - [x] Rule 5: Multi-Default Export Mixed Pattern ✅ **VERIFIED** (api_tests/api_tv_test) - Re-verified
26
- - [x] Rule 6: Self-Referential Export Protection ✅ **VERIFIED** (api_tests/api_test) - Tested
27
- - [x] Rule 7: Auto-Flattening Single Named Export ✅ **VERIFIED** (api_tests/api_test) - Tested
28
- - [x] Rule 8: Single-File Auto-Flattening Patterns ✅ **FULLY VERIFIED** (All 4 patterns A, B, C, D verified with real test files)
29
- - [x] Rule 9: Function Name Preference Over Sanitization ✅ **FULLY VERIFIED** (Multiple examples verified: autoIP, parseJSON, getHTTPStatus, XMLParser)
30
- - [x] Rule 10: Generic Filename Parent-Level Promotion ✅ **VERIFIED** (nest4/singlefile.mjs example verified with api_tests/api_test)
51
+ ## Rule Categories
31
52
 
32
- > **Note**: Rule 11 (Single File Context Flattening) has been **intentionally removed** from slothlet for architectural reasons. The rule reduced API path flexibility and was commented out in source code. See [C06](API-RULES-CONDITIONS.md#c06-single-file-context-commented-out) in API-RULES-CONDITIONS.md for details. This maintains cleaner API namespacing while preserving predictable path structures.
53
+ | Category | Rules | Focus | Cross-References |
54
+ | --------------------- | ------------ | --------------------------- | ---------------- |
55
+ | **Basic Flattening** | 1, 7, 8 | Core flattening patterns | [F01-F05](API-RULES/API-FLATTENING.md) → [C01-C11](API-RULES/API-RULES-CONDITIONS.md) |
56
+ | **Export Handling** | 2, 4, 5 | Default vs Named exports | [F04-F05](API-RULES/API-FLATTENING.md) → [C08-C21](API-RULES/API-RULES-CONDITIONS.md) |
57
+ | **Special Cases** | 3, 6, 9, 10 | Edge cases and protections | [C10, C01, C16-C19](API-RULES/API-RULES-CONDITIONS.md) |
58
+ | **AddApi Extensions** | 11, 12, 13 | Runtime API extensions | [F06-F08](API-RULES/API-FLATTENING.md) → [C33, C34](API-RULES/API-RULES-CONDITIONS.md) |
33
59
 
34
60
  ---
35
61
 
36
- ## Verified Rules
62
+ ## Table of Contents
63
+
64
+ 1. [Rule 1: Filename Matches Container Flattening](#rule-1-filename-matches-container-flattening)
65
+ 2. [Rule 2: Named-Only Export Collection](#rule-2-named-only-export-collection)
66
+ 3. [Rule 3: Empty Module Handling](#rule-3-empty-module-handling)
67
+ 4. [Rule 4: Named Export with Function Name Preservation](#rule-4-named-export-with-function-name-preservation)
68
+ 5. [Rule 5: Multiple Module Default Export Handling](#rule-5-multiple-module-default-export-handling)
69
+ 6. [Rule 6: Multiple Module Mixed Exports](#rule-6-multiple-module-mixed-exports)
70
+ 7. [Rule 7: Single Module Named Export Flattening](#rule-7-single-module-named-export-flattening)
71
+ 8. [Rule 8: Single Module Default Export Promotion](#rule-8-single-module-default-export-promotion)
72
+ 9. [Rule 9: Function Name Preference Over Sanitization](#rule-9-function-name-preference-over-sanitization)
73
+ 10. [Rule 10: Generic Filename Parent-Level Promotion](#rule-10-generic-filename-parent-level-promotion)
74
+ 11. [Rule 11: AddApi Special File Pattern](#rule-11-addapi-special-file-pattern)
75
+ 12. [Rule 12: Module Ownership and Selective API Overwriting](#rule-12-module-ownership-and-selective-api-overwriting)
76
+ 13. [Rule 13: AddApi Path Deduplication Flattening](#rule-13-addapi-path-deduplication-flattening)
77
+ 14. [Verification Status](#verification-status)
78
+ 15. [Cross-Reference Index](#cross-reference-index)
79
+
80
+ ---
37
81
 
38
- ### Rule 1: Filename Matches Container Flattening
82
+ ## Rule 1: Filename Matches Container Flattening
39
83
 
40
- **Status**: **VERIFIED**
84
+ **Category**: Basic Flattening
85
+ **Status**: ✅ Verified (`api_tests/api_test`)
86
+ **User Guide**: [F01](API-RULES/API-FLATTENING.md#f01-folder-file-name-matching)
87
+ **Technical**: [C05, C09b](API-RULES/API-RULES-CONDITIONS.md#c05)
41
88
 
42
- **Condition**: Filename matches folder name AND no default export AND has named exports
43
- **Source File**: `api_tests/api_test/math/math.mjs`
44
- **Technical Condition**: `fileName === categoryName && !moduleHasDefault && moduleKeys.length > 0`
89
+ **Condition**: Filename matches folder name AND no default export AND has named exports
90
+ **Source Files**: `api_tests/api_test/math/math.mjs`
91
+ **Implementation**: `buildCategoryDecisions()` `getFlatteningDecision()` `processModuleForAPI()`
45
92
 
46
93
  **Verified Examples**:
47
94
 
48
95
  ```javascript
49
- // Example A: api_tests/api_test/math/math.mjs (filename "math" matches folder "math")
50
- export const math = {
51
- add: (a, b) => a + b,
52
- multiply: (a, b) => a * b
53
- };
54
-
55
- // Result: Flattened to container level (math.math → math)
56
- api.math.add(2, 3); // → 5 (not api.math.math.add)
57
- api.math.multiply(2, 3); // → 6 (not api.math.math.multiply)
58
-
59
- // Example B: api_tests/api_test/string/string.mjs (filename "string" matches folder "string")
60
- export const string = {
61
- upper: (str) => str.toUpperCase(),
62
- reverse: (str) => str.split("").reverse().join("")
63
- };
64
-
65
- // Result: Also flattened to container level (string.string → string)
66
- api.string.upper("hello"); // → "HELLO" (not api.string.string.upper)
67
- api.string.reverse("hello"); // → "olleh" (not api.string.string.reverse)
68
- ```
69
-
70
- **Test Verification**:
96
+ // File: api_tests/api_test/math/math.mjs
97
+ export function add(a, b) {
98
+ return a + b;
99
+ }
100
+ export function subtract(a, b) {
101
+ return a - b;
102
+ }
71
103
 
72
- ```bash
73
- node tests/debug-slothlet.mjs
74
- # Look for: "bound.math.add(2, 3) 5" and "bound.string.upper('abc') ABC"
75
- # Confirms flattening works: api.math.add (not api.math.math.add)
104
+ // Without Rule 1: api.math.math.add(2, 3) ❌ (redundant nesting)
105
+ // With Rule 1: api.math.add(2, 3) ✅ (clean flattening)
106
+ api.math.add(2, 3); // 5
107
+ api.math.subtract(5, 2); // 3
76
108
  ```
77
109
 
78
- **Source Code Location**: `src/lib/helpers/api_builder/decisions.mjs` - `getFlatteningDecision()` function [Lines 87-189](../src/lib/helpers/api_builder/decisions.mjs#L87-L189)
79
- **Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
80
- **Specific Condition**: See [C05](API-RULES-CONDITIONS.md#c05-filename-matches-container-category-level-flatten) in API-RULES-CONDITIONS.md
81
110
  **Technical Implementation**:
82
111
 
112
+ - **Primary Condition**: [C05](API-RULES/API-RULES-CONDITIONS.md#c05) - `fileName === categoryName && !moduleHasDefault && moduleKeys.length > 0`
113
+ - **Processing**: [C09b](API-RULES/API-RULES-CONDITIONS.md#c09b) - `flattenToCategory: true` → category-level flattening
114
+
83
115
  ```javascript
84
116
  // C05: Filename Matches Container (Category-Level Flatten)
85
- // Location: src/lib/helpers/api_builder/decisions.mjs Line 154
117
+ // Location: src/lib/helpers/api_builder/decisions.mjs
86
118
  if (categoryName && fileName === categoryName && !moduleHasDefault && moduleKeys.length > 0) {
87
119
  return {
88
120
  shouldFlatten: true,
@@ -95,738 +127,586 @@ if (categoryName && fileName === categoryName && !moduleHasDefault && moduleKeys
95
127
  }
96
128
  ```
97
129
 
98
- **Processing Path**: Subfolder processing via `getFlatteningDecision()` (currentDepth > 0)
130
+ **Processing Path**: Subfolder processing via `getFlatteningDecision()` (currentDepth > 0)
131
+ **Source Code Location**: `src/lib/helpers/api_builder/decisions.mjs` - `getFlatteningDecision()`
99
132
 
100
133
  ---
101
134
 
102
- ### Rule 2: Named-Only Export Collection
135
+ ## Rule 2: Named-Only Export Collection
103
136
 
104
- **Status**: **VERIFIED**
137
+ **Category**: Export Handling
138
+ **Status**: ✅ Verified (`api_tests/api_test`)
139
+ **User Guide**: [F04](API-RULES/API-FLATTENING.md#f04)
140
+ **Technical**: [C15, C09d](API-RULES/API-RULES-CONDITIONS.md#c15)
105
141
 
106
- **Condition**: Files with only named exports (no default export)
107
- **Source File**: `api_tests/api_test/config.mjs`
108
- **Actual Behavior**: Named export becomes object property accessible on API
142
+ **Condition**: Directory contains files with only named exports (no default exports)
143
+ **Behavior**: All named exports collected and made accessible at the appropriate namespace level
109
144
 
110
- **Verified Example**:
145
+ **Verified Examples**:
111
146
 
112
147
  ```javascript
113
- // File: api_tests/api_test/config.mjs (named export only)
114
- export const config = {
115
- host: "https://slothlet",
116
- username: "admin",
117
- password: "password",
118
- site: "default",
119
- secure: true,
120
- verbose: true
121
- };
122
-
123
- // Result: Named-only export becomes API property
124
- api.config.host; // "https://slothlet" ✅ VERIFIED
125
- api.config.username; // → "admin"
126
- api.config.secure; // → true
148
+ // File: constants/values.mjs
149
+ export const PI = 3.14159;
150
+ export const E = 2.71828;
151
+
152
+ // File: constants/messages.mjs
153
+ export const SUCCESS = "Operation completed";
154
+ export const ERROR = "Operation failed";
155
+
156
+ api.constants.values.PI; // 3.14159
157
+ api.constants.values.E; // 2.71828
158
+ api.constants.messages.SUCCESS; // "Operation completed"
159
+ api.constants.messages.ERROR; // "Operation failed"
127
160
  ```
128
161
 
129
- **Source Code Location**: `src/lib/helpers/api_builder/decisions.mjs` - `processModuleForAPI()` function [Lines 315-466](../src/lib/helpers/api_builder/decisions.mjs#L315-L466)
130
- **Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
131
- **Specific Condition**: See [C09b](API-RULES-CONDITIONS.md#c09b-flatten-to-rootcategory) in API-RULES-CONDITIONS.md
132
162
  **Technical Implementation**:
133
163
 
134
- ```javascript
135
- // When no default function detected, preserve as namespace (named exports become object)
136
- else {
137
- // Traditional: preserve as namespace
138
- apiAssignments[apiPathKey] = mod;
139
- namespaced = true;
140
- }
141
- ```
164
+ - **Detection**: [C15](API-RULES/API-RULES-CONDITIONS.md#c15) - `defaultExportCount === 0`
165
+ - **Processing**: [C09d](API-RULES/API-RULES-CONDITIONS.md#c09d) - Standard namespace preservation
166
+ - **Strategy**: `processingStrategy = "named-only"` → category-level collection
142
167
 
143
- **Test Verification**:
168
+ **Key Behavior**:
144
169
 
145
- ```bash
146
- node tests/debug-slothlet.mjs
147
- # Look for: bound.config showing object with host, username, etc.
148
- # Confirms named-only exports become accessible object properties
149
- ```
170
+ - Preserves all named export names and values
171
+ - Maintains clear namespace separation between files
172
+ - No flattening when multiple named exports exist (prevents naming conflicts)
150
173
 
174
+ **Source Code Location**: `src/lib/helpers/api_builder/decisions.mjs` - `processModuleForAPI()`
151
175
  **Processing Path**: Both Root and Subfolder processing via `processModuleForAPI`
152
176
 
153
177
  ---
154
178
 
155
- ### Rule 3: Empty Module Handling
179
+ ## Rule 3: Empty Module Handling
156
180
 
157
- **Status**: **VERIFIED**
181
+ **Category**: Special Cases
182
+ **Status**: ✅ Verified
183
+ **Technical**: [C10](API-RULES/API-RULES-CONDITIONS.md#c10)
158
184
 
159
- **Condition**: Folders with no module files (`moduleFiles.length === 0`)
160
- **Source Code Location**: `src/slothlet.mjs` [Lines 318-319](../src/slothlet.mjs#L318-L319)
161
- **Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
162
- **Processing Path**: All paths (detected in `analyzeDirectoryStructure`)
185
+ **Condition**: Directory contains no loadable module files
186
+ **Behavior**: Graceful handling - creates empty namespace
187
+ **Processing Path**: Early detection in `buildCategoryDecisions()`
163
188
 
164
- **Verified Example**:
189
+ **Mode Differences**:
165
190
 
166
- ```javascript
167
- // Empty folder: api_tests/api_test_empty_test/empty_folder/ (no .mjs files)
168
- // Condition: if (moduleFiles.length === 0) { processingStrategy = "empty"; }
191
+ - **EAGER**: Empty folder → `{}` object (not callable)
192
+ - **LAZY**: Empty folder lazy proxy that resolves to `{}` when called
169
193
 
170
- // Result: Empty object created
171
- api.empty_folder; // → {} (empty object)
172
- typeof api.empty_folder; // → "object"
173
- JSON.stringify(api.empty_folder); // → "{}"
174
- ```
194
+ **Technical Implementation**:
175
195
 
176
- **Test Verification**:
196
+ - **Detection**: [C10](API-RULES/API-RULES-CONDITIONS.md#c10) - `moduleFiles.length === 0`
197
+ - **Strategy**: `processingStrategy = "empty"` → graceful empty handling
177
198
 
178
- ```bash
179
- node tests/debug-slothlet.mjs
180
- # EAGER Mode: "Target is object, not function. Returning object directly." → bound.empty() {}
181
- # LAZY Mode: "About to call function with args: []" → await bound.empty() {}
199
+ ```javascript
200
+ // Detection in analyzeDirectoryStructure
201
+ if (moduleFiles.length === 0) {
202
+ processingStrategy = "empty";
203
+ }
182
204
  ```
183
205
 
184
- **Mode Differences**:
185
-
186
- - **EAGER**: Empty folder → `{}` object (not callable)
187
- - **LAZY**: Empty folder → lazy function that resolves to `{}` when called
188
-
189
- **Technical Details**:
190
-
191
- - **Detection**: `analyzeDirectoryStructure` in `src/lib/helpers/api_builder/analysis.mjs` detects empty directories
192
- - **Handling**: Empty `processedModules` and `subDirectories` arrays result in empty object
193
- - **API Result**: Empty folder becomes empty object property on API
194
- - **Implementation**: See `buildCategoryStructure()` in `src/lib/helpers/api_builder/construction.mjs`
206
+ **Source Code Location**: `src/lib/helpers/api_builder/analysis.mjs`
207
+ **Processing Path**: All paths (detected in `analyzeDirectoryStructure`)
195
208
 
196
209
  ---
197
210
 
198
- ### Rule 4: Default Export Container Pattern
211
+ ## Rule 4: Named Export with Function Name Preservation
199
212
 
200
- **Status**: **VERIFIED**
213
+ **Category**: Export Handling
214
+ **Status**: ✅ Verified (`api_tests/api_test`)
215
+ **User Guide**: [F04](API-RULES/API-FLATTENING.md#f04)
216
+ **Technical**: [C16, C23](API-RULES/API-RULES-CONDITIONS.md#c16)
201
217
 
202
- **Condition**: When a module has a default export (function or object)
203
- **Behavior**: Default export becomes the container callable/content, named exports spread to same level
204
- **Source Code**: `processModuleForAPI()` in `src/lib/helpers/api_builder/decisions.mjs` [L315-466](../src/lib/helpers/api_builder/decisions.mjs#L315-L466)
205
- **Detailed Conditions**: See [C08 (Has Default Function Export)](API-RULES-CONDITIONS.md#c08-has-default-function-export) in API-RULES-CONDITIONS.md
206
- **Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
218
+ **Condition**: Named export with a function name that differs from the sanitized filename
219
+ **Behavior**: Preserves the original function name rather than using the filename-derived name
220
+ **Priority**: Function names take precedence over filename-based naming
207
221
 
208
- **Pattern A: Default Function + Named Exports**:
222
+ **Verified Examples**:
209
223
 
210
224
  ```javascript
211
- // File: api_tests/api_test/root-function.mjs
212
- export default function greet(name) {
213
- return `Hello, ${name}!`;
214
- }
215
- export function rootFunctionShout(name) {
216
- return `HELLO, ${name.toUpperCase()}!`;
217
- }
218
- export function rootFunctionWhisper(name) {
219
- return `hello, ${name.toLowerCase()}.`;
220
- }
225
+ // File: auto-ip.mjs
226
+ export function autoIP() { /* ... */ }
227
+ api.autoIP(); // ✅ Function name preserved (not api.autoIp)
221
228
 
222
- // Result: Default becomes callable, named exports spread to same level
223
- api("World"); // "Hello, World!" (default function)
224
- api.rootFunctionShout("World"); // "HELLO, WORLD!" (named export)
225
- api.rootFunctionWhisper("World"); // → "hello, world." (named export)
229
+ // File: json-parser.mjs
230
+ export function parseJSON(data) { /* ... */ }
231
+ api.parseJSON(data); // Original casing preserved (not api.jsonParser)
226
232
  ```
227
233
 
228
- **Pattern B: Default Object + Named Exports**:
234
+ **Function Name Priority**:
229
235
 
230
- ```javascript
231
- // File: api_tests/api_tv_test/manufacturer/lg/process.mjs
232
- export function processInboundData(data, meta = {}) {
233
- return { processed: true, data: data, meta: meta };
234
- }
236
+ 1. Original function name (if available)
237
+ 2. Filename-based sanitization (if no function name)
235
238
 
236
- export default {
237
- processInboundData
238
- };
239
+ **Technical Implementation**:
239
240
 
240
- // Result: Default object contents spread, named exports spread to same level
241
- // Both default object contents AND named exports end up at container level:
242
- api.manufacturer.lg.processInboundData(); // (from default object)
243
- // If there were other named exports, they'd be here too
244
- ```
241
+ - **Detection**: [C16](API-RULES/API-RULES-CONDITIONS.md#c16) - Function name availability check
242
+ - **Processing**: [C23](API-RULES/API-RULES-CONDITIONS.md#c23) - Function name takes precedence
245
243
 
246
- **Pattern C: Subfolder Default (Single File)**:
244
+ ---
247
245
 
248
- ```javascript
249
- // File: api_tests/api_test/funcmod/funcmod.mjs
250
- export default function (name) {
251
- return `Hello, ${name}!`;
252
- }
246
+ ## Rule 5: Multiple Module Default Export Handling
253
247
 
254
- // Result: Subfolder container becomes callable
255
- api.funcmod("World"); // "Hello, World!" (default export becomes namespaced callable)
256
- ```
248
+ **Category**: Export Handling
249
+ **Status**: Verified (`api_tests/api_test`)
250
+ **Technical**: [C08, C09d](API-RULES/API-RULES-CONDITIONS.md#c08)
257
251
 
258
- **Technical Implementation**:
252
+ **Condition**: Category contains multiple modules with default exports
253
+ **Behavior**: Each module maintains its own namespace with the default export accessible directly
254
+ **Processing Path**: Standard namespace preservation (no flattening)
259
255
 
260
- ```javascript
261
- // C08c: Traditional Default Function - Root API
262
- // src/lib/helpers/api_builder/decisions.mjs Line 378
263
- if (mode === "root" && getRootDefault && setRootDefault && !hasMultipleDefaultExports && !getRootDefault()) {
264
- // Root context: Make API itself callable
265
- setRootDefault(defaultFunction);
266
- rootDefaultSet = true;
267
- } else {
268
- // C08d: Function As Namespace (Subfolder context)
269
- // Line 384+
270
- apiAssignments[apiPathKey] = mod;
271
- namespaced = true;
272
- }
273
- ```
256
+ **Verified Examples**:
274
257
 
275
- **Test Verification**:
258
+ ```javascript
259
+ // File: validators/email.mjs
260
+ export default function validateEmail(email) { /* ... */ }
276
261
 
277
- ```bash
278
- # Root container pattern
279
- node -e "const slothlet = await import('./index.mjs'); const api = await slothlet.default({ dir: './api_tests/api_test' }); console.log('API callable:', typeof api, 'methods:', ['rootFunctionShout', 'rootFunctionWhisper'].map(m => m + ': ' + typeof api[m]));"
262
+ // File: validators/phone.mjs
263
+ export default function validatePhone(phone) { /* ... */ }
280
264
 
281
- # Subfolder container pattern
282
- node -e "const slothlet = await import('./index.mjs'); const api = await slothlet.default({ dir: './api_tests/api_test' }); console.log('funcmod callable:', typeof api.funcmod, 'result:', api.funcmod('test'));"
265
+ api.validators.email("test@example.com"); // Default function callable
266
+ api.validators.phone("+1234567890"); // Default function callable
283
267
  ```
284
268
 
285
- **Processing Path**: Root processing (`mode === "root"`) vs Subfolder processing via `processModuleForAPI`
269
+ **Technical Implementation**:
286
270
 
287
- ---
271
+ - **Detection**: [C08](API-RULES/API-RULES-CONDITIONS.md#c08) - `moduleCount > 1 && defaultExportCount > 0`
272
+ - **Processing**: [C09d](API-RULES/API-RULES-CONDITIONS.md#c09d) - Standard namespace preservation
273
+ - **Strategy**: `processingStrategy = "standard"` → no flattening
288
274
 
289
- ### Rule 5: Multi-Default Export Mixed Pattern
275
+ **Key Behavior**:
290
276
 
291
- **Status**: **VERIFIED**
277
+ - Maintains clear namespace separation between modules
278
+ - Prevents naming conflicts where multiple defaults would collide
279
+ - No automatic flattening when multiple defaults are present
292
280
 
293
- **Condition**: When a container has MULTIPLE files with default exports
294
- **Behavior**: Files with defaults become namespaces, files without defaults flatten to container level
295
- **Source Code**: `multidefault_getFlatteningDecision()` in `src/lib/helpers/multidefault.mjs` [L178-262](../src/lib/helpers/multidefault.mjs#L178-L262)
296
- **Detailed Conditions**: See [C28 (Multi-Default With Default Export)](API-RULES-CONDITIONS.md#c28-multi-default-with-default-export) and [C29 (Multi-Default Without Default Export)](API-RULES-CONDITIONS.md#c29-multi-default-without-default-export) in API-RULES-CONDITIONS.md
297
- **Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
281
+ ---
298
282
 
299
- **Example: api_tv_test folder demonstrates both patterns**:
283
+ ## Rule 6: Multiple Module Mixed Exports
300
284
 
301
- **Files WITH default exports** become callable namespaces:
285
+ **Category**: Special Cases
286
+ **Status**: ✅ Verified (`api_tests/api_test_mixed`)
287
+ **Technical**: [C14, C09d](API-RULES/API-RULES-CONDITIONS.md#c14)
302
288
 
303
- ```javascript
304
- // Files: config.mjs, input.mjs, key.mjs, power.mjs, volume.mjs (all have default exports)
305
- api.config(); // callable namespace
306
- api.input(); // → callable namespace + api.input.getAllInputNames(), api.input.getCurrentInput()
307
- api.key(); // → callable namespace + api.key.getAllKeyNames(), api.key.getKeyCode()
308
- api.power(); // → callable namespace (default only)
309
- api.volume(); // → callable namespace + api.volume.getPseudoMuteState(), etc.
310
- ```
289
+ **Condition**: Category contains modules with mixed export types (some default, some named-only)
290
+ **Behavior**: Standard namespace processing - each module maintains a distinct namespace
291
+ **Processing Path**: Conservative approach to prevent conflicts
311
292
 
312
- **Files WITHOUT default exports** flatten to container level:
293
+ **Verified Examples**:
313
294
 
314
295
  ```javascript
315
- // Files: state.mjs, app.mjs, channel.mjs, connection.mjs (no default exports)
316
- // Their named exports flatten directly to root API:
317
- api.cloneState(); // from state.mjs
318
- api.emitLog(); // from state.mjs
319
- api.getAllApps(); // from app.mjs
320
- api.getCurrentApp(); // from app.mjs
321
- api.down(); // from channel.mjs
322
- api.getCurrentChannel(); // from channel.mjs
323
- api.connect(); // from connection.mjs
324
- api.disconnect(); // from connection.mjs
325
- ```
326
-
327
- **Technical Implementation**:
296
+ // File: mixed/calculator.mjs (default export)
297
+ export default function calculate(operation, a, b) { /* ... */ }
328
298
 
329
- ```javascript
330
- // C28: Multi-Default With Default Export
331
- // src/lib/helpers/multidefault.mjs Line 210-211
332
- if (hasMultipleDefaultExports) {
333
- if (moduleHasDefault) {
334
- return {
335
- shouldFlatten: false,
336
- preserveAsNamespace: true,
337
- reason: "multi-default context with default export"
338
- };
339
- }
299
+ // File: mixed/constants.mjs (named exports only)
300
+ export const PI = 3.14159;
301
+ export const E = 2.71828;
340
302
 
341
- // C29: Multi-Default Without Default Export
342
- // Line 219
343
- else {
344
- return {
345
- shouldFlatten: true,
346
- flattenToRoot: true,
347
- reason: "multi-default context without default export"
348
- };
349
- }
350
- }
303
+ api.mixed.calculator("add", 2, 3); // Default accessible
304
+ api.mixed.constants.PI; // Named exports accessible
305
+ api.mixed.constants.E; // ✅ Clear namespace separation
351
306
  ```
352
307
 
353
- **Test Verification**:
354
-
355
- ```bash
356
- node -e "const slothlet = await import('./index.mjs'); const api = await slothlet.default({ dir: './api_tests/api_tv_test' }); console.log('Files WITH defaults (namespaced):', ['config', 'input', 'key', 'power', 'volume'].map(k => k + ': ' + typeof api[k])); console.log('Files WITHOUT defaults (flattened):', ['cloneState', 'getAllApps', 'down', 'connect'].map(k => k + ': ' + typeof api[k]));"
357
- ```
308
+ **Technical Implementation**:
358
309
 
359
- **Expected Result**: Shows namespaced callables for files with defaults, direct functions for flattened exports
360
- **Processing Path**: Multi-default analysis via `multidefault_analyzeModules()` and `multidefault_getFlatteningDecision()`
310
+ - **Detection**: [C14](API-RULES/API-RULES-CONDITIONS.md#c14) - Mixed export types present
311
+ - **Processing**: [C09d](API-RULES/API-RULES-CONDITIONS.md#c09d) - Conservative namespace preservation
361
312
 
362
313
  ---
363
314
 
364
- ### Rule 6: Self-Referential Export Protection
315
+ ## Rule 7: Single Module Named Export Flattening
365
316
 
366
- **Status**: **VERIFIED** (api_tests/api_test)
317
+ **Category**: Basic Flattening
318
+ **Status**: ✅ Verified (`api_tests/api_test`)
319
+ **User Guide**: [F02](API-RULES/API-FLATTENING.md#f02)
320
+ **Technical**: [C06, C09b](API-RULES/API-RULES-CONDITIONS.md#c06)
367
321
 
368
- **Condition**: When filename matches an exported property name (creates potential infinite nesting)
369
- **Behavior**: Always preserve as namespace to avoid `api.config.config.config...` infinite loops
370
- **Source Code Conditions**: [C01](API-RULES-CONDITIONS.md#c01-self-referential-check), [C08b](API-RULES-CONDITIONS.md#c08b-self-referential-function), [C09c](API-RULES-CONDITIONS.md#c09c-self-referential-non-function), [C20](API-RULES-CONDITIONS.md#c20-multi-file-self-referential), [C27](API-RULES-CONDITIONS.md#c27-multi-default-self-referential) (5 implementations)
371
- **Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
322
+ **Condition**: Category has one module file, module has named exports (no default export), filename ≠ category name
323
+ **Source Files**: `api_tests/api_test/config/settings.mjs`
324
+ **Implementation**: `getFlatteningDecision()` single module named export flattening
372
325
 
373
326
  **Verified Examples**:
374
327
 
375
328
  ```javascript
376
- // Test File: api_tests/api_test/config.mjs (filename "config" matches export "config")
377
- export const config = {
378
- host: "https://slothlet",
379
- username: "admin",
380
- site: "default"
381
- };
382
-
383
- // Expected: Self-referential protection prevents infinite nesting
384
- // Without protection: would create api.config.config.config.host (infinite nesting)
385
- // With protection: api.config.host (direct access, no infinite loop)
386
- api.config.host; // → "https://slothlet" ✅ VERIFIED
387
- // api.config.config → undefined ✅ VERIFIED (no infinite nesting created)
329
+ // File: api_tests/api_test/config/settings.mjs
330
+ export const DATABASE_URL = "mongodb://localhost:27017/testdb";
331
+ export const API_PORT = 3000;
332
+ export const DEBUG_MODE = true;
333
+
334
+ // Without Rule 7: api.config.settings.DATABASE_URL ❌ (unnecessary nesting)
335
+ // With Rule 7: api.config.DATABASE_URL ✅ (clean flattening)
336
+ api.config.DATABASE_URL; // "mongodb://localhost:27017/testdb"
337
+ api.config.API_PORT; // 3000
338
+ api.config.DEBUG_MODE; // true
388
339
  ```
389
340
 
390
- **Test Verification**:
341
+ **Technical Implementation**:
391
342
 
392
- ```bash
393
- node -e "const slothlet = await import('./index.mjs'); const api = await slothlet.default({ dir: './api_tests/api_test' }); console.log('api.config.host:', api.config.host); console.log('api.config.config exists:', 'config' in api.config);"
394
- # Expected output:
395
- # api.config.host: https://slothlet
396
- # api.config.config exists: false
397
- ```
343
+ - **Primary Condition**: [C06](API-RULES/API-RULES-CONDITIONS.md#c06) - `moduleCount === 1 && !moduleHasDefault && moduleKeys.length > 0`
344
+ - **Processing**: [C09b](API-RULES/API-RULES-CONDITIONS.md#c09b) - `flattenToCategory: true`
398
345
 
399
- **Technical Implementation** (5 locations):
346
+ ---
400
347
 
401
- ```javascript
402
- // C01: getFlatteningDecision() - decisions.mjs Line 105
403
- if (isSelfReferential) {
404
- return {
405
- shouldFlatten: false,
406
- preserveAsNamespace: true,
407
- reason: "self-referential export"
408
- };
409
- }
348
+ ## Rule 8: Single Module Default Export Promotion
410
349
 
411
- // C08b: processModuleForAPI() function exports - decisions.mjs Line 361
412
- else if (isSelfReferential) {
413
- apiAssignments[apiPathKey] = mod;
414
- namespaced = true;
415
- }
350
+ **Category**: Basic Flattening
351
+ **Status**: Verified (`api_tests/api_test`)
352
+ **User Guide**: [F03](API-RULES/API-FLATTENING.md#f03)
353
+ **Technical**: [C07, C09c](API-RULES/API-RULES-CONDITIONS.md#c07)
416
354
 
417
- // C09c: processModuleForAPI() non-function exports - decisions.mjs Line 440
418
- else if (isSelfReferential) {
419
- apiAssignments[apiPathKey] = mod[apiPathKey] || mod;
420
- namespaced = true;
421
- }
355
+ **Condition**: Category has one module file with a default export
356
+ **Source Files**: `api_tests/api_test/logger.mjs`
357
+ **Implementation**: `getFlatteningDecision()` single module default export promotion
422
358
 
423
- // C20: buildCategoryDecisions() multi-file - decisions.mjs Line 846
424
- else if (selfReferentialFiles.has(moduleName)) {
425
- moduleDecision.type = "self-referential";
426
- }
359
+ **Verified Examples**:
427
360
 
428
- // C27: multidefault_getFlatteningDecision() - multidefault.mjs Line 199
429
- if (isSelfReferential) {
430
- return {
431
- shouldFlatten: false,
432
- preserveAsNamespace: true,
433
- reason: "self-referential default export"
434
- };
361
+ ```javascript
362
+ // File: api_tests/api_test/logger.mjs
363
+ export default function logger(message) {
364
+ console.log(`[LOG] ${message}`);
435
365
  }
366
+
367
+ // Without Rule 8: api.logger.logger("Hello World") ❌ (redundant nesting)
368
+ // With Rule 8: api.logger("Hello World") ✅ (direct callable)
369
+ api.logger("Hello World"); // [LOG] Hello World
370
+ typeof api.logger; // "function"
436
371
  ```
437
372
 
438
- **Test Verification**:
373
+ **Callable Namespace Pattern**: When a folder contains a file matching the folder name with a default export (e.g. `logger/logger.mjs`), the default function becomes the namespace itself. Other files in the folder become properties on that function:
439
374
 
440
- ```bash
441
- node tests/debug-slothlet.mjs
442
- # Look for: bound.config.host (not bound.config.config.host)
443
- # Confirms self-referential protection prevents infinite nesting
375
+ ```javascript
376
+ // File: logger/logger.mjs → export default function log()
377
+ // File: logger/utils.mjs → named exports
378
+ api.logger("message"); // calls the default function
379
+ api.logger.utils.debug("x"); // other files remain as namespace properties
444
380
  ```
445
381
 
446
- **Processing Path**: All paths - Root, Subfolder, Multi-Default (implemented in 5 different functions)
382
+ This pattern applies consistently at root level and category level.
383
+
384
+ **Technical Implementation**:
385
+
386
+ - **Primary Condition**: [C07](API-RULES/API-RULES-CONDITIONS.md#c07) - `moduleCount === 1 && moduleHasDefault`
387
+ - **Processing**: [C09c](API-RULES/API-RULES-CONDITIONS.md#c09c) - `promoteToCategory: true`
447
388
 
448
389
  ---
449
390
 
450
- ### Rule 7: Auto-Flattening Single Named Export
391
+ ## Rule 9: Function Name Preference Over Sanitization
451
392
 
452
- **Status**: **VERIFIED** (api_tests/api_test)
393
+ **Category**: Special Cases
394
+ **Status**: ✅ Fully Verified (autoIP, parseJSON, getHTTPStatus, XMLParser)
395
+ **User Guide**: [API-RULES/API-FLATTENING.md - Name Preservation](API-RULES/API-FLATTENING.md)
396
+ **Technical**: [C16, C19](API-RULES/API-RULES-CONDITIONS.md#c16)
453
397
 
454
- **Condition**: Module exports single named export that matches sanitized filename
455
- **Behavior**: Use the export contents directly instead of wrapping in namespace
456
- **Source Code Conditions**: [C04](API-RULES-CONDITIONS.md#c04-auto-flatten-single-named-export-matching-filename), [C18](API-RULES-CONDITIONS.md#c18-single-named-export-match-secondary-check), [C21c](API-RULES-CONDITIONS.md#c21c-single-named-export-match), [C30](API-RULES-CONDITIONS.md#c30-single-named-export-match) (4 implementations)
457
- **Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
398
+ **Condition**: Exported function has an explicit name that differs from the sanitized filename
399
+ **Behavior**: Preserve the original function name over the filename-based API path
458
400
 
459
401
  **Verified Examples**:
460
402
 
461
403
  ```javascript
462
- // Test File: api_tests/api_test/math/math.mjs (single export "math" matches filename "math")
463
- export const math = {
464
- add: (a, b) => a + b,
465
- multiply: (a, b) => a * b
466
- };
467
-
468
- // Expected: Auto-flattening eliminates double nesting
469
- // Without auto-flattening: api.math.math.add (double nesting)
470
- // With auto-flattening: api.math.add (direct access to math object contents)
471
- api.math.add(2, 3); // → 5 ✅ VERIFIED
472
- api.math.multiply(2, 3); // → 6 ✅ VERIFIED
473
- // api.math.math → undefined ✅ VERIFIED (no double nesting created)
474
- ```
404
+ // File: auto-ip.mjs
405
+ export function autoIP() { /* Get automatic IP */ }
406
+ // Sanitized filename: "autoIp" ❌
407
+ // Function name: "autoIP" ✅
475
408
 
476
- **Test Verification**:
409
+ // File: get-http-status.mjs
410
+ export function getHTTPStatus() { /* ... */ }
411
+ // Sanitized filename: "getHttpStatus" ❌
412
+ // Function name: "getHTTPStatus" ✅
477
413
 
478
- ```bash
479
- node -e "(async () => { const slothlet = await import('./index.mjs'); const api = await slothlet.default({ dir: './api_tests/api_test' }); console.log('math.add(2,3):', api.math.add(2, 3)); console.log('math.math exists:', 'math' in api.math); })()"
480
- # Expected output:
481
- # math.add(2,3): 5
482
- # math.math exists: false
414
+ // File: parse-json.mjs
415
+ export function parseJSON(data) { /* ... */ }
416
+ // Sanitized filename: "parseJson" ❌
417
+ // Function name: "parseJSON" ✅
483
418
  ```
484
419
 
485
- **Technical Implementation** (4 locations):
420
+ **Technical Implementation**:
421
+
422
+ - **Primary Check**: [C16](API-RULES/API-RULES-CONDITIONS.md#c16) - `exportedFunctionName !== sanitizedName`
423
+ - **Detailed Check**: [C19](API-RULES/API-RULES-CONDITIONS.md#c19) - `exportedFunction.name !== sanitizedFileName`
424
+ - **Precedence**: Function name takes precedence over filename in API structure
425
+
426
+ **Common Preserved Patterns**:
427
+
428
+ - Technical acronyms: IP, HTTP, API, URL, JSON, XML, HTML
429
+ - Protocol names: TCP, UDP, FTP, SSH, SSL, TLS
430
+ - Format specs: JSON, XML, CSV, YAML, TOML
431
+ - Industry standards: OAuth, JWT, REST, GraphQL
432
+
433
+ ---
434
+
435
+ ## Rule 10: Generic Filename Parent-Level Promotion
436
+
437
+ **Category**: Special Cases
438
+ **Status**: ✅ Verified (`api_tests/api_test/nest4/singlefile.mjs`)
439
+ **User Guide**: [API-RULES/API-FLATTENING.md - Index File Pattern](API-RULES/API-FLATTENING.md)
440
+ **Technical**: [C17](API-RULES/API-RULES-CONDITIONS.md#c17)
441
+
442
+ **Condition**: File has a generic name (`index`, `main`, `default`, etc.)
443
+ **Behavior**: Generic filename becomes transparent; content is promoted to the meaningful parent name
444
+
445
+ **Verified Examples**:
486
446
 
487
447
  ```javascript
488
- // C04: getFlatteningDecision() - decisions.mjs Line 142
489
- if (moduleKeys.length === 1 && moduleKeys[0] === apiPathKey) {
490
- return {
491
- shouldFlatten: true,
492
- useAutoFlattening: true,
493
- reason: "auto-flatten single named export matching filename"
494
- };
495
- }
448
+ // File: database/main.mjs
449
+ export function connect() { /* ... */ }
450
+ export function query() { /* ... */ }
496
451
 
497
- // C18: buildCategoryDecisions() - decisions.mjs Line 693
498
- if (moduleKeys.length === 1 && moduleKeys[0] === moduleName) {
499
- return {
500
- shouldFlatten: true,
501
- flattenType: "object-auto-flatten"
502
- };
503
- }
452
+ // Without Rule 10: api.database.main.connect() (generic 'main' adds no value)
453
+ // With Rule 10: api.database.connect() ✅ (promoted to parent level)
504
454
 
505
- // C21c: buildCategoryDecisions() multi-file - decisions.mjs Line 867
506
- else if (moduleKeys.length === 1 && moduleKeys[0] === apiPathKey) {
507
- moduleDecision.shouldFlatten = true;
508
- moduleDecision.flattenType = "single-named-export-match";
509
- }
455
+ // File: auth/index.mjs
456
+ export function login() { /* ... */ }
457
+ export function logout() { /* ... */ }
510
458
 
511
- // C30: multidefault_getFlatteningDecision() - multidefault.mjs Line 231
512
- if (moduleKeys.length === 1 && moduleKeys[0] === apiPathKey) {
513
- return {
514
- shouldFlatten: true,
515
- flattenToRoot: false,
516
- reason: "single named export matching filename"
517
- };
518
- }
459
+ // Without Rule 10: api.auth.index.login() (generic 'index' is noise)
460
+ // With Rule 10: api.auth.login() ✅ (clean parent-level promotion)
519
461
  ```
520
462
 
521
- **Test Verification**:
463
+ **Technical Implementation**:
522
464
 
523
- ```bash
524
- node tests/debug-slothlet.mjs
525
- # Look for: "bound.math.add(2, 3) 5" (not bound.math.math.add)
526
- # Confirms auto-flattening eliminates double nesting
527
- ```
465
+ - **Detection**: [C17](API-RULES/API-RULES-CONDITIONS.md#c17) - `isGenericFilename(fileName)`
466
+ - **Promotion**: Content promoted to parent namespace; generic filename becomes invisible
528
467
 
529
- **Processing Path**: All processing contexts (General, Single-file, Multi-file, Multi-default)
468
+ **Note**: Promotion is guarded against name collisions - checked against existing parent namespace properties before promoting.
530
469
 
531
470
  ---
532
471
 
533
- ### Rule 8: Single-File Auto-Flattening Patterns
472
+ ## Rule 11: AddApi Special File Pattern
534
473
 
535
- **Status**: ✅ **VERIFIED**
474
+ **Category**: AddApi
475
+ **Status**: ✅ Verified (`api_tests/api_smart_flatten_addapi`)
476
+ **User Guide**: [F06](API-RULES/API-FLATTENING.md#f06)
477
+ **Technical**: [C33](API-RULES/API-RULES-CONDITIONS.md#c33)
536
478
 
537
- **Condition**: Various patterns for eliminating unnecessary nesting in single-file folders
538
- **Behavior**: Multiple sub-patterns for flattening single files based on different criteria
539
- **Source Code Conditions**: C10, C11a/C11b/C11c, C13, C15 (buildCategoryStructure single-file logic)
540
- **Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
479
+ **Condition**: A file named `addapi.mjs` is loaded via `api.slothlet.api.add()`
480
+ **Behavior**: Exports are always flattened to the mount namespace regardless of other settings
481
+ **Processing Path**: Detection in `getFlatteningDecision()` (`src/lib/processors/flatten.mjs`); execution in `src/lib/builders/modes-processor.mjs`
541
482
 
542
- **Pattern A: Object Export Flattening** (C11a/C11b/C11c):
483
+ **Verified Example**:
543
484
 
544
485
  ```javascript
545
- // File: api_tests/api_test/nested/date/date.mjs (filename matches object, exports object)
546
- export const date = {
547
- today() {
548
- return "2025-08-15";
549
- }
550
- };
486
+ // File: plugin-folder/addapi.mjs
487
+ export function initializePlugin() { /* ... */ }
488
+ export function cleanup() { /* ... */ }
489
+ export function configure() { /* ... */ }
551
490
 
552
- // Result: Object contents promoted to folder level (date/date.mjs → api.nested.date)
553
- api.nested.date.today(); // → "2025-08-15" ✅ VERIFIED with api_tests/api_test
554
- ```
491
+ await api.slothlet.api.add("plugins", "./plugin-folder");
555
492
 
556
- ```javascript
557
- // File: api_tests/api_test/math/math.mjs (filename matches object, exports object)
558
- export const math = {
559
- add: (a, b) => a + b,
560
- multiply: (a, b) => a * b
561
- };
562
-
563
- // Result: Object contents promoted to folder level (math/math.mjs → api.math)
564
- api.math.add(2, 3); // → 5 ✅ VERIFIED with api_tests/api_test
493
+ // addapi.mjs exports are always flattened - never nested:
494
+ api.plugins.initializePlugin(); //
495
+ api.plugins.cleanup(); //
496
+ api.plugins.configure(); //
497
+ // NOT: api.plugins.addapi.initializePlugin()
565
498
  ```
566
499
 
567
- **Pattern B: Mixed Export Flattening** (C10):
500
+ **Technical Implementation**:
568
501
 
569
502
  ```javascript
570
- // File: folder/folder.mjs (filename matches folder, exports mixed default+named)
571
- // Need to find example - no current test case available
572
- // ⚠️ PATTERN B NEEDS TEST CASE
503
+ // C33: AddApi Special File Detection
504
+ if (moduleKeys.includes("addapi")) {
505
+ const addapiModule = newModules["addapi"];
506
+ const otherModules = { ...newModules };
507
+ delete otherModules["addapi"];
508
+ modulesToMerge = { ...addapiModule, ...otherModules };
509
+ }
573
510
  ```
574
511
 
575
- **Pattern C: Non-matching Object Export** (C13):
512
+ **Use Cases**:
576
513
 
577
- ```javascript
578
- // File: api_tests/api_test/singletest/helper.mjs (single file, object name ≠ filename)
579
- export const utilities = {
580
- format(input) {
581
- return `Formatted: ${input}`;
582
- },
583
- parse(value) {
584
- return `Parsed: ${value}`;
585
- }
586
- };
514
+ - Plugin systems that extend the API at a known namespace
515
+ - Hot-reloadable API extension points
516
+ - Clean integration of external modules into a live API surface
587
517
 
588
- // Result: No auto-flattening, full nested path preserved
589
- api.singletest.helper.utilities.format("test"); // → "Formatted: test" ✅ VERIFIED (eager mode)
590
- // Note: Deep nested paths have known issues in lazy mode
591
- ```
518
+ ---
592
519
 
593
- **Pattern D: Default Function Flattening** (C15):
520
+ ## Rule 12: Module Ownership and Selective API Overwriting
594
521
 
595
- ```javascript
596
- // File: api_tests/api_test/funcmod/funcmod.mjs (default function in subfolder)
597
- export default function funcmod(name) {
598
- return `Hello, ${name}!`;
599
- }
522
+ **Category**: AddApi
523
+ **Status**: Implemented (`src/lib/handlers/ownership.mjs`)
524
+ **User Guide**: [F07](API-RULES/API-FLATTENING.md#f07)
525
+ **Technical**: [C19-C22](API-RULES/API-RULES-CONDITIONS.md#c19)
600
526
 
601
- // Result: Default function becomes folder callable (funcmod/funcmod.mjs api.funcmod)
602
- api.funcmod("test"); // → "Hello, test!" ✅ VERIFIED with api_tests/api_test
603
- ```
527
+ **Purpose**: Track which module registered each API path, enabling safe hot-reloading and cross-module conflict protection.
604
528
 
605
- **Technical Implementation**:
529
+ **Implementation**: Stack-based ownership system. Each API path maintains an independent ownership history stack. Removing a module automatically rolls back to the previous owner. Collision behavior is controlled by the `api.collision` configuration.
606
530
 
607
- ```javascript
608
- // C10: Single-file function folder match - decisions.mjs Line 584
609
- if (moduleName === categoryName && typeof mod === "function" && currentDepth > 0) {
610
- return {
611
- shouldFlatten: true,
612
- flattenType: "function-folder-match"
613
- };
614
- }
531
+ ### Configuration
615
532
 
616
- // C12: Object auto-flatten - decisions.mjs Line 604-609
617
- if (moduleName === categoryName && mod && typeof mod === "object" && currentDepth > 0) {
618
- if (moduleKeys.length === 1 && moduleKeys[0] === moduleName) {
619
- return {
620
- shouldFlatten: true,
621
- flattenType: "object-auto-flatten"
622
- };
533
+ ```javascript
534
+ const api = await slothlet({
535
+ dir: "./api",
536
+ api: {
537
+ collision: {
538
+ initial: "merge", // During initial API build
539
+ api: "replace" // During api.slothlet.api.add()
540
+ }
623
541
  }
624
- }
542
+ });
543
+ ```
625
544
 
626
- // C15: Function name matches folder - decisions.mjs Line 663
627
- if (functionNameMatchesFolder && currentDepth > 0) {
628
- return {
629
- shouldFlatten: true,
630
- flattenType: "function-folder-match",
631
- preferredName: mod.name
632
- };
633
- }
545
+ ### moduleId Tracking
634
546
 
635
- // C17: Default function export - decisions.mjs Line 680-682
636
- if (typeof mod === "function" && (!mod.name || mod.name === "default" || mod.__slothletDefault === true) && currentDepth > 0) {
637
- return {
638
- shouldFlatten: true,
639
- flattenType: "default-function"
640
- };
641
- }
642
- ```
547
+ Each `api.slothlet.api.add()` call accepts an optional `moduleId`. This is the key for ownership tracking:
643
548
 
644
- **Processing Path**: Single-file subfolder processing via `buildCategoryStructure()`
549
+ ```javascript
550
+ // Module A registers plugins namespace
551
+ await api.slothlet.api.add("plugins.moduleA", "./modules/moduleA", {}, {
552
+ moduleId: "moduleA"
553
+ });
645
554
 
646
- ---
555
+ // Module B registers in the same parent namespace
556
+ await api.slothlet.api.add("plugins.moduleB", "./modules/moduleB", {}, {
557
+ moduleId: "moduleB"
558
+ });
647
559
 
648
- ### Rule 9: Function Name Preference Over Sanitization
560
+ // Hot-reload Module A - ownership system allows this because moduleA owns these paths
561
+ await api.slothlet.api.add("plugins.moduleA", "./modules/moduleA-v2", {}, {
562
+ moduleId: "moduleA",
563
+ forceOverwrite: true
564
+ });
649
565
 
650
- **Status**: **VERIFIED**
566
+ // Cross-module overwrite - blocked if collision mode is "error"
567
+ await api.slothlet.api.add("plugins.moduleB", "./modules/other", {}, {
568
+ moduleId: "moduleA", // moduleA does not own moduleB's paths
569
+ forceOverwrite: true // Throws OWNERSHIP_CONFLICT in "error" mode
570
+ });
571
+ ```
651
572
 
652
- **Condition**: Original function name semantically matches sanitized filename but has different casing
653
- **Behavior**: Use original function name instead of sanitized version to preserve conventions (IP, JSON, HTTP, etc.)
654
- **Source Code Conditions**: [C16](API-RULES-CONDITIONS.md#c16-function-name-matches-filename-name-preference), [C19](API-RULES-CONDITIONS.md#c19-multi-file-function-with-preferred-name) (function name preference logic)
655
- **Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
573
+ ### Ownership Stack
656
574
 
657
- **Verified Examples**:
575
+ Each API path has a history stack. When a module is removed, the previous owner is automatically restored:
658
576
 
659
577
  ```javascript
660
- // File: api_tests/api_test/task/auto-ip.mjs exports function "autoIP"
661
- // Sanitized filename: "autoIp", Function name: "autoIP"
662
- // Result: Use "autoIP" instead of "autoIp" (preserves IP capitalization)
663
- api.task.autoIP(); // → "testAutoIP" ✅ VERIFIED with api_tests/api_test
664
-
665
- // Note: Other examples (parseJSON, getHTTPStatus) mentioned in the rule
666
- // do not exist in current test files - need real test cases
667
- // ⚠️ Need additional test files for broader verification
578
+ // Stack for "plugins.tools": [module-a, module-b] (module-b is current owner)
579
+ await api.slothlet.api.remove("module-b");
580
+ // Stack restored to: [module-a] (module-a is active again)
668
581
  ```
669
582
 
670
- **Technical Implementation**:
583
+ ### Collision Modes
671
584
 
672
- ```javascript
673
- // C14: buildCategoryStructure() function name filename match - line 1049
674
- if (functionNameMatchesFilename) {
675
- return { [mod.name]: mod }; // Use original function name
676
- }
585
+ | Mode | Behavior |
586
+ | ---- | -------- |
587
+ | `"merge"` (default) | Preserve existing properties, add new ones |
588
+ | `"merge-replace"` | Add new properties, overwrite existing |
589
+ | `"replace"` | Completely replace the existing value |
590
+ | `"skip"` | Keep existing value, silently ignore new |
591
+ | `"warn"` | Keep existing value, log a warning |
592
+ | `"error"` | Throw `OWNERSHIP_CONFLICT` error |
677
593
 
678
- // C16: Function name matches filename - decisions.mjs Line 671
679
- if (functionNameMatchesFilename) {
680
- return {
681
- shouldFlatten: false,
682
- preferredName: mod.name
683
- };
684
- }
594
+ ### forceOverwrite
685
595
 
686
- // C19: Multi-file function with preferred name - decisions.mjs Line 844
687
- if (hasPreferredName) {
688
- return {
689
- specialHandling: "preferred-export-names"
690
- };
691
- }
596
+ `forceOverwrite: true` requires an explicit `moduleId` and performs a complete replacement regardless of collision mode. Use for cases where a module must fully replace its own prior registration:
692
597
 
693
- // Function name preference logic checks:
694
- const functionNameLower = exportValue.name.toLowerCase();
695
- const filenameLower = fileName.toLowerCase();
696
- if (functionNameLower === filenameLower && exportValue.name !== apiPathKey) {
697
- preferredKey = exportValue.name; // Use original function name
698
- }
598
+ ```javascript
599
+ await api.slothlet.api.add("config", "./new-config", {}, {
600
+ moduleId: "config-v2",
601
+ forceOverwrite: true
602
+ });
699
603
  ```
700
604
 
701
- **Test Verification**:
605
+ **Source Code**: `src/lib/handlers/ownership.mjs`
702
606
 
703
- ```bash
704
- node tests/debug-slothlet.mjs
705
- # Look for function names with preserved casing (autoIP, parseJSON, getHTTPStatus)
706
- # Confirms preference logic maintains programming conventions
707
- ```
607
+ ---
708
608
 
709
- **Processing Path**: Both single-file and multi-file contexts via function name analysis
609
+ ## Rule 13: AddApi Path Deduplication Flattening
710
610
 
711
- ---
611
+ > **New in v3**
712
612
 
713
- ### Rule 10: Generic Filename Parent-Level Promotion
613
+ **Category**: AddApi
614
+ **Status**: ✅ Implemented (`api_tests/smart_flatten/api_smart_flatten_folder_config`)
615
+ **User Guide**: [F08](API-RULES/API-FLATTENING.md#f08)
616
+ **Technical**: [C34](API-RULES/API-RULES-CONDITIONS.md#c34)
714
617
 
715
- **Status**: **VERIFIED**
618
+ **Purpose**: When `api.slothlet.api.add("config", folder)` is called and the folder contains a subfolder whose name matches the last segment of the mount path (e.g. `config/config.mjs`), prevent double-nesting `api.config.config.*` by hoisting the subfolder's exports up to `api.config.*`.
716
619
 
717
- **Condition**: Single export with generic filename (singlefile, index, main, default) in subfolder
718
- **Behavior**: Promote export to parent level to eliminate meaningless intermediate namespace
719
- **Source Code Conditions**: [C14](API-RULES-CONDITIONS.md#c14-parent-level-flattening-generic-filenames) (parent-level flattening logic)
720
- **Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
620
+ **Condition**: After `buildAPI` returns `newApi`, if `newApi` contains a key equal to `lastPart` (last segment of `normalizedPath`) AND the matching value's `filePath` has its parent directory equal to `resolvedFolderPath/lastPart` (direct child check), hoist that key's own exports to the same level as the other keys in `newApi` and remove the duplicate key.
721
621
 
722
- **Verified Examples**:
622
+ **Verified Example**:
723
623
 
724
624
  ```javascript
725
- // File: api_tests/api_test/advanced/nest4/singlefile.mjs (generic filename "singlefile")
726
- export function beta(name) {
727
- return `Hello, ${name}!`;
728
- }
625
+ // Folder structure: api_smart_flatten_folder_config/
626
+ // main.mjs ← exports getRootInfo, setRootConfig
627
+ // config/
628
+ // config.mjs ← exports getNestedConfig, setNestedConfig
729
629
 
730
- // Without promotion: api.advanced.nest4.singlefile.beta (meaningless "singlefile" namespace)
731
- // With promotion: api.advanced.nest4.beta (promoted to parent level)
732
- api.advanced.nest4.beta("test"); // "Hello, test!" ✅ VERIFIED with api_tests/api_test
630
+ await api.slothlet.api.add("config", "./api_smart_flatten_folder_config", {});
631
+
632
+ // Without Rule 13 (double-nested):
633
+ api.config.config.getNestedConfig(); // ❌
634
+
635
+ // With Rule 13 (hoisted):
636
+ api.config.getNestedConfig(); // ✅ subfolder exports promoted
637
+ api.config.setNestedConfig(); // ✅
638
+ api.config.main.getRootInfo(); // ✅ other files unaffected
733
639
  ```
734
640
 
735
- **Technical Implementation**:
641
+ **Guard - `isDirectChild`**: Rule 13 only fires when the matching key's `filePath` is **directly** inside `resolvedFolderPath/lastPart`. This prevents false positives when a deeper nested folder coincidentally shares the mount-path name:
736
642
 
737
643
  ```javascript
738
- // C14: Parent-level flattening detection - decisions.mjs Line 641
739
- if (moduleFiles.length === 1 && currentDepth > 0 && mod && typeof mod === "object" && !Array.isArray(mod)) {
740
- const isGenericFilename = ["singlefile", "index", "main", "default"].includes(fileName.toLowerCase());
741
-
742
- // Line 649: Generic filename single export promotion
743
- if (moduleKeys.length === 1 && isGenericFilename) {
744
- return {
745
- shouldFlatten: true,
746
- flattenType: "parent-level-flatten"
747
- };
748
- }
749
- }
644
+ // Should NOT hoist (services/services/services.mjs):
645
+ // api.add("services", folder) → newApi has key "services"
646
+ // but filePath = .../services/services/services.mjs
647
+ // dirname = .../services/services ≠ resolvedFolderPath/services
648
+ // Rule 13 does NOT fire
649
+ // → api.services.services.getNestedService remains properly nested
750
650
  ```
751
651
 
752
- **Generic Filenames**: `singlefile`, `index`, `main`, `default` (case-insensitive)
753
-
754
- **Test Verification**:
652
+ **Implementation**: `src/lib/handlers/api-manager.mjs` - immediately after `buildAPI` call, before `setValueAtPath`
755
653
 
756
- ```bash
757
- node tests/debug-slothlet.mjs
758
- # Look for: api.nest4.beta (not api.nest4.singlefile.beta)
759
- # Confirms generic filename elimination
760
- ```
654
+ ---
761
655
 
762
- **Processing Path**: Single-file subfolder processing via `buildCategoryStructure()`
656
+ ## Verification Status
657
+
658
+ | Rule | Title | Status | Test Source |
659
+ | ---- | ---------------------------------------------- | ------------ | ----------- |
660
+ | 1 | Filename Matches Container Flattening | ✅ Verified | `api_tests/api_test` |
661
+ | 2 | Named-Only Export Collection | ✅ Verified | `api_tests/api_test` |
662
+ | 3 | Empty Module Handling | ✅ Verified | debug testing |
663
+ | 4 | Named Export with Function Name Preservation | ✅ Verified | `api_tests/api_test`, `api_tests/api_tv_test` |
664
+ | 5 | Multiple Module Default Export Handling | ✅ Verified | `api_tests/api_tv_test` |
665
+ | 6 | Multiple Module Mixed Exports | ✅ Verified | `api_tests/api_test_mixed` |
666
+ | 7 | Single Module Named Export Flattening | ✅ Verified | `api_tests/api_test` |
667
+ | 8 | Single Module Default Export Promotion | ✅ Verified | Multiple test files |
668
+ | 9 | Function Name Preference Over Sanitization | ✅ Verified | autoIP, parseJSON, getHTTPStatus, XMLParser |
669
+ | 10 | Generic Filename Parent-Level Promotion | ✅ Verified | `api_tests/api_test/nest4/singlefile.mjs` |
670
+ | 11 | AddApi Special File Pattern | ✅ Verified | `api_tests/api_smart_flatten_addapi` |
671
+ | 12 | Module Ownership and Selective API Overwriting | ✅ Verified | `src/lib/handlers/ownership.mjs` |
672
+ | 13 | AddApi Path Deduplication Flattening | ✅ Verified | `api_tests/smart_flatten/api_smart_flatten_folder_config` |
763
673
 
764
674
  ---
765
675
 
766
- ## Source Code Conditions Cross-Reference
767
-
768
- ### Source Code Condition Mapping to Rules
769
-
770
- | Condition | Location | Rule(s) | Description |
771
- | --------- | ------------------------------- | --------- | --------------------------------- |
772
- | C01 | getFlatteningDecision:558 | Rule 6 | Self-referential check |
773
- | C02 | getFlatteningDecision:570 | Rule 5 | Multi-default WITH default |
774
- | C03 | getFlatteningDecision:580 | Rule 5 | Multi-default WITHOUT default |
775
- | C04 | getFlatteningDecision:593 | Rule 7 | Auto-flatten single named export |
776
- | C05 | getFlatteningDecision:605 | Rule 1 | Filename matches container |
777
- | C07 | getFlatteningDecision:629 | Rule 2 | Default namespace preservation |
778
- | C08a | processModuleForAPI:716 | Rule 5 | Multi-default function handling |
779
- | C08b | processModuleForAPI:728 | Rule 6 | Self-referential function |
780
- | C08c | processModuleForAPI:748 | Rule 4 | Root function setting |
781
- | C08d | processModuleForAPI:758 | Rule 4 | Function as namespace |
782
- | C09a | processModuleForAPI:782 | Rule 7 | Apply auto-flattening |
783
- | C09b | processModuleForAPI:786 | Rules 1,5 | Flatten to root/category |
784
- | C09c | processModuleForAPI:797 | Rule 6 | Self-referential non-function |
785
- | C09d | processModuleForAPI:801 | Rule 2 | Traditional namespace |
786
- | C10 | buildCategoryStructure:984 | Rule 8 | Single-file function folder match |
787
- | C11a | buildCategoryStructure:1000 | Rules 7,8 | Single named export match |
788
- | C11b | buildCategoryStructure:1009 | Rule 8 | Multiple exports (default spread) |
789
- | C11c | buildCategoryStructure:fallback | Rule 8 | Folder match fallback |
790
- | C12 | buildCategoryStructure:1018 | Rule 10 | Parent-level flattening |
791
- | C12a | buildCategoryStructure:1026 | Rule 10 | Generic filename promotion |
792
- | C13 | buildCategoryStructure:1039 | Rule 8 | Function name matches folder |
793
- | C14 | buildCategoryStructure:1049 | Rule 9 | Function name matches filename |
794
- | C15 | buildCategoryStructure:1053 | Rule 8 | Default function export |
795
- | C16 | buildCategoryStructure:1063 | Rule 7 | Auto-flatten (second instance) |
796
- | C18 | buildCategoryDecisions:1709 | Rule 9 | Preferred export names |
797
- | C19 | buildCategoryDecisions:1712 | Rule 6 | Self-referential multi-file |
798
- | C20a | buildCategoryDecisions:1723 | Rule 4 | Single default object |
799
- | C20b | buildCategoryDecisions:1727 | Rule 5 | Multi-default no default |
800
- | C20c | buildCategoryDecisions:1731 | Rule 7 | Single named export match |
801
- | C20d | buildCategoryDecisions:1736 | Rule 1 | Category name match flatten |
802
- | C20e | buildCategoryDecisions:1740 | Rule 2 | Standard object export |
803
- | C21 | multidefault:168 | Rule 6 | Multi-default self-referential |
804
- | C22 | multidefault:179 | Rule 5 | Multi-default with default |
805
- | C23 | multidefault:186 | Rule 5 | Multi-default without default |
806
- | C24 | multidefault:200 | Rule 7 | Multi-default single named export |
807
- | C26 | multidefault:220+ | Rule 2 | Multi-default default fallback |
808
-
809
- **Total Coverage**: 23 source code conditions mapped to 10 comprehensive rules
810
-
811
- > **Note**: Rule 11 conditions (C06, C17, C25) have been removed following architectural decision to eliminate single file context flattening. This preserves API path predictability and flexibility.
812
-
813
- ## Source Code Locations
814
-
815
- **Note**: The slothlet API generation logic has been refactored into a modular structure:
816
-
817
- - **`src/lib/helpers/api_builder/decisions.mjs`** - Core decision logic (899 lines)
818
- - `getFlatteningDecision()` [L87-189] - Controls flattening behavior
819
- - `processModuleForAPI()` [L315-466] - Module processing logic
820
- - `buildCategoryDecisions()` [L505-899] - Directory structure decisions
821
-
822
- - **`src/lib/helpers/api_builder/construction.mjs`** - API assembly (555 lines)
823
- - `buildCategoryStructure()` [L125-555] - Structural construction
824
-
825
- - **`src/lib/helpers/multidefault.mjs`** - Multi-default handling (262 lines)
826
- - `multidefault_getFlatteningDecision()` [L178-262] - Multi-default flattening logic
827
-
828
- **For complete documentation** of all 32 conditional statements with exact line numbers, see [API-RULES-CONDITIONS.md](API-RULES-CONDITIONS.md).
829
-
830
- ## Test File Index
831
-
832
- _To be populated with confirmed examples from actual test files_
676
+ ## Cross-Reference Index
677
+
678
+ ### By Flattening Pattern (F##)
679
+
680
+ | Flattening Pattern | API Rules | Technical Conditions |
681
+ | ------------------ | --------- | -------------------- |
682
+ | [F01](API-RULES/API-FLATTENING.md#f01) | Rule 1 | [C05, C09b, C11](API-RULES/API-RULES-CONDITIONS.md#c05) |
683
+ | [F02](API-RULES/API-FLATTENING.md#f02) | Rule 8 (Pattern A) | [C12, C21a](API-RULES/API-RULES-CONDITIONS.md#c12) |
684
+ | [F03](API-RULES/API-FLATTENING.md#f03) | Rule 7 | [C04, C09a, C18, C21c, C30](API-RULES/API-RULES-CONDITIONS.md#c04) |
685
+ | [F04](API-RULES/API-FLATTENING.md#f04) | Rule 4, Rule 8 (Pattern B) | [C08c, C24](API-RULES/API-RULES-CONDITIONS.md#c08c) |
686
+ | [F05](API-RULES/API-FLATTENING.md#f05) | Rule 4, Rule 8 (Pattern C) | [C08c, C11](API-RULES/API-RULES-CONDITIONS.md#c08c) |
687
+ | [F06](API-RULES/API-FLATTENING.md#f06) | Rule 11 | [C33](API-RULES/API-RULES-CONDITIONS.md#c33) |
688
+ | [F07](API-RULES/API-FLATTENING.md#f07) | Rule 12 | [C19-C22](API-RULES/API-RULES-CONDITIONS.md#c19) |
689
+ | [F08](API-RULES/API-FLATTENING.md#f08) | Rule 13 | [C34](API-RULES/API-RULES-CONDITIONS.md#c34) |
690
+
691
+ ### By Technical Condition (C##)
692
+
693
+ | Condition | API Rules | Flattening Patterns |
694
+ | --------- | --------- | ------------------- |
695
+ | [C01-C07](API-RULES/API-RULES-CONDITIONS.md#c01) | Rules 1, 6, 7, 8 | F01, F03 |
696
+ | [C08-C09d](API-RULES/API-RULES-CONDITIONS.md#c08) | Rules 4, 6, 7 | F04, F05 |
697
+ | [C10-C21d](API-RULES/API-RULES-CONDITIONS.md#c10) | Rules 1, 2, 3, 5, 7, 8, 9, 10 | F01, F02, F03 |
698
+ | [C22-C26](API-RULES/API-RULES-CONDITIONS.md#c22) | Rules 4, 6 | F04, F05 |
699
+ | [C27-C32](API-RULES/API-RULES-CONDITIONS.md#c27) | Rules 5, 6, 7 | Multi-default scenarios |
700
+ | [C33](API-RULES/API-RULES-CONDITIONS.md#c33) | Rule 11 | F06 |
701
+ | [C34](API-RULES/API-RULES-CONDITIONS.md#c34) | Rule 13 | F08 |
702
+
703
+ ### By Processing Context
704
+
705
+ | Context | Rules | Primary Conditions |
706
+ | ------- | ----- | ------------------ |
707
+ | **Single-File Directories** | 1, 7, 8, 10 | C11, C12, C04, C17 |
708
+ | **Multi-File Directories** | 1, 2, 5, 7, 9 | C13, C15, C21a-d, C16, C19 |
709
+ | **Multi-Default Scenarios** | 5, 6, 7 | C02, C03, C27-C32 |
710
+ | **AddApi Operations** | 11, 12, 13 | C33, C34, C19-C22 |
711
+ | **Root-Level Processing** | 4, 8, 10 | C08c, C22, C17 |
712
+ | **Subfolder Processing** | 4, 6, 8 | C08d, C20, C24 |