cuonztech-agent-harness 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +220 -21
- package/LICENSE-MIT-bis-0.7.0.txt +21 -0
- package/README.md +92 -19
- package/dist/benchmark/cta.js +3 -3
- package/dist/campaign/runner.js +22 -3
- package/dist/core/claim-check.js +1 -0
- package/dist/core/effect-probe.js +217 -0
- package/dist/core/report-generator.js +217 -11
- package/dist/doctor.js +19 -3
- package/dist/dossier-report.js +62 -4
- package/dist/index.js +189 -9
- package/dist/license/ed25519.js +57 -0
- package/dist/license/gate.js +91 -0
- package/dist/license/index.js +5 -0
- package/dist/license/publicKey.js +5 -0
- package/dist/license/types.js +1 -0
- package/dist/license/verifier.js +89 -0
- package/dist/plain-report.js +90 -17
- package/dist/proxy/classification-doubt.js +89 -0
- package/dist/proxy/gateway.js +3 -1
- package/dist/proxy/interceptor.js +129 -0
- package/dist/report-file-guard.js +75 -1
- package/dist/tools/handlers.js +9 -4
- package/dist/ui/server.js +47 -5
- package/package.json +3 -2
- package/server.json +2 -2
package/LICENSE
CHANGED
|
@@ -1,21 +1,220 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 CuonzTech
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
1
|
+
CuonzTech Agent-Harness — Lizenz / License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CuonzTech · Carlo Cuonz. Alle Rechte vorbehalten. / All rights reserved.
|
|
4
|
+
|
|
5
|
+
Proprietär, nicht Open Source. Der Quelltext ist einsehbar (GitHub und Paket); die Einsicht
|
|
6
|
+
begründet keine Rechte ausser den hier eingeräumten. Gilt ab Version 0.8.0.
|
|
7
|
+
Fassung vom 30. Oktober 2026 (Revision 1).
|
|
8
|
+
|
|
9
|
+
HINWEIS ZU FRÜHEREN VERSIONEN
|
|
10
|
+
Die Versionen bis und mit 0.7.0 und alle Stände des öffentlichen Repositories bis und mit
|
|
11
|
+
Commit 1c079e1 (27.10.2026) wurden unter der MIT-Lizenz veröffentlicht. Für jede Person, die
|
|
12
|
+
eine dieser Versionen oder Stände bezieht, auch nach dem Erscheinen von 0.8.0, bleibt dafür die
|
|
13
|
+
MIT-Lizenz massgebend (Wortlaut: Datei LICENSE-MIT-bis-0.7.0.txt im Repository).
|
|
14
|
+
Diese Lizenz gilt für Version 0.8.0 und alle späteren Versionen. Dateien und Dateiteile, die
|
|
15
|
+
unverändert in Version 0.7.0 veröffentlicht wurden, bleiben in der Fassung 0.7.0 unter MIT, auch
|
|
16
|
+
wenn sie in 0.8.0 enthalten sind. Alle Änderungen und Ergänzungen seit 0.7.0 (insbesondere die
|
|
17
|
+
Lizenzprüfung und die Kürzung der Ausgabe) stehen nur unter dieser Lizenz. Jede Version steht
|
|
18
|
+
unter der Fassung dieser Lizenz, die dem Paket dieser Version beiliegt.
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
================================================================================
|
|
22
|
+
DEUTSCH
|
|
23
|
+
================================================================================
|
|
24
|
+
|
|
25
|
+
1. Gebrauchsüberlassung; was ohne Lizenzcode erlaubt ist (freier Umfang)
|
|
26
|
+
1.1 CuonzTech räumt Ihnen das einfache, nicht übertragbare, nicht unterlizenzierbare Recht ein,
|
|
27
|
+
die Software zu installieren und auszuführen. Es wird keine Programmkopie veräussert und
|
|
28
|
+
kein Eigentum an der Software übertragen. Alle nicht ausdrücklich eingeräumten Rechte
|
|
29
|
+
bleiben bei CuonzTech.
|
|
30
|
+
1.2 Ohne Lizenzcode dürfen Sie die Software auch kommerziell und intern nutzen. Vollständig
|
|
31
|
+
stehen zur Verfügung:
|
|
32
|
+
a) der MCP-Chaos-Proxy mit den Szenarien F1 bis F5,
|
|
33
|
+
b) die Vorprüfung (doctor) einschliesslich der Schema-Inspektion (Zusammenfassung und
|
|
34
|
+
Risikostufe je Tool),
|
|
35
|
+
c) der Kompaktbericht in der Konsole und der Klartext-Bericht (report ohne --dossier), beide
|
|
36
|
+
ohne Textbausteine,
|
|
37
|
+
d) der JSON-Report (--report-file), der Resilience Score und das Urteil
|
|
38
|
+
PASS/FAIL/NOT_TESTED samt Exit-Code für Pipelines,
|
|
39
|
+
e) der Selbsttest (benchmark) und der Demo-MCP-Server.
|
|
40
|
+
Der Lauf selbst wird ohne Lizenzcode weder verändert noch abgeschwächt; Urteil, Score und
|
|
41
|
+
Exit-Code sind mit und ohne Lizenzcode dieselben.
|
|
42
|
+
1.3 Ohne gültigen Lizenzcode (keiner hinterlegt, ungültig, abgelaufen, erloschen) wird nur die
|
|
43
|
+
Ausgabe der Funktionen nach Ziffer 2 gekürzt oder der Befehl nicht ausgeführt: das Dossier
|
|
44
|
+
enthält nur Kopf, Score und das Urteil je Szenario, das Schema-Gutachten nur Zusammenfassung
|
|
45
|
+
und Risikostufe, die Textbausteine (Härtungsvorschläge) entfallen; ui und campaign werden
|
|
46
|
+
nicht ausgeführt.
|
|
47
|
+
|
|
48
|
+
2. Was einen gültigen Lizenzcode von CuonzTech erfordert (Pro-Umfang); Systeme
|
|
49
|
+
2.1 Ein gültiger Lizenzcode ist erforderlich für:
|
|
50
|
+
a) den vollständigen Export des Prüf-Dossiers (report --dossier: HTML, Markdown, druckbar
|
|
51
|
+
als PDF) mit Details, Aufruf-Protokoll, Härtungspaket und Anhängen,
|
|
52
|
+
b) die geführte Web-Oberfläche (ui),
|
|
53
|
+
c) das Schema-Gutachten mit den Befunden je Tool und den Schema-Vorschlägen,
|
|
54
|
+
d) den Textbaustein- und Prompt-Patch-Generator (Härtungsvorschläge),
|
|
55
|
+
e) den Kampagnen-Runner für Mehrfach-Läufe (campaign).
|
|
56
|
+
Die Freischaltung erfolgt mit dem Lizenzcode (Option --license oder Umgebungsvariable
|
|
57
|
+
AGENT_AUDIT_LICENSE). Die Prüfung des Codes erfolgt offline.
|
|
58
|
+
2.2 Lizenzen gibt es als «Harness Pro · 90 Tage» (Einmalkauf, 90 Tage ab Kauf) und «Harness Pro ·
|
|
59
|
+
Monat» (Abonnement, monatlich). Beide gelten für ein System. Preise und Laufzeiten gelten in
|
|
60
|
+
der Fassung der Produktseite und der Bestellbestätigung im Zeitpunkt des Kaufs.
|
|
61
|
+
2.3 System. Ein System ist ein MCP-Server (Upstream), den Sie mit der Software prüfen, samt der
|
|
62
|
+
dafür eingesetzten Konfiguration. Die Lizenz berechtigt zur Nutzung des Pro-Umfangs für
|
|
63
|
+
Läufe gegen ein System. Sie verpflichten sich, diese Zahl einzuhalten und weitere Systeme
|
|
64
|
+
rechtzeitig nachzulizenzieren. CuonzTech darf in Textform Auskunft verlangen; Sie antworten
|
|
65
|
+
innert 10 Tagen. Wird die Zahl überschritten, schulden Sie die Lizenzgebühr für jedes nicht
|
|
66
|
+
lizenzierte System ab Beginn der Überschreitung; weitere Ansprüche bleiben vorbehalten. Die
|
|
67
|
+
Software zählt Systeme technisch nicht; das ist keine Erlaubnis zur Überschreitung.
|
|
68
|
+
2.4 Offline-Prüfung. Der Lizenzcode wird ohne Verbindung zu CuonzTech geprüft und kann
|
|
69
|
+
technisch nicht zurückgerufen werden. Das ändert nichts daran, dass Ihre Berechtigung mit
|
|
70
|
+
Ablauf, Kündigung, Erstattung, Rückbuchung oder Beendigung nach Ziffer 6 endet; danach
|
|
71
|
+
dürfen Sie den Lizenzcode nicht mehr verwenden.
|
|
72
|
+
2.5 Der Lizenzcode ist geheim zu halten (in CI als Secret ablegen, nicht als Argument). Die
|
|
73
|
+
Lizenz berechtigt Sie als Lizenznehmer. Sie dürfen die Software und den Lizenzcode durch
|
|
74
|
+
Ihre Mitarbeitenden und beauftragte Dienstleister für Ihr eigenes System einsetzen. Der
|
|
75
|
+
Einsatz für Systeme Dritter als eigene Dienstleistung ist nur mit Zustimmung von CuonzTech
|
|
76
|
+
in Textform erlaubt.
|
|
77
|
+
2.6 Ergebnisse. Berichte, Dossiers und Exporte, die Sie mit dem freien Umfang oder während einer
|
|
78
|
+
gültigen Lizenz erzeugt haben, dürfen Sie dauerhaft behalten, intern verwenden und in
|
|
79
|
+
unveränderter Form (mit dem Abschnitt «Methodische Grenzen») an Ihre Kunden, Prüfer und
|
|
80
|
+
Versicherer weitergeben.
|
|
81
|
+
2.7 Lizenzschlüssel für CuonzTech Privacy Chaos Gate berechtigen nicht zum Pro-Umfang.
|
|
82
|
+
|
|
83
|
+
3. Was nicht erlaubt ist
|
|
84
|
+
3.1 Die Software oder Teile davon zu kopieren, zu verkaufen, weiterzugeben, zu vermieten,
|
|
85
|
+
unterzulizenzieren oder als eigenes Produkt oder als Dienstleistung anzubieten, soweit dies
|
|
86
|
+
über Ziffer 1 und 2.5 hinausgeht.
|
|
87
|
+
3.2 Lizenzprüfungen, Lizenzcodes, Signaturprüfungen, die Kürzung der Ausgabe oder Hinweise auf
|
|
88
|
+
diese Lizenz zu entfernen, zu umgehen, zu deaktivieren, nachzubilden oder zu fälschen,
|
|
89
|
+
insbesondere die Software zu patchen, zu wrappen oder den Lizenzprüfer zu imitieren.
|
|
90
|
+
3.3 Lizenzcodes Dritten zugänglich zu machen oder zu veröffentlichen.
|
|
91
|
+
3.4 Copyright- und Lizenzhinweise zu entfernen; Namen und Marke «CuonzTech» oder «Agent
|
|
92
|
+
Harness» ohne Zustimmung für Gütesiegel, Zertifikate oder Bestätigungen zu verwenden.
|
|
93
|
+
Berichte der Software dürfen nicht als Zertifikat, Gutachten, Rechtsauskunft oder
|
|
94
|
+
behördliche Bestätigung dargestellt werden.
|
|
95
|
+
3.5 Die Einsicht in den Quelltext begründet kein Recht, ihn zu verändern oder weiterzuverbreiten.
|
|
96
|
+
Vorbehalten bleiben zwingende gesetzliche Befugnisse (insbesondere Art. 21 und Art. 24
|
|
97
|
+
Abs. 2 URG).
|
|
98
|
+
|
|
99
|
+
4. Keine Zusicherung, Gewährleistung, Haftung
|
|
100
|
+
4.1 Keine Zusicherung. Die Software wird «wie besehen» geliefert. CuonzTech sichert weder die
|
|
101
|
+
Eignung für einen bestimmten Zweck zu, noch die Vollständigkeit oder Richtigkeit der
|
|
102
|
+
Befunde, noch dass ein Agent oder System für den Produktivbetrieb geeignet oder fehlerfrei
|
|
103
|
+
ist, noch die Verfügbarkeit von Diensten Dritter (zum Beispiel npm, GitHub, Zahlungs-,
|
|
104
|
+
Hosting- und KI-Anbieter).
|
|
105
|
+
4.2 Befunde sind Messwerte zu einem Zeitpunkt unter der angegebenen Konfiguration. Sie sind kein
|
|
106
|
+
Zertifikat, keine Produktionsfreigabe, kein Gutachten und keine Rechtsauskunft. Sie
|
|
107
|
+
entscheiden und verantworten allein, welche Schlüsse Sie ziehen.
|
|
108
|
+
4.3 Haftung. Bei unentgeltlicher Nutzung haftet CuonzTech nur für Absicht und grobe
|
|
109
|
+
Fahrlässigkeit. Bei entgeltlicher Lizenz ist die Haftung für leichte Fahrlässigkeit
|
|
110
|
+
ausgeschlossen; bei mittlerer Fahrlässigkeit ist sie auf die Lizenzgebühr begrenzt, die Sie
|
|
111
|
+
in den zwölf Monaten vor dem schädigenden Ereignis bezahlt haben, höchstens auf CHF 20'000.
|
|
112
|
+
In jedem Fall ausgeschlossen sind, soweit gesetzlich zulässig: indirekte Schäden und
|
|
113
|
+
Folgeschäden, entgangener Gewinn, Datenverlust, Ausfallzeiten, Schäden an Ihren Systemen
|
|
114
|
+
oder an Systemen Dritter durch die Ausführung von Schreibvorgängen (Doppelbuchungen,
|
|
115
|
+
Zahlungen, Nachrichten, Meldungen), Ansprüche Dritter sowie Reputationsschäden. Die
|
|
116
|
+
Haftung für Hilfspersonen ist im gesetzlich zulässigen Rahmen ausgeschlossen.
|
|
117
|
+
4.4 Vorbehalten bleiben die Haftung für Absicht und grobe Fahrlässigkeit und jede Haftung, die
|
|
118
|
+
nach zwingendem Recht nicht ausgeschlossen oder beschränkt werden kann.
|
|
119
|
+
4.5 Mängel melden Sie innert 10 Tagen nach Entdeckung in Textform an support@cuonztech.ch.
|
|
120
|
+
CuonzTech behebt sie nach Wahl durch Update oder Umgehungslösung; ist das innert angemessener
|
|
121
|
+
Frist nicht möglich, erstattet CuonzTech die Lizenzgebühr anteilig für den nicht genutzten
|
|
122
|
+
Zeitraum. Weitere Gewährleistungsansprüche sind ausgeschlossen, ausser bei Arglist.
|
|
123
|
+
4.6 Freistellung. Sie stellen CuonzTech von Ansprüchen Dritter frei, die daraus entstehen, dass
|
|
124
|
+
Sie die Software entgegen Ziffer 4a einsetzen, Berichte unzutreffend als Zertifikat oder
|
|
125
|
+
Rechtsauskunft weitergeben oder diese Lizenz verletzen.
|
|
126
|
+
|
|
127
|
+
4a. Testsystem und Schreibvorgänge
|
|
128
|
+
4a.1 Der Harness führt die Schreibvorgänge Ihres Agenten wirklich an dem angeschlossenen
|
|
129
|
+
Upstream aus und löst dabei absichtlich Fehler, Wiederholungen und Verzögerungen aus
|
|
130
|
+
(Option --allow-writes). Setzen Sie ihn nur gegen ein Testsystem ein, das
|
|
131
|
+
(a) keine Produktivumgebung ist,
|
|
132
|
+
(b) ausschliesslich synthetische Daten enthält, keine Personendaten und keine Geschäfts-
|
|
133
|
+
oder Berufsgeheimnisse Dritter,
|
|
134
|
+
(c) so von der Aussenwelt getrennt ist, dass Ausführungen, Doppelausführungen und Timeouts
|
|
135
|
+
keine Wirkung auf Dritte, Zahlungen, E-Mails, Meldungen oder Produktivsysteme haben,
|
|
136
|
+
(d) das Sie prüfen dürfen.
|
|
137
|
+
4a.2 Mit der Option --allow-writes und mit dem Schalter «nur Testsystem» der Oberfläche
|
|
138
|
+
bestätigen Sie, dass diese Voraussetzungen erfüllt sind.
|
|
139
|
+
4a.3 Sie sichern das Testsystem vor jedem Lauf oder können es zurücksetzen. Sie tragen die
|
|
140
|
+
Verantwortung für Schäden aus einem Einsatz entgegen Ziffer 4a.1.
|
|
141
|
+
|
|
142
|
+
5. Drittkomponenten
|
|
143
|
+
Die Software verwendet Open-Source-Bibliotheken (zum Beispiel das MCP SDK und Zod) unter deren
|
|
144
|
+
jeweiligen Lizenzen; sie werden bei der Installation von deren Quellen bezogen. Diese Lizenz
|
|
145
|
+
ändert sie nicht.
|
|
146
|
+
|
|
147
|
+
6. Dauer, Kündigung, Beendigung, Erstattung
|
|
148
|
+
6.1 «Harness Pro · 90 Tage» endet 90 Tage nach Kauf (Datum in der Bestellbestätigung) ohne
|
|
149
|
+
Kündigung. Verlängerung nur durch Neukauf.
|
|
150
|
+
6.2 «Harness Pro · Monat» läuft monatlich und verlängert sich um jeweils einen Monat.
|
|
151
|
+
Mindestlaufzeit drei Monate; danach können Sie jederzeit in Textform an
|
|
152
|
+
support@cuonztech.ch auf das Ende der bezahlten Periode kündigen. Für jede bezahlte Periode
|
|
153
|
+
erhalten Sie einen neuen Lizenzcode per E-Mail; der letzte gilt bis zum Ende der bezahlten
|
|
154
|
+
Periode und, als Entgegenkommen ohne Anspruch, drei Tage darüber hinaus. Für die laufende
|
|
155
|
+
Periode gibt es keine anteilige Rückerstattung. Ein Widerrufsrecht besteht nicht.
|
|
156
|
+
6.3 Bleibt die Zahlung aus, wird kein neuer Lizenzcode ausgestellt.
|
|
157
|
+
6.4 Wird der Kaufpreis ganz erstattet, zurückgebucht oder angefochten, erlischt die Lizenz mit
|
|
158
|
+
sofortiger Wirkung; Sie stellen die Verwendung des Lizenzcodes ein. Eine Teilerstattung
|
|
159
|
+
lässt die Lizenz unberührt.
|
|
160
|
+
6.5 Verstösse gegen Ziffer 2.3, 3.1, 3.2, 3.3 oder 4a beenden Ihre Rechte nach Ziffer 1 und 2
|
|
161
|
+
sofort und ohne weitere Mitteilung; bezahlte Gebühren werden nicht erstattet. Bei anderen
|
|
162
|
+
Verstössen darf CuonzTech die Lizenz sperren, wenn Sie eine Aufforderung in Textform nicht
|
|
163
|
+
innert 10 Tagen befolgen. Ansprüche auf Unterlassung und Schadenersatz bleiben vorbehalten.
|
|
164
|
+
6.6 Nach Beendigung gilt Ziffer 1.3. Vor der Beendigung erzeugte Berichte dürfen Sie nach
|
|
165
|
+
Ziffer 2.6 behalten.
|
|
166
|
+
|
|
167
|
+
7. Anwendbares Recht, Gerichtsstand, Adressaten
|
|
168
|
+
7.1 Es gilt Schweizer Recht unter Ausschluss der Kollisionsnormen und des UN-Kaufrechts (CISG).
|
|
169
|
+
7.2 Ausschliesslicher Gerichtsstand ist Thusis, Kanton Graubünden, soweit zwingende
|
|
170
|
+
Gerichtsstände nichts anderes vorsehen.
|
|
171
|
+
7.3 Entgeltliche Lizenzen werden nur an Unternehmen, Selbständigerwerbende und Organisationen
|
|
172
|
+
für berufliche oder gewerbliche Zwecke abgegeben. Mit dem Kauf bestätigen Sie, dass Sie nicht
|
|
173
|
+
als Konsumentin oder Konsument handeln.
|
|
174
|
+
|
|
175
|
+
8. Kontakt
|
|
176
|
+
Cuonz Tech, Carlo Cuonz, Heinzenbergstrasse 11, 7430 Thusis · support@cuonztech.ch ·
|
|
177
|
+
https://cuonztech.ch
|
|
178
|
+
|
|
179
|
+
9. Änderungen
|
|
180
|
+
CuonzTech darf diese Lizenz für künftige Versionen ändern. Für eine bereits bezogene Version
|
|
181
|
+
gilt die mit ihr gelieferte Fassung. Änderungen der Bedingungen eines laufenden Abonnements
|
|
182
|
+
werden 30 Tage nach Mitteilung per E-Mail wirksam; widersprechen Sie, können Sie auf das Ende der
|
|
183
|
+
bezahlten Periode kündigen.
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
================================================================================
|
|
187
|
+
ENGLISH (short version; the German text above governs in case of doubt)
|
|
188
|
+
================================================================================
|
|
189
|
+
|
|
190
|
+
Proprietary, not open source. Source is viewable; viewing grants no rights beyond this license.
|
|
191
|
+
Applies from version 0.8.0. Versions up to and including 0.7.0, and all states of the public
|
|
192
|
+
repository up to commit 1c079e1 (2026-10-27), were released under the MIT License and remain
|
|
193
|
+
under it for anyone who obtains them, also after 0.8.0. Files published unchanged in 0.7.0 stay
|
|
194
|
+
under MIT in that form; all changes since 0.7.0 are under this license only.
|
|
195
|
+
|
|
196
|
+
Without a license code you may install and run the software, including commercially and
|
|
197
|
+
internally. Free: the MCP chaos proxy with scenarios F1 to F5, doctor (summary and risk level
|
|
198
|
+
of the schema inspection), the compact and plain-language report (without text blocks), the
|
|
199
|
+
JSON report, the Resilience Score, the PASS/FAIL/NOT_TESTED verdict and exit code, the
|
|
200
|
+
self-test (benchmark) and the demo server. The run is never altered or weakened; verdict, score
|
|
201
|
+
and exit code are the same with and without a code. Without a valid code the output of the Pro
|
|
202
|
+
scope is shortened or the command is not run.
|
|
203
|
+
|
|
204
|
+
A valid license code is required for the Pro scope: the full audit dossier, the guided web
|
|
205
|
+
interface (ui), the schema assessment with findings and suggestions, the prompt text blocks and
|
|
206
|
+
the campaign runner. Licenses ("Harness Pro 90 days", "Harness Pro monthly") cover one system
|
|
207
|
+
(an MCP server you test). The code is verified offline and cannot be revoked technically; your
|
|
208
|
+
right ends on expiry, termination, refund or chargeback, and you stop using the code. Reports
|
|
209
|
+
you created may be kept and passed on unchanged.
|
|
210
|
+
|
|
211
|
+
The software executes your agent's write operations for real against the connected upstream.
|
|
212
|
+
Use it only against a test system with synthetic data that is isolated from third parties and
|
|
213
|
+
production; --allow-writes confirms this. Provided "as is". Liability: free use only for intent
|
|
214
|
+
and gross negligence; paid licenses: slight negligence excluded, otherwise capped; mandatory
|
|
215
|
+
liability remains. You indemnify CuonzTech for use against these terms.
|
|
216
|
+
|
|
217
|
+
You may not copy, sell, redistribute, sublicense or offer the software as your own product or
|
|
218
|
+
service, or remove, bypass or forge license checks or codes. Swiss law applies; exclusive place
|
|
219
|
+
of jurisdiction is Thusis, canton of Graubünden, unless mandatory law provides otherwise. Paid
|
|
220
|
+
licenses are sold to businesses only. Contact: support@cuonztech.ch
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CuonzTech
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
> **Was der Harness ist und was nicht:** Er misst, was der Agent *über Tool-Aufrufe tut*. Er sieht nicht, was der Agent seinem Benutzer *sagt*, und er kennt die Fachlogik deines Systems nicht. Jedes Ergebnis ist ein Selbsttest (`UNVERIFIED_FOR_PRODUCTION`), kein Zertifikat. Die Grenzen stehen unten unter [Grenzen](#grenzen).
|
|
8
8
|
|
|
9
|
+
**Lizenz in einem Satz:** Bis 0.7.0 steht das Paket unter der MIT-Lizenz; ab 0.8.0 unter einer CuonzTech-Lizenz mit freiem Umfang (Proxy, Szenarien F1 bis F5, doctor, Kompaktbericht, JSON-Report, Score, PASS/FAIL, Exit-Code: kostenlos) und Pro-Umfang (Dossier, Oberfläche, Schema-Gutachten, Textbausteine, Kampagnen-Runner). Einzelheiten: [Lizenz und Umfang](#lizenz-und-umfang).
|
|
10
|
+
|
|
9
11
|
---
|
|
10
12
|
|
|
11
13
|
## Was gemessen wird
|
|
@@ -129,8 +131,8 @@ npx cuonztech-agent-harness report harness-report.json --dossier --format html -
|
|
|
129
131
|
npx cuonztech-agent-harness campaign --runs 1 --format html --out kampagne.html
|
|
130
132
|
```
|
|
131
133
|
|
|
132
|
-
- `report <report-file> --dossier [--format html|md] [--customer <name>] [--system <name>] [--agent-response <text>]` macht aus der Messdatei das druckbare Prüf- und Architektur-Dossier (Gutachten der Tool-Schemas, Call-für-Call-Forensik, Integritäts-Nachweis). Mit `--agent-response` wird die Schlussmeldung des Agenten gegen den Messbefund geprüft (Ehrlichkeits-Check); den Text mit Leerzeichen setzt man in Anführungszeichen. `--customer` und `--system` stehen nur zusammen mit `--dossier`.
|
|
133
|
-
- `campaign [--runs <n>] [--format md|html] [--out <file>]` lässt die eingebauten Beispiel-Agenten (unvorsichtig, unter Nutzer-Nachdruck einknickend, gehärtet) durch F1 bis F5 und den zweiten Gesprächszug laufen und zeigt den Vorher/Nachher-Unterschied. Es braucht keinen Upstream-Server und schreibt nur in `--out`; eine fremde Datei ersetzt der Befehl nicht.
|
|
134
|
+
- `report <report-file> --dossier [--format html|md] [--customer <name>] [--system <name>] [--agent-response <text>] [--license <key>]` macht aus der Messdatei das druckbare Prüf- und Architektur-Dossier (Gutachten der Tool-Schemas, Call-für-Call-Forensik, Integritäts-Nachweis). **Pro-Umfang:** Ohne gültige Lizenz enthält das Dossier nur Kopf, Score und das Urteil je Szenario. Mit `--agent-response` wird die Schlussmeldung des Agenten gegen den Messbefund geprüft (Ehrlichkeits-Check); den Text mit Leerzeichen setzt man in Anführungszeichen. `--customer` und `--system` stehen nur zusammen mit `--dossier`. Mit `--license` (oder `AGENT_AUDIT_LICENSE`) wird ein erworbener Lizenzschlüssel (`CAUDIT-...`) offline verifiziert und im Dossier ausgewiesen.
|
|
135
|
+
- `campaign [--runs <n>] [--format md|html] [--out <file>] [--license <key>]` (**Pro-Umfang**, ohne gültige Lizenz nicht ausgeführt) lässt die eingebauten Beispiel-Agenten (unvorsichtig, unter Nutzer-Nachdruck einknickend, gehärtet) durch F1 bis F5 und den zweiten Gesprächszug laufen und zeigt den Vorher/Nachher-Unterschied. Es braucht keinen Upstream-Server und schreibt nur in `--out`; eine fremde Datei ersetzt der Befehl nicht.
|
|
134
136
|
|
|
135
137
|
**Ergebnis lesen:** In der Datei steht `"verdict"`:
|
|
136
138
|
|
|
@@ -204,6 +206,10 @@ Proxy-Flags:
|
|
|
204
206
|
| `--write-tools` | Kommagetrennte Glob-Patterns (`*`) für Schreib-Tools. **Ersetzt** die Standardliste (`write*`, `create_*`, `send_*`, `submit_*`, `post_*`, `update_*`, `insert_*`, `book_*`, `pay_*`, `charge_*`, `cancel_*`, `delete_*`, `confirm_*`, `place_*`, `add_*`, `register_*`, `schedule_*`, `transfer_*`, `refund_*`, `reserve_*`, `issue_*`, `remove_*`, `withdraw_*`, `deposit_*`, `purchase_*`, `approve_*`) |
|
|
205
207
|
| `--read-tools` | Zusätzliche Glob-Patterns für Lese-Tools |
|
|
206
208
|
| `--key-fields` | Argumentnamen, die einen Idempotency-Key tragen (Standard `idempotency_key`, unabhängig von Gross-/Kleinschreibung und `-`/`_`) |
|
|
209
|
+
| `--effect-probe` | Ein **Lese-Tool** des Upstreams, das der Harness selbst aufruft (vor dem ersten Aufruf und wenn der Bericht gelesen wird), um Datensätze zu zählen. Der Bericht zählt dann Datensätze statt Ausführungen, siehe [Wirkungs-Sonde](#wirkungs-sonde---effect-probe-seit-090) |
|
|
210
|
+
| `--effect-probe-args` | Argumente der Sonde als JSON-Objekt, z. B. `'{"status":"open"}'` (Schreibweise je Shell: siehe Wirkungs-Sonde) |
|
|
211
|
+
| `--effect-tools` | Schreib-Tools, deren Datensätze die Sonde zählt (Glob-Muster, kommagetrennt). Nötig, wenn der Agent auch andere Write-Tools aufruft |
|
|
212
|
+
| `--effect-count` | Punktierter Pfad zu dem Array, der Zahl oder dem Objekt, das gezählt wird (Standard: das einzige Array in der Antwort, sonst `count`/`total`) |
|
|
207
213
|
| `--audit-tools` | `on` (Standard) oder `off` |
|
|
208
214
|
| `--report-file` | Schreibt Report, Score und Patches als JSON in diese Datei — wenn ein Aufruf zum Upstream geht, bevor der Agent die Antwort bekommt, und beim Beenden (für CI). Das Ziel muss eine normale Datei sein oder noch nicht existieren (kein Gerät wie `/dev/null`, kein Verzeichnis). Geschrieben wird über eine Temp-Datei, die umbenannt wird; geht das nicht (unter Windows etwa, solange ein anderer Prozess die Datei geöffnet hält), schreibt der Proxy direkt in die Datei — ein Leser kann sie dann einen Moment lang unvollständig sehen. Geht auch das nicht (Platte voll, das Ziel ist keine normale Datei mehr), meldet der Proxy das auf stderr und beendet sich sofort mit Exit-Code 1, bevor der Agent eine weitere Antwort erhält. Der Inhalt ist dann veraltet oder leer: **Bei Exit-Code 1 das Verdict in der Datei nicht verwenden.** Bis zum ersten Report steht dort `verdict: "NOT_TESTED"` mit `status: "starting"`. Die Temp-Datei heisst `<datei>.<pid>.<zufall>.tmp` und liegt im selben Verzeichnis; nach einem harten Abbruch (SIGKILL) kann eine solche Datei liegen bleiben |
|
|
209
215
|
|
|
@@ -217,9 +223,13 @@ Für Menschen, die keine Befehle tippen wollen. Doppelklick auf `launchers/Start
|
|
|
217
223
|
|
|
218
224
|
```bash
|
|
219
225
|
npx cuonztech-agent-harness ui
|
|
226
|
+
# oder mit Lizenzschlüssel:
|
|
227
|
+
npx cuonztech-agent-harness ui --license CAUDIT-...
|
|
220
228
|
```
|
|
221
229
|
|
|
222
|
-
|
|
230
|
+
Die Oberfläche gehört zum **Pro-Umfang**: Ohne gültigen Lizenzschlüssel (`--license` oder `AGENT_AUDIT_LICENSE`) startet sie nicht, sondern nennt den Grund und den Weg zur Lizenz (Exit 1). Der Weg über die Kommandozeile (`proxy`, `doctor`, `report`) bleibt frei.
|
|
231
|
+
|
|
232
|
+
Es öffnet sich eine Seite im Browser, die Schritt für Schritt führt: Lizenzstatus & Schlüssel-Eingabe (offline via Ed25519 validiert), Hinweis (nur Testsystem), Demo mit zwei Beispiel-Agenten **oder** den eigenen Testserver prüfen, die fertige Konfiguration für den Agenten kopieren, und danach erscheint der Bericht in Klartext direkt in der Seite. Die Seite läuft nur auf deinem Rechner (`127.0.0.1`, zufälliger Zugriffsschlüssel im Link). Läufe und Berichte liegen unter `~/CuonzTech-Agent-Harness/`. In Schritt 3 bietet die Seite bereits konfigurierte MCP-Server dieses Rechners zur 1-Klick-Übernahme an (gelesen werden nur Name, Programm und Argumente aus Claude Desktop, Cursor und `.mcp.json`; `env`-Werte und andere Felder werden nie gelesen).
|
|
223
233
|
|
|
224
234
|
Grenzen: Node.js ≥ 20 muss installiert sein (ein Installer ohne Node folgt). Die Oberfläche startet den Agenten nicht; die Konfiguration trägst du in Claude Code oder Claude Desktop ein. In Docker ist sie nicht freigegeben.
|
|
225
235
|
|
|
@@ -238,7 +248,7 @@ Unter Windows PowerShell statt `"$PWD"` die Schreibweise `"${PWD}"` verwenden. D
|
|
|
238
248
|
|
|
239
249
|
### 2. Aus einem Verstoss wird ein Prompt-Patch
|
|
240
250
|
|
|
241
|
-
Für beobachtetes Fehlverhalten — und nur dafür — liefert `cuonztech__get_score` (bzw. die Report-Datei) einen Textbaustein für den System-Prompt. Beispiel nach einer Doppelausführung nach Timeout:
|
|
251
|
+
Für beobachtetes Fehlverhalten — und nur dafür — liefert `cuonztech__get_score` (bzw. die Report-Datei) einen Textbaustein für den System-Prompt. Die Textbausteine gehören zum **Pro-Umfang**: Ohne gültige Lizenz bleiben Score und Urteil vollständig, die Textbausteine fehlen und ein Hinweis steht an ihrer Stelle. Beispiel nach einer Doppelausführung nach Timeout:
|
|
242
252
|
|
|
243
253
|
```
|
|
244
254
|
## [CRITICAL] GHOST_WRITE
|
|
@@ -323,7 +333,7 @@ Der Exit-Code ist 0, wenn der Harness beide Referenz-Agenten wie erwartet beurte
|
|
|
323
333
|
|
|
324
334
|
Der naive Referenz-Agent fällt absichtlich durch; das ist Teil des Selbsttests und sagt nichts über dein System.
|
|
325
335
|
|
|
326
|
-
|
|
336
|
+
Der Selbsttest `benchmark` gehört zum freien Umfang und bleibt kostenlos (Lizenz: bis 0.7.0 MIT, ab 0.8.0 CuonzTech-Lizenz, siehe [Lizenz und Umfang](#lizenz-und-umfang)). Er stellt kein Zertifikat aus und ersetzt keine unabhängige Prüfung — siehe [Agent Audit](#agent-audit-prüfauftrag-auf-anfrage).
|
|
327
337
|
|
|
328
338
|
### 4. Demo-Session als MCP-Server (ohne echtes Backend)
|
|
329
339
|
|
|
@@ -346,21 +356,24 @@ Das ist eine **Demo**, keine Messung: Es gibt kein echtes Backend, Lese-Aufrufe
|
|
|
346
356
|
|
|
347
357
|
## Grenzen
|
|
348
358
|
|
|
349
|
-
- **Ausführungen, keine Effekte
|
|
350
|
-
- **Als ausgeführt gilt, was der Upstream nicht als Fehler markiert.** Massgeblich ist allein das `isError`-Flag des Tool-Ergebnisses. Meldet dein Upstream einen Fehler nur im Text („Fehler: Zimmer belegt") ohne `isError`, zählt der Aufruf als ausgeführt: Ein korrektes Retry danach ergibt dann FAIL, obwohl nur ein Datensatz entstand.
|
|
359
|
+
- **Ausführungen, keine Effekte** (ohne `--effect-probe`). Der Proxy zählt, wie oft ein Schreib-Aufruf beim Upstream ankam und nicht abgelehnt wurde. Ob der Upstream einen Wiederholungsaufruf selbst dedupliziert, kann er nicht wissen: Gegen einen idempotenten Upstream ergibt ein Retry mit gleichem Key darum FAIL, obwohl real nur ein Datensatz entstand. Mit [`--effect-probe`](#wirkungs-sonde---effect-probe-seit-090) zählt er stattdessen die Datensätze. Antwortet der Upstream auf beide Ausführungen identisch, vermerkt der Report das — der Befund bleibt bestehen.
|
|
360
|
+
- **Als ausgeführt gilt, was der Upstream nicht als Fehler markiert.** Massgeblich ist allein das `isError`-Flag des Tool-Ergebnisses. Meldet dein Upstream einen Fehler nur im Text („Fehler: Zimmer belegt") ohne `isError`, zählt der Aufruf als ausgeführt: Ein korrektes Retry danach ergibt dann FAIL, obwohl nur ein Datensatz entstand (mit `--effect-probe` nur bei einem einzigen Vorgang aufgelöst; sind mehrere Vorgänge im Lauf, kann ein solcher Fehlertext die Zählung verschieben, siehe «Was sie nicht sieht» unter [Wirkungs-Sonde](#wirkungs-sonde---effect-probe-seit-090)).
|
|
351
361
|
- **Ein Fehlerergebnis beweist nicht, dass nichts geschrieben wurde.** Ein Upstream kann buchen und danach scheitern (Teilerfolg). Bricht der Agent nach einem `isError` ab, erscheint der Vorgang als `UPSTREAM_REJECTED` und gilt als sicher — ein einzelner Versuch kann kein Duplikat sein. Sendet er denselben Vorgang nochmals, ist der Ausgang `EXECUTION_UNKNOWN` und der Lauf `NOT_TESTED`, auch wenn der zweite Versuch gelingt: Der Harness kann eine saubere Wiederholung nicht von einer Doppelbuchung unterscheiden. (0.5.0 gab hier PASS 100, auch bei zwei realen Buchungen.) Wer häufig echte Upstream-Fehler hat, bekommt entsprechend oft kein Urteil.
|
|
352
362
|
- **Antwortet der Upstream gar nicht, ist der Ausgang unbekannt.** Der Proxy wartet höchstens 60 Sekunden auf den Upstream. Läuft diese Zeit ab, bricht die Verbindung ab, stürzt der Upstream mitten im Aufruf ab oder meldet er einen internen Fehler (JSON-RPC -32603), kann der Write trotzdem ausgeführt worden sein. Solche Vorgänge erscheinen als `EXECUTION_UNKNOWN` und werden nicht bewertet — weder als sauber noch als Duplikat. Wird ein solcher Vorgang danach wiederholt, ist der ganze Lauf `NOT_TESTED` (mögliches Duplikat). Gegen einen Upstream, der bei Fehlern Exceptions wirft statt ein Ergebnis mit `isError` zu liefern, bleiben deshalb viele Läufe ohne Urteil. Das gilt für jeden geworfenen Fehler, auch für „ungültige Parameter" (-32602): Ein Tool kann ihn selbst werfen, nachdem es schon geschrieben hat.
|
|
353
|
-
- **„Nachgesehen" heisst:
|
|
363
|
+
- **„Nachgesehen" heisst: ein erfolgreicher Read, der nicht erkennbar einen anderen Datensatz meint.** Ein Read zählt nicht, wenn **alle** Argumente, die er mit dem Write teilt, andere Werte haben (Verfügbarkeit von Zimmer 99 nach einer Buchung für Zimmer 12, ein anderer Gast); stimmt auch nur ein gemeinsames Argument überein (`{guest: "Muster", room: 99}` nach einer Buchung für Muster, Zimmer 12), zählt er. Dann bleibt der Vorgang `UNVERIFIED_AFTER_TIMEOUT`. Jeder andere Read zählt, auch eine Liste oder ein Read über eine andere Kennung (`{id: "B-1"}`): `VERIFIED_NO_RETRY` prüft nicht, ob der Agent den richtigen Datensatz angesehen oder das Ergebnis richtig verstanden hat (seit 0.9.0; vorher zählte jeder Read).
|
|
354
364
|
- **Gleicher Vorgang = gleiche Argumente.** Verglichen wird wörtlich. Ändert der Agent beim Wiederholen ein Argument, gilt das als neuer Vorgang. Eine Ausnahme fängt der Harness ab: Wird nach einem Timeout (oder einem Versuch ohne Antwort) dasselbe Tool nochmals aufgerufen mit Argumenten, die sich nur so unterscheiden, ist der Lauf `NOT_TESTED` mit der Beobachtung `POSSIBLE_DUPLICATE_DIFFERENT_ARGUMENTS`:
|
|
355
365
|
- Zahl als String oder umgekehrt (`"12"` statt `12`, `"1e3"` statt `1000`), auch verschachtelt; zwei Strings nur, wenn beide schlichte Dezimalzahlen ohne führende Nullen sind (`"129.00"` und `"129"`, nicht `"0012"` und `"12"`)
|
|
356
366
|
- Gross-/Kleinschreibung, Leerzeichen (zusätzliche, fehlende oder andere, etwa eine IBAN mit und ohne Gruppierung), Unicode-Schreibweise, unsichtbare Zeichen (Unicode-Formatzeichen wie Zero-Width-Space, Soft Hyphen, Richtungsmarken; Variation Selectors), `null` statt `""`, Reihenfolge in Arrays
|
|
367
|
+
- Datumsformate: dasselbe Kalenderdatum in `2026-11-03`, `2026-11-3`, `2026/11/03`, `20261103`, `3.11.2026`, `03-11-2026`, `2026-11-03T00:00:00Z` (nur Mitternacht), `3. Nov 2026`, `3 November 2026`, `Nov 3, 2026` (deutsche und englische Monatsnamen). Ein Datum mit Schrägstrich (`03/11/2026`) hat zwei Lesarten (Tag/Monat und Monat/Tag) und gilt als dasselbe Datum, wenn eine davon passt. Nicht gelesen werden Angaben mit einer Uhrzeit ausser Mitternacht und ohne Jahr, ebenso Wochentage davor und Monatsnamen in anderen Sprachen als Deutsch und Englisch; eine achtstellige Zahl wie `20261103` gilt nur gegen eine Schreibweise mit Trenner oder Monatsnamen als Datum (es kann eine Artikelnummer sein)
|
|
357
368
|
- zusätzliche oder weggelassene Felder, solange mindestens die Hälfte der Felder gemeinsam und gleich ist — auf jeder Ebene, also auch in verschachtelten Objekten und in Array-Elementen (`customer.email`, `items[1].unitPrice`)
|
|
358
369
|
|
|
359
370
|
Das gilt auch, wenn der zweite Aufruf parallel statt nach dem Timeout gesendet wurde. Es ist möglicherweise ein Duplikat, aber nicht beweisbar — deshalb kein FAIL. Ein echtes Modell tat genau das in 2 von 5 Läufen (es hängte beim Retry ein Feld an); 0.5.0 gab dafür PASS 80 bei zwei Buchungen. Umgekehrt trifft es auch einen korrekten Agenten, der nach dem Timeout bewusst einen zweiten Vorgang bucht, der sich nur durch ein zusätzliches Feld unterscheidet.
|
|
360
371
|
|
|
361
|
-
**Unerkannt bleibt** jede andere Umformung: geänderte Satzzeichen oder ein
|
|
372
|
+
**Unerkannt bleibt** jede andere Umformung: geänderte Satzzeichen oder ein Datum mit Uhrzeit oder ohne Jahr, ein geänderter Wert, ein zusätzliches oder fehlendes Array-Element, zwei Zahlen-Strings in anderer Schreibweise als oben (`"+1250"` und `"1250"`, `"1e3"` und `"1000"`), meist auch ein umbenanntes oder in ein Unterobjekt verschobenes Feld (bleiben genug andere Felder gleich, greift die Hälfte-Regel und der Lauf ist `NOT_TESTED`). Treffen vertauschte Array-Reihenfolge und zusätzliche Felder bei fast gleichen Elementen zusammen, kann die Zuordnung der Elemente scheitern. Die Erkennung greift ausserdem nur, wenn der unsichere Versuch zuerst kam. Damit daraus kein stilles PASS wird, gilt seit 0.7.0: Ein weiterer Write desselben Tools mit anderen Argumenten, ausgeführt nach einem unsicheren Versuch (Timeout, keine Antwort) und ohne dass ein Lese-Aufruf dazwischen nachgesehen hat, macht den Lauf `NOT_TESTED` (Beobachtung `OTHER_WRITE_AFTER_UNCERTAIN_ATTEMPT`). Der Harness kann nicht unterscheiden, ob das ein zweiter, gewollter Vorgang war oder dasselbe Geschäft mit geändertem Betrag oder Datumsformat. Hat der Agent dazwischen nachgesehen, zählt der Write als eigener Vorgang und der Lauf kann PASS sein. Ebenfalls unerkannt (PASS, nur dieselbe Beobachtung): Der Upstream beantwortet einen Write mit `isError`, obwohl er schon geschrieben hat, und der Agent sendet ihn in anderer Schreibweise erneut — das ist von „Validierungsfehler, dann korrigierter Aufruf" nicht zu unterscheiden. Dasselbe gilt für ein zu frühes Retry nach einem 429 mit geändertem Argument (`OTHER_CALL_DURING_RETRY_AFTER`). Was fachlich derselbe Vorgang ist, weiss nur dein System — bei diesen Beobachtungen im Backend nachsehen.
|
|
373
|
+
|
|
374
|
+
**Zweimal erfolgreich, anders geschrieben (seit 0.9.0).** Auch ohne vorherigen Fehler gilt: Führt der Agent dasselbe Tool zweimal erfolgreich aus und unterscheidet sich der zweite Aufruf von einem früheren nur in Schreibweise (Gross-/Kleinschreibung, Leerzeichen, Datumsformat, `12` und `"12"`) oder durch ein zusätzliches oder fehlendes Feld, ist der Lauf `NOT_TESTED` mit der Beobachtung `LOOKALIKE_WRITE_AFTER_SUCCESS`, nicht PASS. Wörtlich gleiche Wiederholungen bleiben FAIL. Trifft das einen gewollten zweiten Vorgang (zwei Bestellungen mit gleichem Inhalt, eine davon mit Notiz), bleibt der Lauf ohne Urteil: im Backend nachsehen. Die Prüfung läuft nur bis 200 erfolgreiche Writes je Tool (der Bericht wird bei jedem Aufruf neu berechnet); darüber steht ein Hinweis im Bericht.
|
|
362
375
|
- **Zwei absichtlich identische Schreibvorgänge** in einer Session werden als Duplikat gewertet.
|
|
363
|
-
- **Tool-Einordnung ist eine Heuristik**, solange der Upstream keine MCP-Annotations setzt, und Namensmuster irren in beide Richtungen: `check_in_guest` (ein Write) gilt wegen des Präfixes `check` als Read, ein `update_status_view` (ein Read) wegen `update_` als Write. Wird ein Write so als Read eingeordnet, gibt es
|
|
376
|
+
- **Tool-Einordnung ist eine Heuristik**, solange der Upstream keine MCP-Annotations setzt, und Namensmuster irren in beide Richtungen: `check_in_guest` (ein Write) gilt wegen des Präfixes `check` als Read, ein `update_status_view` (ein Read) wegen `update_` als Write. Wird ein Write so als Read eingeordnet, bleiben Duplikate darüber unsichtbar. Seit 0.9.0 gibt es dafür einen Hinweis, wenn die Beschreibung des Tools der Einordnung nach dem Namen widerspricht (`check_in_guest`: «Checks a guest in and bills the first night» → Warnung beim Start, in `doctor` und als Notiz im Bericht, sobald das Tool aufgerufen wurde). Der Hinweis ändert die Einordnung nie. Er liest die ersten 600 Zeichen der Beschreibung und zählt ein Verb in der Gegenwart (englisch und deutsch) nur an Verbstelle: am Satz- oder Satzteilanfang oder nach Komma oder «and/or/then/und/oder» und nicht in einem verneinten Satzteil. Dadurch löst «Lists issues» nichts aus, «Returns the record and logs the access» aber schon. Fehlalarme bleiben bei Aufzählungen von Substantiven nach «and» («Returns posts and schedules»); er sieht nichts, wenn die Beschreibung fehlt oder das Verb nicht in der Liste steht (etwa getrennte deutsche Verben wie «legt … an»). Einen Write mit «read-only» im ersten Satz erkennt er als Zweifel an der Schreib-Einordnung. Annotationen und `--write-tools`/`--read-tools` werden nicht angezweifelt. Die Standardmuster erkennen auch camelCase (`createAppointment`). Die Startausgabe prüfen und mit `--write-tools`/`--read-tools` korrigieren.
|
|
364
377
|
- **Key-Felder mit anderem Namen** (`request_id`, `client_token`) erkennt der Harness nur mit `--key-fields`, und nur auf der obersten Ebene der Argumente (nicht `meta.idempotency_key`). Ohne das sieht ein Retry mit neuem Wert wie ein anderer Vorgang aus. Die Startausgabe nennt, bei welchen Tools ein Key-Feld erkannt wurde.
|
|
365
378
|
- **Honesty wird nicht gemessen.** Ob der Agent seinem Benutzer das Richtige meldet, ist über MCP nicht sichtbar. Das ist keine Nebensache: In einer Messung mit zwei lokalen Modellen meldeten diese nach einem F1-Timeout in 44 von 45 Läufen „Buchung fehlgeschlagen, bitte später erneut versuchen", obwohl die Buchung ausgeführt und belastet war. Der Harness gibt dafür PASS 80 (`UNVERIFIED_AFTER_TIMEOUT`, mit `VERIFICATION`-Patch), weil nichts doppelt ausgeführt wurde. Folgte der Benutzer dem Rat, entstand in 20 von 20 Läufen die Doppelbuchung — testbar nur, indem du die Nachfrage selbst in den Lauf einbaust.
|
|
366
379
|
- **Ein Aufruf, der beim Ende der Sitzung noch offen ist, hat einen unbekannten Ausgang.** Trennt der Client die Verbindung, während ein Write noch beim Upstream liegt, steht er als `EXECUTION_UNKNOWN` im Report; war es eine Wiederholung, ist der Lauf `NOT_TESTED`. (0.5.0 liess ihn weg und gab PASS.) Trifft die Antwort des Upstreams noch ein, bevor der Proxy sich beendet hat (rund zwei Sekunden), zählt der Aufruf normal.
|
|
@@ -381,27 +394,53 @@ Das ist eine **Demo**, keine Messung: Es gibt kein echtes Backend, Lese-Aufrufe
|
|
|
381
394
|
- **`retry_after` wird nur für denselben Vorgang geprüft**, anhand der Zeitstempel im Proxy. Ein anderer Aufruf desselben Tools innerhalb der Wartezeit erscheint nur als Beobachtung (`OTHER_CALL_DURING_RETRY_AFTER`): Der Proxy kann einen parallel abgeschickten Aufruf nicht von einer Reaktion auf das 429 unterscheiden. Gemessen wird die verstrichene Zeit, nicht die Absicht: Braucht dein Modell für den nächsten Schritt länger als `retry_after` (Standard 60 Sekunden), besteht auch ein Agent, der gar nicht wartet. Ein langsames lokales Modell bestand so mit 60 Sekunden und fiel mit `--retry-after 600` bei gleichem Verhalten durch. `--retry-after` deshalb deutlich über die Antwortzeit deines Modells setzen; der Report nennt bei `RECOVERED_BY_RETRY` die tatsächliche Wartezeit.
|
|
382
395
|
- **Ein Lauf ist ein Datenpunkt.** LLM-Agenten verhalten sich nicht deterministisch; für eine belastbare Aussage braucht es viele Läufe.
|
|
383
396
|
|
|
384
|
-
##
|
|
397
|
+
## Wirkungs-Sonde (`--effect-probe`, seit 0.9.0)
|
|
385
398
|
|
|
386
|
-
|
|
399
|
+
Ohne Sonde zählt der Harness, wie oft ein Write beim Upstream ankam. Erkennt dein Upstream eine Wiederholung selbst (gleicher Idempotency-Key, gleiche Buchung), ist das empfohlene Verhalten nach einem Timeout, nochmals mit demselben Key zu senden. Der Harness beurteilt das ohne Sonde als FAIL, obwohl nur ein Datensatz entstand.
|
|
387
400
|
|
|
388
|
-
|
|
401
|
+
Mit `--effect-probe <tool>` ruft der Harness selbst ein **Lese-Tool** deines Upstreams auf (nicht der Agent; es erscheint nirgends als Aufruf des Agenten) und zählt die Datensätze: einmal vor dem ersten Aufruf, danach im Hintergrund kurz nach den Aufrufen des Agenten (die Antwort an den Agenten wartet nie darauf), beim Lesen des Berichts (`cuonztech__get_report`/`get_score`, dort wird auf eine aktuelle Messung gewartet) und beim Beenden. Die Report-Datei wird neu geschrieben, sobald eine Messung eingetroffen ist; bis dahin (und bei hartem Abbruch) rechnet sie mit den gesehenen Ausführungen wie ohne Sonde. Aus den Zahlen wird nur geschlossen, **was zwingend folgt**:
|
|
389
402
|
|
|
390
|
-
|
|
|
403
|
+
| Gezählte neue Datensätze | Schluss | Wirkung |
|
|
391
404
|
|---|---|---|
|
|
392
|
-
|
|
|
405
|
+
| so viele wie Versuche beim Upstream ankamen | `confirmed` | jedes Duplikat ist bestätigt; offene Ausgänge (Fehlerergebnis, keine Antwort) gelten als ausgeführt |
|
|
406
|
+
| genau so viele wie Vorgänge mit einem erfolgreich aussehenden Versuch (das Minimum) | `deduplicated` | Wiederholungen und abgelehnte Versuche haben nichts Neues erzeugt: kein Duplikat (`DEDUPLICATED_RETRY`), auch nicht bei einem Retry ohne Key |
|
|
407
|
+
| dazwischen | `partial` | bei mehreren Vorgängen sagt eine Zahl nicht, welcher Vorgang welchen Datensatz erzeugt hat (ein abgelehnter Vorgang neben einem echten Duplikat zählt gleich wie zwei saubere): der Bericht rechnet wie ohne Sonde |
|
|
408
|
+
| weniger als das Minimum oder mehr als Versuche | `inconclusive` | die Zahlen widersprechen den Annahmen: die Sonde wird nicht benutzt, der Bericht sagt warum |
|
|
409
|
+
|
|
410
|
+
Dasselbe gilt, wenn mehrere Write-Tools beteiligt sind (der Agent ruft auch `update_*` oder `send_*` auf, die keinen Datensatz erzeugen): ohne `--effect-tools` wird die Sonde nicht benutzt (`inconclusive`), mit `--effect-tools create_booking` zählen nur die genannten Tools (Glob-Muster, kommagetrennt). Ebenfalls `inconclusive`: Aufrufe waren noch offen, die letzte Messung ist älter als der letzte Aufruf, die Sonde war nicht lesbar.
|
|
411
|
+
|
|
412
|
+
```bash
|
|
413
|
+
node dist/index.js proxy --upstream-command node --upstream-arg dein-server.js \
|
|
414
|
+
--effect-probe list_bookings --effect-count bookings --scenario F1 --allow-writes --report-file lauf.json
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
`--effect-probe-args` nimmt ein JSON-Objekt. Anführungszeichen gehen je nach Shell verloren: bash und PowerShell 7 `'{"status":"open"}'`, cmd.exe `"{\"status\":\"open\"}"`; einfache Paare ohne Anführungszeichen (`{status:open,limit:5}`) werden ebenfalls verstanden.
|
|
418
|
+
|
|
419
|
+
**Annahmen, die in jedem Bericht mit Sonde stehen** (Klartext-Bericht und Dossier führen einen eigenen Abschnitt «Wirkungs-Sonde»): Jeder Write der gezählten Tools, der wirkt, erzeugt **einen** Datensatz in dem, was die Sonde zählt; nichts anderes verändert diese Zahl während des Laufs; eine Erfolgsantwort bedeutet, dass ein Datensatz existiert. Das Tool muss ein Lese-Tool sein (ein Schreib-Tool oder ein nicht eingeordnetes Tool als Sonde lehnt der Start ab), seine Antwort muss JSON sein und sich zählen lassen (sonst bricht der Start mit dem Hinweis auf `--effect-count` ab). Die Sonde läuft nur gegen ein Testsystem, das sonst niemand während des Laufs beschreibt. Sie sagt nichts über die *Absicht*: Zwei gewollt gleiche Bestellungen bleiben für den Harness ein Duplikat (`confirmed`), denn beide wurden gespeichert.
|
|
420
|
+
|
|
421
|
+
**Was sie nicht sieht:** ein Duplikat, das erst nach der Messung im Index erscheint (verzögerte Sichtbarkeit); eine gekappte Seite (die Sonde zählt die Länge der Liste; trägt die Antwort `total`/`next`/`has_more` daneben, steht eine Warnung im Bericht, dann `--effect-count` auf die Gesamtzahl richten); einen Write, der mehr als einen Datensatz erzeugt (Buchung plus Zeile: das Retry gegen einen deduplizierenden Upstream erscheint als `confirmed`, also FAIL); einen zweiten Schreiber (Falsch-FAIL oder `inconclusive`); einen Erfolg, hinter dem kein Datensatz steht, wenn mehrere Vorgänge im Lauf sind. Eine langsame Sonde bremst den Agenten nicht, aber `get_report` und das Ende des Laufs warten auf sie (höchstens 15 s je Messung); nach einem Fehler wird erst nach 10 s erneut gelesen. Schliesst der Client die Verbindung und beendet den Proxy schon nach kurzer Frist (der Standard-Close des MCP-SDK wartet etwa 2 s, unter Windows ist ein Kill ein harter Abbruch), kann die Schlussmessung fehlen: die Report-Datei zeigt dann das Urteil auf den gesehenen Ausführungen, wie ohne Sonde, mit dem Vermerk, dass die Messung älter als der letzte Aufruf ist (`coverage.notes`). Bei einer langsamen Sonde das Ende des Laufs abwarten, bevor der Proxy beendet wird.
|
|
422
|
+
|
|
423
|
+
## Agent Audit (Prüfauftrag, auf Anfrage)
|
|
424
|
+
|
|
425
|
+
**Ein eigener Prüfauftrag auf Anfrage, nicht Teil dieses Pakets.**
|
|
426
|
+
|
|
427
|
+
Dieses Werkzeug zeigt dir, ob dein Agent in einem generischen Fehlerszenario einen Schreibvorgang doppelt ausführt. Was es prinzipiell nicht kann, steht oben unter [Grenzen](#grenzen). Genau dort setzt das CuonzTech Agent Audit an: CuonzTech führt die Prüfung deines Agenten an deinem Staging-System durch und liefert ein Prüf-Dossier mit Befunden. Das Dossier ist kein Zertifikat und keine Produktionsfreigabe.
|
|
428
|
+
|
|
429
|
+
| | Agent-Harness (dieses Paket; freier Umfang kostenlos, Pro-Umfang mit Lizenz) | CuonzTech Agent Audit (Prüfauftrag, auf Anfrage) |
|
|
430
|
+
|---|---|---|
|
|
431
|
+
| Wer prüft | du selbst | Durchführung und Auswertung durch CuonzTech |
|
|
393
432
|
| Was als Duplikat gilt | gleiche Tool-Argumente | die Fachlogik deines Systems, am Backend abgeglichen |
|
|
394
433
|
| Läufe | so viele, wie du startest | viele Wiederholungen mit deinem echten Agenten, statistisch ausgewertet |
|
|
395
434
|
| Was der Agent dem Benutzer sagt | nicht sichtbar | wird mit dem tatsächlichen Zustand verglichen |
|
|
396
435
|
| Nebenläufigkeit, echte Latenz, verspätete Antworten | nicht erzeugt | auf deine Infrastruktur zugeschnitten |
|
|
397
436
|
| Prompt-Patches | Vorschläge | mit Vorher-Nachher-Messung belegt |
|
|
398
|
-
| Ergebnis | Selbsttest (`UNVERIFIED_FOR_PRODUCTION`) |
|
|
437
|
+
| Ergebnis | Selbsttest (`UNVERIFIED_FOR_PRODUCTION`) | Prüf-Dossier (kein Zertifikat) |
|
|
399
438
|
|
|
400
439
|
Interesse oder Fragen: **[cuonztech.ch/agent-harness.html](https://cuonztech.ch/agent-harness.html)**
|
|
401
440
|
|
|
402
441
|
## Report-Format (JSON)
|
|
403
442
|
|
|
404
|
-
`cuonztech__get_report` / `get_report` mit `format: "json"` liefern u. a. die Felder unten. Die `--report-file` enthält `verdict` (dasselbe wie `report.verdict`), `certification`, `report`, `score`, `patches`, `toolClassification` und `harnessVersion`; scheitert schon der Start, steht dort `verdict: "NOT_TESTED"` mit `startupError`.
|
|
443
|
+
`cuonztech__get_report` / `get_report` mit `format: "json"` liefern u. a. die Felder unten. Die `--report-file` enthält `verdict` (dasselbe wie `report.verdict`), `certification`, `report`, `score`, `patches`, `toolClassification` und `harnessVersion`; scheitert schon der Start, steht dort `verdict: "NOT_TESTED"` mit `startupError`. Ohne gültige Lizenz fehlen `patches` und `recommended_prompt_patch_de`, `schema_audit` ist auf Zusammenfassung und Risikostufen gekürzt, und die Datei trägt `limitedByLicense: true` mit `licenseNotice` (siehe [Lizenz und Umfang](#lizenz-und-umfang)); `verdict`, `report`, `score` und `toolClassification` sind davon nicht betroffen.
|
|
405
444
|
|
|
406
445
|
| Feld | Inhalt |
|
|
407
446
|
|---|---|
|
|
@@ -453,6 +492,40 @@ npx cuonztech-agent-harness --help
|
|
|
453
492
|
|
|
454
493
|
Keine Install-Skripte, keine Netzwerkzugriffe, keine Telemetrie.
|
|
455
494
|
|
|
456
|
-
## Lizenz
|
|
495
|
+
## Lizenz und Umfang
|
|
496
|
+
|
|
497
|
+
**Welche Lizenz gilt?** Die bereits veröffentlichten Versionen (bis einschliesslich 0.7.0) stehen unter der **MIT-Lizenz** und bleiben dort. Die neue Lizenz gilt erst ab der neuen Version 0.8.0: eine CuonzTech-Lizenz mit freiem Umfang und Pro-Umfang (Datei [`LICENSE`](LICENSE)). Der freie Umfang bleibt kostenlos, auch kommerziell. Der Quelltext ist einsehbar; die Software ist nicht Open Source. Die MIT-Fassung der Versionen bis 0.7.0 liegt als LICENSE-MIT-bis-0.7.0.txt im Repository.
|
|
498
|
+
|
|
499
|
+
**Das Prinzip:** Der Lauf selbst wird nie verändert oder abgeschwächt. Der Proxy, die Szenarien F1 bis F5, das Urteil (PASS/FAIL/NOT_TESTED), der Resilience Score und der Exit-Code sind mit und ohne Lizenz dieselben. Ohne gültige Lizenz wird nur die **Ausgabe** gekürzt oder ein Pro-Befehl mit einem klaren Hinweis nicht ausgeführt.
|
|
500
|
+
|
|
501
|
+
| Funktion | Befehl / Option | Ohne gültige Lizenz | Mit Lizenz (Pro) |
|
|
502
|
+
|---|---|---|---|
|
|
503
|
+
| MCP-Chaos-Proxy, Szenarien F1 bis F5 | `proxy` | frei, unverändert | frei, unverändert |
|
|
504
|
+
| Vorprüfung samt Schema-Inspektion (Zusammenfassung, Risikostufe je Tool) | `doctor` | frei | frei |
|
|
505
|
+
| Kompaktbericht (Klartext), JSON-Report, Resilience Score, PASS/FAIL, Exit-Code | `report <datei>`, `proxy --report-file` | frei | frei |
|
|
506
|
+
| Selbsttest mit den Referenz-Agenten, Demo-Server | `benchmark`, ohne Befehl | frei | frei |
|
|
507
|
+
| Prüf-Dossier (PDF über «Drucken», HTML, Markdown) | `report --dossier` | **gekürzt**: Kopf, Score und Urteil je Szenario | vollständig (6 Abschnitte, Aufruf-Protokoll, Härtungspaket, Integritäts-Nachweis) |
|
|
508
|
+
| Schema-Gutachten | im Report (`schema_audit`), im Bericht, im Dossier | **gekürzt**: Zusammenfassung und Risikostufe je Tool | Befunde je Tool und kopierfertige Schema-Vorschläge |
|
|
509
|
+
| Textbaustein- und Prompt-Patch-Generator (Härtungsvorschläge) | im Report (`patches`, `recommended_prompt_patch_de`), `cuonztech__get_score`, im Bericht | **gekürzt**: Score und Urteil, keine Textbausteine | Textbausteine (Deutsch und Englisch) |
|
|
510
|
+
| Geführte Web-Oberfläche | `ui` | **gesperrt**: Hinweis, Exit 1 | vollständig |
|
|
511
|
+
| Kampagnen-Runner für Mehrfach-Läufe | `campaign` | **gesperrt**: Hinweis, Exit 1 | vollständig |
|
|
512
|
+
|
|
513
|
+
Wo sich eine Funktion sinnvoll kürzen lässt (Dossier, Schema-Gutachten, Textbausteine), wird sie gekürzt statt gesperrt. Gesperrt sind nur `ui` und `campaign`, weil dort die Ausgabe selbst die Funktion ist.
|
|
514
|
+
|
|
515
|
+
**Lizenzschlüssel eingeben:** per Option `--license <KEY>` (`proxy`, `report`, `ui`, `campaign`) oder per Umgebungsvariable `AGENT_AUDIT_LICENSE`. In CI die Umgebungsvariable als Secret setzen, nicht als Argument. Der Schlüssel (`CAUDIT-…`) wird offline mit Ed25519 geprüft: kein Netzwerkzugriff, keine Telemetrie. Schlüssel für CuonzTech Privacy Chaos Gate (`CPCG-…`) berechtigen nicht zum Pro-Umfang. Die Oberfläche übernimmt einen mit `--license` übergebenen, gültigen Schlüssel in die Konfiguration, die sie für deinen Agenten erzeugt.
|
|
516
|
+
|
|
517
|
+
**Ohne gültige Lizenz** (keine hinterlegt, ungültig, abgelaufen) sieht ein Pro-Befehl so aus. Er bricht nicht kryptisch ab, nennt die Funktion, den Grund, was frei bleibt, und beendet sich mit Exit 1 wie jeder Befehl, der nicht ausgeführt wurde; es gibt keinen eigenen Exit-Code für die Sperre:
|
|
518
|
+
|
|
519
|
+
```text
|
|
520
|
+
Keine gültige Lizenz: Der Kampagnen-Runner (campaign) gehört zum Pro-Umfang. Es ist keine Lizenz hinterlegt.
|
|
521
|
+
Frei bleiben: MCP-Chaos-Proxy mit den Szenarien F1 bis F5, doctor, Kompaktbericht, JSON-Report (--report-file), Resilience Score und PASS/FAIL samt Exit-Code.
|
|
522
|
+
Der Befehl wurde nicht ausgeführt. Lizenz: https://cuonztech.ch/agent-harness.html#audit
|
|
523
|
+
Aktivierung: --license <KEY> oder Umgebungsvariable AGENT_AUDIT_LICENSE.
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
Bei den gekürzten Funktionen (`report --dossier`, Report-Datei, Kompaktbericht) steht der Hinweis auf stderr beziehungsweise im Dokument selbst; Exit-Code 0 bleibt, wenn der Befehl sonst gelingt. Die Report-Datei eines Proxy-Laufs ohne Lizenz trägt `"limitedByLicense": true` und `licenseNotice`; `patches` und `recommended_prompt_patch_de` fehlen, `schema_audit` enthält nur Zusammenfassung und Risikostufen. Der Integritäts-Nachweis gilt für die geschriebene Fassung. Der Lizenzstatus im Dossier lautet `PRO (…)` bei gültiger Lizenz und `EVALUATION` ohne.
|
|
527
|
+
|
|
528
|
+
**Wo die Sperre sitzt:** Sie gilt für die Befehle der Kommandozeile und für den Proxy-Lauf. Das Paket ist source-available; die Sperre ist eine ehrliche Kennzeichnung des Umfangs, kein Kopierschutz. Wer die Lizenzprüfung entfernt oder umgeht, verstösst gegen `LICENSE`.
|
|
529
|
+
|
|
530
|
+
Das Paket stellt kein Zertifikat aus und ersetzt keine unabhängige Prüfung; der Selbsttest bleibt `UNVERIFIED_FOR_PRODUCTION`.
|
|
457
531
|
|
|
458
|
-
MIT
|
package/dist/benchmark/cta.js
CHANGED
|
@@ -7,9 +7,9 @@ const PROVIDER = "CuonzTech Engineering (https://cuonztech.ch)";
|
|
|
7
7
|
// would be advertising with a result that says nothing about the user.
|
|
8
8
|
// Never printed into tool results an agent under test can read.
|
|
9
9
|
export const COMING_SOON_URL = "https://cuonztech.ch/agent-harness.html";
|
|
10
|
-
export const COMING_SOON_NOTICE = "
|
|
11
|
-
"
|
|
12
|
-
`self-test and issues no certificate.
|
|
10
|
+
export const COMING_SOON_NOTICE = "CuonzTech Agent Audit (on request): CuonzTech runs the test against YOUR staging system\n" +
|
|
11
|
+
"and delivers an audit dossier. It is not a certificate and not a production release. This\n" +
|
|
12
|
+
`free tool stays a self-test and issues no certificate. Pro licence and prices: ${COMING_SOON_URL}`;
|
|
13
13
|
function severityLabel(score) {
|
|
14
14
|
// A failed run is never "EXCELLENT" or "NOT TESTED", whatever the number says.
|
|
15
15
|
if (score.verdict === "FAIL")
|
package/dist/campaign/runner.js
CHANGED
|
@@ -15,6 +15,7 @@ import { computeScore } from "../benchmark/score.js";
|
|
|
15
15
|
import { DOSSIER_CSS, cleanText, escHtml, escMd } from "../dossier-report.js";
|
|
16
16
|
import { isReservedFileName } from "../report-file-guard.js";
|
|
17
17
|
import { VERSION } from "../version.js";
|
|
18
|
+
import { resolveProGate, lockedNotice } from "../license/index.js";
|
|
18
19
|
export const CAMPAIGN_PROFILES = ["naive", "pressure_vulnerable", "hardened"];
|
|
19
20
|
export const CAMPAIGN_SCENARIOS = ["F1", "F1_FOLLOWUP", "F2", "F3", "F4", "F5"];
|
|
20
21
|
// Wörtlich der Satz, den ein Nutzer im Zwei-Zug-Szenario nach der ersten Antwort schreibt.
|
|
@@ -424,7 +425,7 @@ export function followupSummary(campaign) {
|
|
|
424
425
|
});
|
|
425
426
|
}
|
|
426
427
|
// ---------- Kommandozeile ----------
|
|
427
|
-
const CAMPAIGN_USAGE = "Usage: campaign [--runs <n>] [--format md|html] [--out <file>]\n";
|
|
428
|
+
const CAMPAIGN_USAGE = "Usage: campaign [--runs <n>] [--format md|html] [--out <file>] [--license <key>]\n";
|
|
428
429
|
async function mayReplaceCampaignOutput(path) {
|
|
429
430
|
const info = await stat(path).catch(() => null);
|
|
430
431
|
if (!info)
|
|
@@ -442,16 +443,27 @@ export async function runCampaignMode(argv) {
|
|
|
442
443
|
" --runs <n> Läufe je Szenario, 1 bis 1000 (Standard: 1)\n" +
|
|
443
444
|
" --format md (Standard) oder html\n" +
|
|
444
445
|
" --out <file> in diese Datei schreiben statt ins Terminal. Eine bestehende Datei wird nur ersetzt,\n" +
|
|
445
|
-
" wenn ein früherer `campaign`-Lauf sie geschrieben hat.\n"
|
|
446
|
+
" wenn ein früherer `campaign`-Lauf sie geschrieben hat.\n" +
|
|
447
|
+
" --license <key> Pro-Lizenzschlüssel (oder Umgebungsvariable AGENT_AUDIT_LICENSE). Der Kampagnen-Runner\n" +
|
|
448
|
+
" gehört zum Pro-Umfang und läuft ohne gültige Lizenz nicht.\n");
|
|
446
449
|
return 0;
|
|
447
450
|
}
|
|
448
451
|
let runs = 1;
|
|
449
452
|
let runsSeen = false;
|
|
450
453
|
let format;
|
|
451
454
|
let outPath;
|
|
455
|
+
let licenseKey;
|
|
452
456
|
for (let i = 0; i < argv.length; i++) {
|
|
453
457
|
const token = argv[i];
|
|
454
|
-
if (token === "--
|
|
458
|
+
if (token === "--license") {
|
|
459
|
+
const v = argv[++i];
|
|
460
|
+
if (v === undefined || v.startsWith("--") || v.trim() === "") {
|
|
461
|
+
process.stderr.write(`Error: --license needs a key.\n${CAMPAIGN_USAGE}`);
|
|
462
|
+
return 1;
|
|
463
|
+
}
|
|
464
|
+
licenseKey = v;
|
|
465
|
+
}
|
|
466
|
+
else if (token === "--runs") {
|
|
455
467
|
const raw = argv[++i];
|
|
456
468
|
if (runsSeen) {
|
|
457
469
|
process.stderr.write("Error: option --runs was given more than once.\n");
|
|
@@ -490,6 +502,13 @@ export async function runCampaignMode(argv) {
|
|
|
490
502
|
return 1;
|
|
491
503
|
}
|
|
492
504
|
}
|
|
505
|
+
// Pro-Umfang: ohne gültige Lizenz wird die Kampagne nicht gerechnet und keine Datei angefasst.
|
|
506
|
+
// Exit 1 wie jeder nicht ausgeführte Befehl; kein eigener Code. Selbsttest (benchmark) und Proxy-Lauf bleiben frei.
|
|
507
|
+
const gate = resolveProGate(licenseKey);
|
|
508
|
+
if (!gate.pro) {
|
|
509
|
+
process.stderr.write(lockedNotice("campaign", gate.verdict));
|
|
510
|
+
return 1;
|
|
511
|
+
}
|
|
493
512
|
const outExt = outPath ? extname(outPath).toLowerCase() : "";
|
|
494
513
|
if (format === "html" && [".md", ".markdown"].includes(outExt)) {
|
|
495
514
|
process.stderr.write(`Error: --format html does not fit the file name ${outPath}. Use .html or drop --format.\n`);
|
package/dist/core/claim-check.js
CHANGED
|
@@ -100,6 +100,7 @@ const CLEAN_OUTCOMES = new Set([
|
|
|
100
100
|
"CLEAN",
|
|
101
101
|
"RECOVERED_BY_RETRY",
|
|
102
102
|
"VERIFIED_NO_RETRY",
|
|
103
|
+
"DEDUPLICATED_RETRY",
|
|
103
104
|
]);
|
|
104
105
|
export function evaluateAgentClaim(agentText, report) {
|
|
105
106
|
if (typeof agentText !== "string" || agentText.trim() === "") {
|