Adds Framework/Database.wsc (WscMvc.Database): explicit, request-scoped
ADODB connection/transaction/command lifecycle, parameterized commands
via ADO positional placeholders (never string-concatenated SQL), and
Null-safe value handling. Proven via tests/Test-Components.vbs against a
real database, including a single-quote-containing value round-tripped
through a parameterized INSERT/SELECT to demonstrate no injection risk.
LocalDB was tried first (zero-install) but failed under the real IIS
ApplicationPoolIdentity ("SQL Server Network Interfaces" - LocalDB isn't
supported for IIS-hosted use per Microsoft's own guidance, confirmed
experimentally via a dedicated SelfTestController check, not assumed).
Pivoted to a real network-reachable SQL Server with SQL auth, which has
no dependency on the caller's Windows identity and was verified to work
under the real app-pool identity via the same check.
The live connection string lives only in an untracked db.connectionstring
file (.gitignore'd before it was ever written to disk) and is threaded
through Application.Run exactly like the existing logDir/viewsDir
pattern - Database.wsc itself never touches the filesystem or ASP
intrinsics. No new production route/view was added, per SPEC's
"database-backed example" non-goal - proven the same way M1-M4 proved
their components, via direct component tests plus one diagnostic-only
self-test check.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds Framework/ViewRenderer.wsc (WscMvc.ViewRenderer), loading separate
.html templates and substituting {{Key}} placeholders with HTML-encoded
values from a Scripting.Dictionary. Wires /hello through the new pipeline
(HomeController -> Application -> ViewRenderer -> Views/Home.html) while
preserving the exact pre-M4 response body, so the M1 acceptance test
doubles as a live regression check for the render pipeline.
Views/ is unreachable over HTTP by the same physical-separation guarantee
already used for Framework/ and Controllers/ (sibling of public/, never
inside it) - verified directly, not assumed.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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
- 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