Host under test: win2025test (Tailscale 100.127.62.31), Windows Server 2025 Standard, build 10.0.26100, 64-bit.
Access: SSH (key-based, Administrator) from the OpenClaw Linux host, driving cscript/powershell remotely.
Site: WscMvc, binding *:8090, physical path C:\Projects\wsc-mvc, app pool WscMvc (64-bit, no managed code).
Date: 2026-09-19.
| Check | Result |
|---|---|
| Windows version / arch | PASS — Server 2025 Standard, 10.0.26100, 64-bit |
IIS + Classic ASP (Web-ASP) + CGI/ISAPI installed |
PASS |
| URL Rewrite module installed | PASS (rewrite.dll registered as global module) |
| WebAdministration PowerShell module | PASS (v1.0.0.0) |
WSC/COM runtime (scrobj.dll) present |
PASS (System32 and SysWOW64) |
regsvr32/cscript/wscript present |
PASS |
| Minimal WSC register/instantiate/call/unregister/re-register outside IIS | PASS — see M1 component tests below (folded into M1 since the same components serve both gates) |
Command: cscript //nologo tests\Test-Components.vbs — see M1.
Command:
cscript //nologo C:\Projects\wsc-mvc\tests\Test-Components.vbs
Result: PASS
PASS: /hello -> 200 OK | text/html; charset=utf-8 | Hello from WSC-MVC!
PASS: unknown route -> 404 Not Found
RESULT: ALL PASS
Command:
powershell -File C:\Projects\wsc-mvc\tests\Test-Http.ps1 -BaseUrl http://localhost:8090
Result: PASS
PASS: GET /hello status 200
PASS: GET /hello content-type
PASS: GET /hello body
PASS: GET /Framework/Application.wsc denied
RESULT: ALL PASS
Also verified directly from the Linux host over the tailnet:
curl -i http://100.127.62.31:8090/hello
-> HTTP/1.1 200 OK, Content-Type: text/html; charset=utf-8, body Hello from WSC-MVC!. PASS
GET /Framework/Application.wsc (and by the same hiddenSegments mechanism, Controllers/, tests/, tools/, docs/) -> 404 Not Found. PASS (covered by Test-Http.ps1 above for the .wsc case; other directories share the identical web.config rule and were not individually re-tested by automated script, only spot-checked manually).
Steps: unregister both components -> request /hello -> observe safe 500 with no leaked path/exception -> re-register -> confirm recovery.
curl http://localhost:8090/hello while unregistered): HTTP/1.1 500 Internal Server Error, Content-Type: text/plain; charset=utf-8, body exactly Internal Server Error (our own Default.asp error branch). PASSHTTP/1.1 500 Internal Server Error with IIS's own generic friendly-error HTML (no path/exception content either). PASS — see docs/DECISIONS.md for why local vs. remote differ (IIS httpErrors errorMode=DetailedLocalOnly, expected default behavior, not a bug).cscript //nologo tests\Test-Components.vbs while unregistered: FAIL: could not create WscMvc.Application - ActiveX component can't create object (test script correctly reports FAILURE, exit code 1 — this is the expected result of this specific check, proving the failure path is real and detectable, not silently swallowed).tools\Register-Components.ps1: HTTP and WSH tests both back to PASS (shown above).Command sequence:
powershell -File tools\Register-Components.ps1
powershell -File tools\Unregister-Components.ps1
powershell -File tools\Register-Components.ps1
Result: PASS, but only after a fix — see docs/DECISIONS.md finding on regsvr32 /s /u not actually removing .wsc registry entries on this host. tools\Unregister-Components.ps1 now verifies and, when needed, explicitly removes exactly this project's ProgID/CLSID pair. Confirmed via direct registry inspection (HKLM:\SOFTWARE\Classes\WscMvc.Application / WscMvc.HomeController and their CLSID subtrees) before and after each step, not just exit codes.
Command: two curl requests to http://100.127.62.31:8090/hello fired in parallel from bash (& + wait).
Result: PASS — both returned 200, both bodies exactly Hello from WSC-MVC!, no cross-request leakage or interference observed. This is a basic smoke check only, not a load test (out of scope for M1).
All SPEC §14 acceptance criteria for M1 were run on real Windows/IIS (not inferred) and passed, including one real defect found and fixed during testing (unregistration). Proceeding to M2 (lifecycle/error-handling generalization) is unblocked.
RequestContext + Application with ctx)Command:
cscript //nologo C:\Projects\wsc-mvc\tests\Test-Components.vbs
Result: PASS (after fixing three real defects found while getting here — see docs/DECISIONS.md: Property Get outside a Class block failing registration; FormatNumber leaking a locale comma into correlation ids; Randomize/Rnd() colliding within the same clock tick):
PASS: RequestContext.Path
PASS: RequestContext.HttpMethod
PASS: RequestContext.CorrelationId non-empty (32810-radD62B0)
PASS: RequestContext.ElapsedMs non-negative (0)
PASS: two RequestContext instances have distinct CorrelationIds
PASS: Application.Run(/hello) statusLine
PASS: Application.Run(/hello) contentType
PASS: Application.Run(/hello) body
PASS: Application.Run(unknown route) statusLine
PASS: app.log contains both 200 OK and 404 Not Found outcomes
RESULT: ALL PASS
Command: powershell -File tests\Test-Http.ps1 -BaseUrl http://localhost:8090 — PASS, identical output to M1 (the ctx-based rewrite is entirely internal to Application.wsc/Default.asp; the HTTP contract for /hello and denied .wsc access is unchanged).
Verified real HTTP requests produce correct logs/app.log entries (timestamp, correlation id, method, path, status, elapsed ms), e.g.:
9/19/2026 8:57:05 AM | 322254727-607479 | GET | /hello | 200 OK | 6ms
logs/ is denied over HTTP (GET /logs/app.log -> 404, same hiddenSegments mechanism as other private directories). PASS
/hello requests (bash &/wait): all 8 returned 200 OK with the correct body, every time, across every run in this milestone. This is the actual M2 gate requirement (“repeated/concurrent requests... behave predictably”) and it holds unconditionally.CreateFolder call, not the real app).logs/app.log line count under 8-way concurrency: as few as 1-4 of 8 lines survive, depending on run. This is an accepted, documented tradeoff (see docs/DECISIONS.md) — the retry budget for the log-file mutex is kept deliberately short so logging contention never adds meaningful latency to the HTTP response. The response correctness gate is unaffected; only the completeness of the best-effort diagnostic log is. Not treated as a FAIL: SPEC §10 calls this “safe diagnostic information,” not a correctness requirement.Command sequence identical to M1, now covering RequestContext.wsc too:
powershell -File tools\Register-Components.ps1
powershell -File tools\Unregister-Components.ps1 # confirmed all 3 ProgID/CLSID pairs removed via registry inspection
powershell -File tools\Register-Components.ps1
Result: PASS — /hello returns 500 while unregistered and 200 after re-registering, for all three components together.
docs/DECISIONS.md).Requested by Daniel: the harness should be callable “via an api call” with a “json response,” runnable from the CLI over plain HTTP, not tied to any specific frontend/tooling.
Command (from the Linux OpenClaw host, no SSH/PowerShell/cscript involved):
curl http://100.127.62.31:8090/self-test
Result on a healthy deployment: PASS
{"ok":true,"checks":[
{"name":"request_context_contract","pass":true,"detail":""},
{"name":"correlation_id_uniqueness","pass":true,"detail":""},
{"name":"application_run_hello","pass":true,"detail":""},
{"name":"application_run_unknown_route","pass":true,"detail":""}
]}
Verified the failure-reporting path is real, not just the happy path: deliberately removed WscMvc.HomeController's registry entries, re-ran curl .../self-test, got "ok":false with application_run_hello pinpointed ("detail":"Expected 200 OK, got [500 Internal Server Error]") while the other three checks correctly still reported true; confirmed GET /hello itself also correctly degraded to 500 at the same time. Re-registered and confirmed both /self-test and /hello fully recovered. PASS
Also verified tests/run-self-test.sh (curl + python3 -m json.tool, zero Windows tooling dependency) and the updated tests/Test-Http.ps1 (now folds each /self-test check into its own PASS/FAIL output alongside its existing direct /hello and denied-.wsc checks) both work end to end. PASS
GET /Controllers/SelfTestController.wsc (the component's own source file) still correctly denied — 404, same hiddenSegments rule as every other component. PASS
The SPEC §13 M2 gate (“repeated/concurrent requests and failure cases behave predictably”) was run on real Windows/IIS and holds unconditionally for HTTP response correctness. Four real defects were found and fixed while building this milestone (WSC property-syntax limitation, a locale-formatting bug, a Randomize collision, and a naive concurrent-logging approach that made things worse before a working lock-file mutex was verified) — see docs/DECISIONS.md for full detail on each. Proceeding to M3 (routing) is unblocked.
Powered by TurnKey Linux.