Kode-Animator commited on
Commit
af09dd7
·
1 Parent(s): e48c905

document S4.5 D1 regression root cause

Browse files
docs/evidence/THOUGHT_ENGINE_NODE_D1_REGRESSION_V1.md ADDED
@@ -0,0 +1,198 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # THOUGHT ENGINE NODE D1 REGRESSION V1
2
+
3
+ Date: 2026-08-18
4
+ Stage: S4.5C Node -> D1 root-cause continuation
5
+
6
+ ## Symptom
7
+
8
+ The deployed Thought Engine Node remained healthy at `/health`, but D1-backed reads took about 10 seconds and returned healthy-looking empty state (`/sessions` => `{"total":0,"sessions":[]}`). Session creation through the Bridge also failed downstream.
9
+
10
+ ## Cloudflare control
11
+
12
+ Authoritative D1 database: `thought-vault`
13
+
14
+ Database UUID: `ed9b375d-bf00-477b-942e-379828b70e81`
15
+
16
+ Authoritative pre-smoke row counts from direct remote Wrangler control:
17
+
18
+ - sessions: 7
19
+ - thought_units: 60
20
+ - thought_edges: 53
21
+ - thought_reviews: 4
22
+ - witness_events: 60
23
+ - pattern_registry: 0
24
+ - version_history: 0
25
+
26
+ No data loss is supported by the evidence. Historical rows are present.
27
+
28
+ Schema control completed from `C:\Users\kryst` context:
29
+
30
+ - `pattern_registry` (7 columns)
31
+ - `version_history` (6)
32
+ - `witness_events` (7)
33
+ - `thought_reviews` (7)
34
+ - `thought_edges` (6)
35
+ - `thought_units` (9)
36
+ - `sessions` (9)
37
+ - Cloudflare internal `_cf_KV`
38
+
39
+ `sessions` columns:
40
+
41
+ 1. session_id TEXT primary key
42
+ 2. title TEXT
43
+ 3. created_by TEXT NOT NULL default 'system'
44
+ 4. created_at TEXT NOT NULL default datetime('now')
45
+ 5. updated_at TEXT NOT NULL default datetime('now')
46
+ 6. status TEXT NOT NULL default 'active'
47
+ 7. root_thought_id TEXT
48
+ 8. active_thought_id TEXT
49
+ 9. metadata TEXT default '{}'
50
+
51
+ Both schema queries completed successfully against the intended UUID in about 0.14-0.21 ms SQL execution time.
52
+
53
+ ### Wrangler context anomaly
54
+
55
+ Launching Wrangler from the production Orchestrator working directory (`C:\Users\kryst\Infrastructure\mcp-servers\mcp-orchestrator`) caused Wrangler to attempt account `ae406365ceacd48b5b3bfa299f2644be` and return Cloudflare authentication error code 10000, while Wrangler's authentication fallback displayed account `8543b906ec5121d56ff7bf7ede12525d`.
56
+
57
+ The Desktop Commander process environment did not contain `CLOUDFLARE_ACCOUNT_ID`, `CLOUDFLARE_D1_DATABASE_ID`, or `CLOUDFLARE_D1_API_TOKEN`. Re-running the schema commands from `C:\Users\kryst` immediately targeted the correct `thought-vault` UUID and succeeded. This is treated as a local Wrangler working-context anomaly, not evidence about the deployed Node.
58
+
59
+ ## Node source and deployment identity
60
+
61
+ Original local / remote / deployed revision: `1fce18e542306fd929363902119b0a496d16ef79`
62
+
63
+ Diagnostic deployed revision: `e48c9052b54c9e1eb221a80027a0a2e66569fbaa`
64
+
65
+ Rollback revision: `1fce18e542306fd929363902119b0a496d16ef79`
66
+
67
+ HF Space: `Kode-Animator/thought-engine-node`
68
+
69
+ HF runtime reached `RUNNING` on diagnostic revision `e48c9052...`.
70
+
71
+ Pre-existing untracked `test_smoke.py` remained untouched and was not committed.
72
+
73
+ ## D1 client implementation
74
+
75
+ `d1_client.py` reads:
76
+
77
+ - `CLOUDFLARE_ACCOUNT_ID`
78
+ - `CLOUDFLARE_D1_DATABASE_ID`
79
+ - `CLOUDFLARE_D1_API_TOKEN`
80
+
81
+ Request construction:
82
+
83
+ `https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/d1/database/{DATABASE_ID}/query`
84
+
85
+ Headers:
86
+
87
+ - `Authorization: Bearer <token>`
88
+ - `Content-Type: application/json`
89
+
90
+ Body:
91
+
92
+ - `{"sql": <sql>}`
93
+ - optional `params`
94
+
95
+ Client behavior:
96
+
97
+ - `httpx.AsyncClient(timeout=10.0)`
98
+ - no retry loop
99
+ - `raise_for_status()` on HTTP response
100
+ - broad exception catch returned `[]`
101
+
102
+ HF metadata confirmed all three Cloudflare values exist as Space Secrets. Hugging Face intentionally hides secret values after creation, so the configured account ID and database UUID could not be compared directly without changing runtime observability or manually replacing secrets. Token value was never exposed.
103
+
104
+ ## API compatibility control
105
+
106
+ Current Cloudflare D1 documentation still specifies:
107
+
108
+ `POST /accounts/{account_id}/d1/database/{database_id}/query`
109
+
110
+ with Bearer API token authorization and `sql` / optional `params` JSON body. The Node request shape matches the current documented API. No API-path compatibility regression is supported.
111
+
112
+ ## HF -> Cloudflare boundary
113
+
114
+ Existing HF logs before instrumentation repeatedly contained only:
115
+
116
+ `D1 Connection Error:`
117
+
118
+ because the broad exception handler logged only `str(e)`.
119
+
120
+ A one-line diagnostic logging change was developed with TDD so the existing log also records `type(e).__name__`.
121
+
122
+ Test: `test_d1_client.py`
123
+
124
+ RED proof: `ReadTimeout` was absent from the original blank log.
125
+
126
+ GREEN proof: after the logging-only change, the test passed and `git diff --check` was clean.
127
+
128
+ After deploying `e48c9052...`, a fresh read-only call to `/sessions` returned HTTP 200 with `{"total":0,"sessions":[]}` after about 10.6 seconds.
129
+
130
+ The corresponding HF runtime log recorded:
131
+
132
+ `D1 Connection Error [ConnectTimeout]:`
133
+
134
+ Therefore the Node does not reach an HTTP response from Cloudflare. Authentication acceptance/rejection and D1 query acceptance/rejection are downstream of the first observed failure.
135
+
136
+ Boundary classification:
137
+
138
+ - DNS: not independently isolated
139
+ - TCP connect: not independently isolated from TLS setup by current `httpx.ConnectTimeout` evidence
140
+ - TLS handshake: not independently isolated
141
+ - HTTP response: NOT REACHED
142
+ - Cloudflare auth: NOT REACHED / NOT TESTED
143
+ - D1 request acceptance: NOT REACHED / NOT TESTED
144
+ - observed timeout class: `httpx.ConnectTimeout`
145
+
146
+ ## Root cause
147
+
148
+ Classification: D - HF runtime cannot successfully establish the Cloudflare API connection.
149
+
150
+ First broken boundary: deployed HF Thought Engine Node -> `api.cloudflare.com:443` connection establishment, before HTTP response.
151
+
152
+ Evidence:
153
+
154
+ 1. Direct remote Wrangler queries to the intended D1 database succeed and historical data is present.
155
+ 2. Node source uses the current documented Cloudflare D1 REST path.
156
+ 3. Deployed Node `/sessions` consistently consumes roughly the 10-second httpx timeout and returns false empty state.
157
+ 4. Typed runtime instrumentation proves the thrown exception is `httpx.ConnectTimeout`.
158
+ 5. No Cloudflare HTTP status is observed, so credential/schema/API response errors cannot be the first failure.
159
+
160
+ Confidence: HIGH for classification D and the first broken boundary; insufficient evidence to attribute the connect timeout specifically to DNS, TCP routing, TLS handshake, provider egress policy, or an upstream network incident.
161
+
162
+ ## Fix status
163
+
164
+ Primary repair: NOT PERFORMED.
165
+
166
+ Reason: no evidence-backed minimal Node-side fix has yet been established for the HF -> Cloudflare connection-establishment timeout. Changing credentials, database identifiers, API path, timeout duration, retries, DNS behavior, IPv4/IPv6 preference, or provider settings without further evidence would violate the no-fix-without-root-cause rule.
167
+
168
+ Database mutation: NONE.
169
+
170
+ Smoke session: NOT CREATED because database connectivity is not restored.
171
+
172
+ Historical Node session restoration: NOT ACHIEVED.
173
+
174
+ Bridge historical list proof: NOT RUN because the downstream Node path remains broken.
175
+
176
+ ## Secondary defect
177
+
178
+ Independently confirmed: any D1 exception is swallowed into `[]`, allowing unavailable D1 state to masquerade as zero records.
179
+
180
+ The diagnostic commit improves log observability only. It does not yet change API error semantics. Per S4.5 ordering, the primary connectivity failure should be resolved before the secondary empty-state masquerade is repaired.
181
+
182
+ ## Untouched systems
183
+
184
+ Bridge revision: `b17615cc0ab007b2dce33ebee9f5f258934c3e96` (unchanged)
185
+
186
+ Candidate changes: NONE
187
+
188
+ Federation changes: NONE
189
+
190
+ Production Orchestrator changes: NONE
191
+
192
+ D1 schema/data mutation: NONE
193
+
194
+ ## Next boundary
195
+
196
+ S5 remains blocked.
197
+
198
+ The next investigation must refine `ConnectTimeout` into DNS vs TCP vs TLS/provider-egress evidence, or establish a provider-side incident/configuration fact, before selecting a repair.