At Daniel's explicit direction (overrides SPEC.md $5's originally fixed
tree, updated in place per AGENTS.md precedence rules):
- Default.asp + web.config moved into public/; Framework/Controllers/
tests/tools/docs/logs are now siblings entirely outside the served root
- physical separation, not a web.config rule, is what protects them now
- IIS site physicalPath changed to C:\Projects\wsc-mvc\public
- enableParentPaths enabled, scoped to just this site via
`appcmd ... /commit:apphost` (writes a <location> block in
applicationHost.config, not a machine-wide unlock of the locked
system.webServer/asp section)
- Default.asp now uses Server.MapPath("../logs") to reach logs/
- tools/Setup-Site.ps1 automates and reconciles all of the above,
verified idempotent (safe to re-run)
- Verified enableParentPaths does not open a client-side traversal hole:
direct/encoded/double-encoded ../ URL attempts all correctly 404/403
- Full regression re-run (WSH, HTTP, curl+JSON self-test) all pass
unchanged from the client's point of view
- SPEC.md, docs/ARCHITECTURE.md, docs/DECISIONS.md, docs/TEST-RESULTS.md
updated to reflect the new structure as current, not left stale
- Controllers/SelfTestController.wsc: runs the same checks as
tests/Test-Components.vbs in-process, returns JSON
({ok, checks:[{name,pass,detail}]}) - no PowerShell/cscript/SSH needed
- Application.wsc routes /self-test to it; always HTTP 200 (pass/fail lives
in the JSON body, matching conventional health-check design)
- tests/run-self-test.sh: pure curl + python3 wrapper, verified working
directly from the Linux host with zero Windows tooling
- tests/Test-Http.ps1: now also calls /self-test and folds each check into
its own PASS/FAIL output
- Verified both the happy path and a genuine failure path (deliberately
broke HomeController's registration, confirmed /self-test correctly
reported ok:false with the specific failing check pinpointed, then
re-registered and confirmed full recovery)
- docs updated: ARCHITECTURE.md, DECISIONS.md, TEST-RESULTS.md
- RequestContext.wsc: per-request path/method/correlationId/elapsed-time,
primitive-only, no ASP intrinsics
- Application.Run(ctx, ...) centralizes expected-vs-unexpected outcomes and
best-effort logging to logs/app.log (lock-file mutex, no ASP Application
intrinsic available by contract)
- Fixed: Property Get requires a Class block, fails at WSC top level
(regsvr32 exit 5) -> switched to plain Function-based getters
- Fixed: FormatNumber() leaks a locale comma into correlation ids
- Fixed: Randomize+Rnd() collide within the same clock tick -> switched to
FileSystemObject.GetTempName()
- Verified real concurrent-logging tradeoffs experimentally (retry-the-open
alone made it worse; lock-file mutex is correct but a full-coverage retry
budget costs ~330ms latency, so a short budget + accepted best-effort log
loss under heavy load is used instead)
- Investigated and resolved an inherited IUSR:(F) ACL finding under logs/
(standard NTFS CREATOR OWNER materialization, correctly scoped, not a
broad grant)
- All M2 SPEC/plan gate items verified PASS on real IIS; see
docs/TEST-RESULTS.md and docs/DECISIONS.md