Stufe 4c (#764): Kommentare in C#, WebUI-Skripten, CSS und HTML auf Englisch
Rund 2.600 Kommentarblöcke in 310 C#-Dateien übersetzt, Begründungen vollständig erhalten: blockweise gleiche Anzahl wie vorher, kein Block unter 60 % seiner Länge, der Code außerhalb der Kommentare per Tokenizer byte-identisch geprüft. Zitate deutscher Oberflächentexte und Testdaten bleiben deutsch. WebUI: Kommentare in JS/CSS/HTML übersetzt, JSDoc-@param an die in 4b umbenannten Parameter angeglichen. Dabei behoben: - 4b hatte "tag" (HTML-Tag) als deutsches "Tag" gelesen und zu "dayValue" gemacht (makeElement, svg, Tagesübersicht) - zurück auf tag/day. - Aufgaben "InProgress" bekamen die Plakettenart "laufend", für die es nie eine CSS-Klasse gab - jetzt "success" wie laufende Instanzen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
da4ceac7d5
commit
837a634a22
@@ -5,8 +5,8 @@ using Shouldly;
|
||||
namespace ClawdDotNet.Core.Tests.Audit;
|
||||
|
||||
/// <summary>
|
||||
/// A3: das append-only Audit-Log und die Receipts. Gegen echte SQLite, weil Schema und
|
||||
/// Persistenz der Punkt sind.
|
||||
/// A3: the append-only audit log and the receipts. Against real SQLite, because schema and
|
||||
/// persistence are the point.
|
||||
/// </summary>
|
||||
public sealed class AuditRepositoryTests : IDisposable
|
||||
{
|
||||
@@ -25,7 +25,7 @@ public sealed class AuditRepositoryTests : IDisposable
|
||||
{
|
||||
ClawdDotNet.Core.Storage.SqliteStorage.ReleasePooledConnections(_directory);
|
||||
try { Directory.Delete(_directory, recursive: true); }
|
||||
catch { /* Aufräumen ist Nebensache */ }
|
||||
catch { /* Cleaning up is secondary */ }
|
||||
}
|
||||
|
||||
private AuditEntry Entry(string runId, string tool, AuditStatus status = AuditStatus.Ok) => new()
|
||||
|
||||
@@ -5,18 +5,18 @@ using Shouldly;
|
||||
namespace ClawdDotNet.Core.Tests.Audit;
|
||||
|
||||
/// <summary>
|
||||
/// A3 an der Engine: Jeder Tool-Aufruf wird protokolliert, jeder Lauf bekommt einen Beleg.
|
||||
/// Entscheidend ist die Provenienz — die Engine stempelt Agent, Modell und Herkunft aus
|
||||
/// ihrem eigenen Wissen, nicht aus dem Tool-Ergebnis.
|
||||
/// A3 on the engine: every tool call is logged, every run gets a receipt.
|
||||
/// What matters is the provenance — the engine stamps agent, model and origin from
|
||||
/// its own knowledge, not from the tool result.
|
||||
///
|
||||
/// <para>Seit #554 erzeugt ein ausgefuehrter Aufruf ZWEI Eintraege: erst
|
||||
/// <see cref="AuditStatus.Started"/> vor der Wirkung, dann den Ausgang. Die Tests
|
||||
/// hier filtern deshalb auf den Abschluss, wo es um den Ausgang geht — dass der
|
||||
/// Beginn mitgeschrieben wird, pruefen die WiederaufnahmeTests.</para>
|
||||
/// <para>Since #554 an executed call produces TWO entries: first
|
||||
/// <see cref="AuditStatus.Started"/> before the effect, then the outcome. The tests
|
||||
/// here therefore filter on the completion where the outcome is concerned — that the
|
||||
/// start is recorded too is checked by the WiederaufnahmeTests.</para>
|
||||
///
|
||||
/// <para>Ein Aufruf, der gar nicht erst laeuft (verweigert, unbekannt, vorgelegt),
|
||||
/// hat weiterhin genau einen Eintrag: Der Beginn wird erst nach Rechtepruefung und
|
||||
/// Staging geschrieben.</para>
|
||||
/// <para>A call that does not even run (refused, unknown, presented)
|
||||
/// still has exactly one entry: the start is only written after the permission check and
|
||||
/// staging.</para>
|
||||
/// </summary>
|
||||
public sealed class EngineAuditTests
|
||||
{
|
||||
@@ -27,7 +27,7 @@ public sealed class EngineAuditTests
|
||||
var fixture = new EngineFixture(audit).WithTool(FakeTool.Returning("ok"));
|
||||
var agent = fixture.AddAgent("agent-a", "TestTool");
|
||||
|
||||
// Zwei Tool-Aufrufe, dann Text.
|
||||
// Two tool calls, then text.
|
||||
fixture.Client
|
||||
.RespondsWithToolCall("TestTool")
|
||||
.RespondsWithToolCall("TestTool")
|
||||
@@ -37,13 +37,13 @@ public sealed class EngineAuditTests
|
||||
|
||||
var entries = audit.Entries.ToList();
|
||||
|
||||
// Zwei Aufrufe, je ein Beginn und ein Abschluss.
|
||||
// Two calls, one start and one completion each.
|
||||
entries.Count.ShouldBe(4);
|
||||
entries.ShouldAllBe(e => e.Tool == "TestTool");
|
||||
entries.Count(e => e.Status == AuditStatus.Started).ShouldBe(2);
|
||||
entries.Count(e => e.Status == AuditStatus.Ok).ShouldBe(2);
|
||||
|
||||
// Jeder Beginn gehoert zu genau einem Abschluss.
|
||||
// Every start belongs to exactly one completion.
|
||||
entries.Where(e => e.Status == AuditStatus.Started).Select(e => e.CallId)
|
||||
.ShouldBe(entries.Where(e => e.Status == AuditStatus.Ok).Select(e => e.CallId),
|
||||
ignoreOrder: true);
|
||||
@@ -70,9 +70,9 @@ public sealed class EngineAuditTests
|
||||
public async Task Ein_verweigerter_Aufruf_wird_als_denied_protokolliert()
|
||||
{
|
||||
var audit = new InMemoryAuditRepository();
|
||||
// Tool ist registriert, aber dem Agenten NICHT zugewiesen → PermissionGate greift.
|
||||
// Tool is registered but NOT assigned to the agent → PermissionGate applies.
|
||||
var fixture = new EngineFixture(audit).WithTool(FakeTool.Returning("ok"));
|
||||
var agent = fixture.AddAgent("agent-a" /* kein Tool zugewiesen */);
|
||||
var agent = fixture.AddAgent("agent-a" /* no tool assigned */);
|
||||
fixture.Client.RespondsWithToolCall("TestTool").RespondsWithText("fertig");
|
||||
|
||||
await fixture.Engine.RunAsync(agent, "los", "test-instance", default);
|
||||
@@ -102,7 +102,7 @@ public sealed class EngineAuditTests
|
||||
var audit = new InMemoryAuditRepository();
|
||||
var fixture = new EngineFixture(audit).WithTool(FakeTool.Returning("ok"));
|
||||
var agent = fixture.AddAgent("agent-a", "TestTool");
|
||||
// Aufgabenlaeufe enden seit #577 erst mit einer Ergebniszeile.
|
||||
// Since #577 task runs only end with a result line.
|
||||
fixture.Client.RespondsWithToolCall("TestTool").RespondsWithText("ERGEBNIS: ok - erledigt");
|
||||
|
||||
await fixture.Engine.RunAsync(agent, "los", "test-instance", default, source: "task", taskId: "t-42");
|
||||
@@ -132,7 +132,7 @@ public sealed class EngineAuditTests
|
||||
[Fact]
|
||||
public async Task Ohne_Audit_Repository_laeuft_alles_normal_weiter()
|
||||
{
|
||||
// Gegenprobe: A3 ist optional — die Engine darf ohne Audit-Repo nicht anders laufen.
|
||||
// Counter-check: A3 is optional — the engine must not run differently without an audit repo.
|
||||
var fixture = new EngineFixture().WithTool(FakeTool.Returning("ok"));
|
||||
var agent = fixture.AddAgent("agent-a", "TestTool");
|
||||
fixture.Client.RespondsWithToolCall("TestTool").RespondsWithText("fertig");
|
||||
|
||||
@@ -6,11 +6,11 @@ using ClawdDotNet.Core.Tools;
|
||||
namespace ClawdDotNet.Core.Tests.Audit;
|
||||
|
||||
/// <summary>
|
||||
/// Wiederaufnahme nach hartem Absturz (#554) und die Auswertung des Protokolls (#556).
|
||||
/// Recovery after a hard crash (#554) and the evaluation of the log (#556).
|
||||
/// </summary>
|
||||
public class WiederaufnahmeTests
|
||||
{
|
||||
// ─────────────── Der "angefangen"-Eintrag ───────────────
|
||||
// ─────────────── The "started" entry ───────────────
|
||||
|
||||
[Fact]
|
||||
public async Task Vor_dem_Werkzeug_steht_ein_Eintrag_im_Protokoll()
|
||||
@@ -27,7 +27,7 @@ public class WiederaufnahmeTests
|
||||
|
||||
var eintraege = audit.Entries.Where(e => e.CallId == "c1").ToList();
|
||||
|
||||
// Genau zwei: erst der Beginn, dann der Abschluss — in dieser Reihenfolge.
|
||||
// Exactly two: first the start, then the completion — in this order.
|
||||
Assert.Equal(2, eintraege.Count);
|
||||
Assert.Equal(AuditStatus.Started, eintraege[0].Status);
|
||||
Assert.Equal(AuditStatus.Ok, eintraege[1].Status);
|
||||
@@ -52,8 +52,8 @@ public class WiederaufnahmeTests
|
||||
[Fact]
|
||||
public async Task Ein_Abbruch_laesst_den_Aufruf_nicht_offen_stehen()
|
||||
{
|
||||
// Sonst sähe jeder gewöhnliche Benutzerabbruch beim nächsten Start aus wie
|
||||
// ein Absturz — und niemand sähe mehr hin.
|
||||
// Otherwise every ordinary user cancellation would look like a crash at the next start
|
||||
// — and nobody would look any more.
|
||||
var audit = new InMemoryAuditRepository();
|
||||
var fixture = new EngineFixture(audit).WithTool(
|
||||
FakeTool.Slow(TimeSpan.FromSeconds(5), name: "LangsamTool"));
|
||||
@@ -77,7 +77,7 @@ public class WiederaufnahmeTests
|
||||
[Fact]
|
||||
public async Task Ein_Aufruf_ohne_Abschluss_wird_als_offen_gefunden()
|
||||
{
|
||||
// Simuliert den harten Absturz: Der Beginn steht im Protokoll, mehr nicht.
|
||||
// Simulates the hard crash: the start is in the log, nothing more.
|
||||
var audit = new InMemoryAuditRepository();
|
||||
await audit.AppendAsync(new AuditEntry
|
||||
{
|
||||
@@ -95,8 +95,8 @@ public class WiederaufnahmeTests
|
||||
[Fact]
|
||||
public async Task Alteintraege_ohne_CallId_gelten_nicht_als_offen()
|
||||
{
|
||||
// Sonst legte der erste Start nach der Aktualisierung das ganze Altprotokoll
|
||||
// zur Prüfung vor.
|
||||
// Otherwise the first start after the update would present the whole old log
|
||||
// for review.
|
||||
var audit = new InMemoryAuditRepository();
|
||||
await audit.AppendAsync(new AuditEntry
|
||||
{
|
||||
@@ -107,7 +107,7 @@ public class WiederaufnahmeTests
|
||||
Assert.Empty(await audit.ListOpenCallsAsync(CancellationToken.None));
|
||||
}
|
||||
|
||||
// ─────────────── Die Einstufung ───────────────
|
||||
// ─────────────── The classification ───────────────
|
||||
|
||||
[Fact]
|
||||
public async Task Ein_wiederholbares_Werkzeug_braucht_keine_Entscheidung()
|
||||
@@ -135,7 +135,7 @@ public class WiederaufnahmeTests
|
||||
{
|
||||
var audit = new InMemoryAuditRepository();
|
||||
var registry = new ToolRegistry();
|
||||
registry.Register(FakeTool.Returning("ok", "Versand")); // Vorgabe: nicht wiederholbar
|
||||
registry.Register(FakeTool.Returning("ok", "Versand")); // default: not repeatable
|
||||
|
||||
await audit.AppendAsync(new AuditEntry
|
||||
{
|
||||
@@ -176,7 +176,7 @@ public class WiederaufnahmeTests
|
||||
Assert.Empty(await recovery.SichtenAsync(CancellationToken.None));
|
||||
}
|
||||
|
||||
// ─────────────── Die Auswertung (#556) ───────────────
|
||||
// ─────────────── The evaluation (#556) ───────────────
|
||||
|
||||
[Fact]
|
||||
public async Task Die_Kennzahlen_zaehlen_nur_abgeschlossene_Aufrufe()
|
||||
@@ -184,8 +184,8 @@ public class WiederaufnahmeTests
|
||||
var audit = new InMemoryAuditRepository();
|
||||
var jetzt = DateTime.Now;
|
||||
|
||||
// Zwei vollständige Aufrufe à 100 ms, einer davon gescheitert,
|
||||
// plus ein dritter, der nie endete.
|
||||
// Two complete calls of 100 ms each, one of them failed,
|
||||
// plus a third that never ended.
|
||||
foreach (var (call, status, dauer) in new[]
|
||||
{
|
||||
("c1", AuditStatus.Ok, 100L),
|
||||
@@ -218,9 +218,9 @@ public class WiederaufnahmeTests
|
||||
Assert.Equal(1, t.Failed);
|
||||
Assert.Equal(1, t.Unfinished);
|
||||
|
||||
// 200 ms auf zwei abgeschlossene Aufrufe. Zählten die drei Started-Einträge
|
||||
// mit ihrer Dauer 0 mit, stünde hier 40 — das Werkzeug sähe doppelt so
|
||||
// schnell aus, wie es ist.
|
||||
// 200 ms over two completed calls. If the three Started entries were counted
|
||||
// with their duration 0, this would say 40 — the tool would look twice as
|
||||
// fast as it is.
|
||||
Assert.Equal(100d, t.AverageDurationMs);
|
||||
Assert.Equal(0.5d, t.FailureRate);
|
||||
}
|
||||
@@ -246,7 +246,7 @@ public class WiederaufnahmeTests
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Ein Werkzeug, das sich als wiederholbar ausgibt.</summary>
|
||||
/// <summary>A tool that declares itself repeatable.</summary>
|
||||
internal sealed class WiederholbaresTool : IAgentTool
|
||||
{
|
||||
public string Name => "Abruf";
|
||||
|
||||
Reference in New Issue
Block a user