@@ -88,6 +88,10 @@ function update_option( string $name, $value, $autoload = null ): bool {
8888
8989 if ( ! function_exists ( 'apply_filters ' ) ) {
9090 function apply_filters ( string $ hook_name , $ value , ...$ args ) {
91+ global $ datamachine_code_test_filters ;
92+ if ( isset ( $ datamachine_code_test_filters [ $ hook_name ] ) && is_callable ( $ datamachine_code_test_filters [ $ hook_name ] ) ) {
93+ return $ datamachine_code_test_filters [ $ hook_name ]( $ value , ...$ args );
94+ }
9195 return $ value ;
9296 }
9397 }
@@ -144,16 +148,32 @@ function wp_mkdir_p( string $path ): bool {
144148
145149 echo "=== smoke-worktree-agent-session-lifecycle === \n" ;
146150
147- // Reset option state for this run.
151+ // Reset option + filter state for this run.
148152 $ GLOBALS ['datamachine_code_test_options ' ] = array ();
153+ $ GLOBALS ['datamachine_code_test_filters ' ] = array ();
154+
155+ // Register two synthetic test runtimes via the public filter contract.
156+ // DMC has zero knowledge of these IDs or env-var names — the integration
157+ // layer (here, the test) owns both.
158+ $ GLOBALS ['datamachine_code_test_filters ' ]['datamachine_code_worktree_runtime_signatures ' ] = function ( array $ signatures ): array {
159+ $ signatures ['alpha-runtime ' ] = array (
160+ 'session_id ' => 'DMC_SMOKE_ALPHA_SESSION_ID ' ,
161+ 'thread_id ' => 'DMC_SMOKE_ALPHA_THREAD_ID ' ,
162+ 'thread_url ' => 'DMC_SMOKE_ALPHA_THREAD_URL ' ,
163+ );
164+ $ signatures ['beta-runtime ' ] = array (
165+ 'session_id ' => 'DMC_SMOKE_BETA_SESSION_ID ' ,
166+ 'run_id ' => 'DMC_SMOKE_BETA_RUN_ID ' ,
167+ );
168+ return $ signatures ;
169+ };
149170
150171 // --- 1) build_lifecycle_metadata captures env-driven session + task fields ---
151- putenv ( 'OPENCODE_SESSION_ID=ses_smoke_42 ' );
152- putenv ( 'OPENCODE_RUN_ID=run-smoke-1 ' );
153- putenv ( 'KIMAKI_SESSION_ID=kim-ses-99 ' );
154- putenv ( 'KIMAKI_THREAD_ID=thr_111 ' );
155- putenv ( 'KIMAKI_CHANNEL_ID=chan_222 ' );
156- putenv ( 'KIMAKI_THREAD_URL=https://discord.com/channels/1/2/3 ' );
172+ putenv ( 'DMC_SMOKE_BETA_SESSION_ID=ses_smoke_42 ' );
173+ putenv ( 'DMC_SMOKE_BETA_RUN_ID=run-smoke-1 ' );
174+ putenv ( 'DMC_SMOKE_ALPHA_SESSION_ID=alpha-ses-99 ' );
175+ putenv ( 'DMC_SMOKE_ALPHA_THREAD_ID=thr_111 ' );
176+ putenv ( 'DMC_SMOKE_ALPHA_THREAD_URL=https://example.test/threads/1/2/3 ' );
157177 putenv ( 'DATAMACHINE_TASK_URL=https://github.com/Extra-Chill/data-machine-code/issues/221 ' );
158178 putenv ( 'DATAMACHINE_TASK_REF=Extra-Chill/data-machine-code#221 ' );
159179
@@ -171,13 +191,26 @@ function wp_mkdir_p( string $path ): bool {
171191 $ assert ( 'Intelligence ' , $ built ['origin_site ' ] ?? null , 'origin site name recorded ' );
172192 $ assert ( 'https://intelligence.example.test ' , $ built ['origin_site_url ' ] ?? null , 'origin site URL recorded ' );
173193 $ assert ( 'chris ' , $ built ['origin_user ' ]['login ' ] ?? null , 'origin user login recorded ' );
174- $ assert ( 'ses_smoke_42 ' , $ built ['origin_session ' ]['opencode_session_id ' ] ?? null , 'opencode session id captured ' );
175- $ assert ( 'kim-ses-99 ' , $ built ['origin_session ' ]['kimaki_session_id ' ] ?? null , 'kimaki session id captured ' );
176- $ assert ( 'chan_222 ' , $ built ['origin_session ' ]['kimaki_channel_id ' ] ?? null , 'kimaki channel id captured ' );
177- $ assert ( 'https://discord.com/channels/1/2/3 ' , $ built ['origin_session ' ]['kimaki_thread_url ' ] ?? null , 'kimaki thread URL captured ' );
194+ $ assert ( 'ses_smoke_42 ' , $ built ['origin_session ' ]['ids ' ]['beta-runtime ' ]['session_id ' ] ?? null , 'beta runtime session id captured under ids envelope ' );
195+ $ assert ( 'run-smoke-1 ' , $ built ['origin_session ' ]['ids ' ]['beta-runtime ' ]['run_id ' ] ?? null , 'beta runtime run id captured under ids envelope ' );
196+ $ assert ( 'alpha-ses-99 ' , $ built ['origin_session ' ]['ids ' ]['alpha-runtime ' ]['session_id ' ] ?? null , 'alpha runtime session id captured under ids envelope ' );
197+ $ assert ( 'thr_111 ' , $ built ['origin_session ' ]['ids ' ]['alpha-runtime ' ]['thread_id ' ] ?? null , 'alpha runtime thread id captured under ids envelope ' );
198+ $ assert ( 'https://example.test/threads/1/2/3 ' , $ built ['origin_session ' ]['ids ' ]['alpha-runtime ' ]['thread_url ' ] ?? null , 'alpha runtime thread URL captured under ids envelope ' );
199+ $ assert ( 'alpha-ses-99 ' , $ built ['origin_session ' ]['primary_id ' ] ?? null , 'primary_id resolves to first registered runtime session_id ' );
178200 $ assert ( 'https://github.com/Extra-Chill/data-machine-code/issues/221 ' , $ built ['origin_task ' ]['task_url ' ] ?? null , 'task URL captured from env ' );
179201 $ assert ( 'Extra-Chill/data-machine-code#221 ' , $ built ['origin_task ' ]['task_ref ' ] ?? null , 'task ref captured from env ' );
180202
203+ // URL-suffixed subkeys must look like http(s) URLs to be captured.
204+ putenv ( 'DMC_SMOKE_ALPHA_THREAD_URL=not-a-url ' );
205+ $ built_bad_url = \DataMachineCode \Workspace \WorktreeContextInjector::build_lifecycle_metadata ( array (
206+ 'handle ' => 'demo@bad-url ' ,
207+ 'path ' => '/tmp/demo@bad-url ' ,
208+ 'repo ' => 'demo ' ,
209+ 'branch ' => 'bad/url ' ,
210+ ) );
211+ $ assert ( null , $ built_bad_url ['origin_session ' ]['ids ' ]['alpha-runtime ' ]['thread_url ' ] ?? null , 'non-URL value for *_url subkey is dropped ' );
212+ putenv ( 'DMC_SMOKE_ALPHA_THREAD_URL=https://example.test/threads/1/2/3 ' );
213+
181214 // Caller-supplied task_url/task_ref override env.
182215 putenv ( 'DATAMACHINE_TASK_URL=https://github.com/some/other/issues/9999 ' );
183216 $ built_explicit = \DataMachineCode \Workspace \WorktreeContextInjector::build_lifecycle_metadata ( array (
@@ -189,12 +222,11 @@ function wp_mkdir_p( string $path ): bool {
189222 $ assert ( 'EC/dmc#221 ' , $ built_explicit ['origin_task ' ]['task_ref ' ] ?? null , 'explicit task_ref wins over env ' );
190223
191224 // Clear env so subsequent assertions get unknown-safe defaults.
192- putenv ( 'OPENCODE_SESSION_ID ' );
193- putenv ( 'OPENCODE_RUN_ID ' );
194- putenv ( 'KIMAKI_SESSION_ID ' );
195- putenv ( 'KIMAKI_THREAD_ID ' );
196- putenv ( 'KIMAKI_CHANNEL_ID ' );
197- putenv ( 'KIMAKI_THREAD_URL ' );
225+ putenv ( 'DMC_SMOKE_BETA_SESSION_ID ' );
226+ putenv ( 'DMC_SMOKE_BETA_RUN_ID ' );
227+ putenv ( 'DMC_SMOKE_ALPHA_SESSION_ID ' );
228+ putenv ( 'DMC_SMOKE_ALPHA_THREAD_ID ' );
229+ putenv ( 'DMC_SMOKE_ALPHA_THREAD_URL ' );
198230 putenv ( 'DATAMACHINE_TASK_URL ' );
199231 putenv ( 'DATAMACHINE_TASK_REF ' );
200232
@@ -289,11 +321,40 @@ function wp_mkdir_p( string $path ): bool {
289321
290322 $ session_unknown = \DataMachineCode \Workspace \WorktreeContextInjector::summarize_session ( null );
291323 $ assert ( null , $ session_unknown ['primary_id ' ], 'summarize_session primary_id null on missing metadata ' );
292- $ assert ( null , $ session_unknown ['kimaki_session_id ' ], 'summarize_session kimaki id null on missing metadata ' );
324+ $ assert ( array () , $ session_unknown ['ids ' ], 'summarize_session ids is empty map on missing metadata ' );
293325
294326 $ session_filled = \DataMachineCode \Workspace \WorktreeContextInjector::summarize_session ( $ built );
295- $ assert ( 'kim-ses-99 ' , $ session_filled ['primary_id ' ], 'summarize_session prefers kimaki session id as primary ' );
296- $ assert ( 'ses_smoke_42 ' , $ session_filled ['opencode_session_id ' ], 'summarize_session exposes opencode session id ' );
327+ $ assert ( 'alpha-ses-99 ' , $ session_filled ['primary_id ' ], 'summarize_session primary_id follows registered runtime order ' );
328+ $ assert ( 'ses_smoke_42 ' , $ session_filled ['ids ' ]['beta-runtime ' ]['session_id ' ] ?? null , 'summarize_session exposes beta runtime session id under ids envelope ' );
329+ $ assert ( 'alpha-ses-99 ' , $ session_filled ['ids ' ]['alpha-runtime ' ]['session_id ' ] ?? null , 'summarize_session exposes alpha runtime session id under ids envelope ' );
330+
331+ // --- 4b) Legacy-shape migration (pre-#416 stored rows). ---
332+ // Stored rows that persisted vendor-specific top-level keys must normalize
333+ // transparently into the generic envelope without losing data.
334+ $ legacy_metadata = array (
335+ 'origin_session ' => array (
336+ 'alpha-runtime_session_id ' => 'legacy-alpha-ses ' ,
337+ 'alpha-runtime_thread_id ' => 'legacy-alpha-thr ' ,
338+ 'beta-runtime_run_id ' => 'legacy-beta-run ' ,
339+ ),
340+ );
341+ $ legacy_view = \DataMachineCode \Workspace \WorktreeContextInjector::summarize_session ( $ legacy_metadata );
342+ $ assert ( 'legacy-alpha-ses ' , $ legacy_view ['ids ' ]['alpha-runtime ' ]['session_id ' ] ?? null , 'legacy migration projects <runtime>_session_id into ids envelope ' );
343+ $ assert ( 'legacy-alpha-thr ' , $ legacy_view ['ids ' ]['alpha-runtime ' ]['thread_id ' ] ?? null , 'legacy migration projects <runtime>_thread_id into ids envelope ' );
344+ $ assert ( 'legacy-beta-run ' , $ legacy_view ['ids ' ]['beta-runtime ' ]['run_id ' ] ?? null , 'legacy migration projects <runtime>_run_id into ids envelope ' );
345+ $ assert ( 'legacy-alpha-ses ' , $ legacy_view ['primary_id ' ], 'legacy-migrated rows still resolve a primary_id via runtime precedence ' );
346+
347+ // Mixed envelope: explicit primary_id wins over runtime-derived precedence.
348+ $ mixed_view = \DataMachineCode \Workspace \WorktreeContextInjector::summarize_session ( array (
349+ 'origin_session ' => array (
350+ 'primary_id ' => 'explicit-primary ' ,
351+ 'ids ' => array (
352+ 'alpha-runtime ' => array ( 'session_id ' => 'alpha-ses ' ),
353+ 'beta-runtime ' => array ( 'session_id ' => 'beta-ses ' ),
354+ ),
355+ ),
356+ ) );
357+ $ assert ( 'explicit-primary ' , $ mixed_view ['primary_id ' ], 'explicit primary_id on stored envelope overrides runtime scan ' );
297358
298359 // --- 5) Duplicate task ownership detection ---
299360 $ rows = array (
0 commit comments