chore: low-severity sweep — import session cap, full compile-error lists, leaf-name-fallback validation warning

#05-T24. Three low-severity cleanups, each TDD'd:
- TransportOptions.MaxConcurrentImportSessions (8): BundleSessionStore.Open rejects
  a new session past the cap (evicting expired entries first), bounding the N×~200 MB
  decrypted-content footprint. Soft cap (count/add not atomic).
- ScriptCompiler.TryCompile now joins ALL forbidden-API violations / compile errors
  (string.Join instead of [0]) so an operator sees every problem at once; the T15
  verdict cache stores the joined string.
- SemanticValidator emits an advisory warning when a CallScript target resolves
  ONLY via the composed leaf-name fallback (dynamic child path, not statically
  verified) instead of silently accepting it.

Claude-Session: https://claude.ai/code/session_01MtdgwpEeCUn6cUA5f1LMPj
This commit is contained in:
Joseph Doherty
2026-07-10 02:32:37 -04:00
parent 039cf69cbb
commit 0642d3b988
7 changed files with 131 additions and 3 deletions
@@ -40,6 +40,19 @@ public class ScriptCompilerTests
Assert.Contains("forbidden", result.Error, StringComparison.OrdinalIgnoreCase);
}
[Fact]
public void TryCompile_MultipleForbiddenApis_ReportsAll()
{
// #05-T24: the failure message must enumerate EVERY forbidden API, not
// just the first, so an operator fixing one isn't surprised by the next.
var result = _sut.TryCompile(
"System.IO.File.ReadAllText(\"x\"); System.Diagnostics.Process.Start(\"y\");",
"Test");
Assert.True(result.IsFailure);
Assert.Contains("System.IO", result.Error, StringComparison.Ordinal);
Assert.Contains("Process", result.Error, StringComparison.Ordinal);
}
[Theory]
// Namespace alias — the old substring scan never saw "System.IO." spelled out.
[InlineData("using IO = System.IO; IO.File.ReadAllText(\"x\");")]