audit-tools 0.30.3 → 0.30.5
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/dist/audit/cli/auditStep.d.ts.map +1 -1
- package/dist/audit/cli/auditStep.js +24 -13
- package/dist/audit/cli/auditStep.js.map +1 -1
- package/dist/audit/cli/nextStepHelpers.d.ts.map +1 -1
- package/dist/audit/cli/nextStepHelpers.js +11 -6
- package/dist/audit/cli/nextStepHelpers.js.map +1 -1
- package/dist/audit/cli/reviewRun.d.ts.map +1 -1
- package/dist/audit/cli/reviewRun.js +9 -4
- package/dist/audit/cli/reviewRun.js.map +1 -1
- package/dist/audit/contracts/schemaEnforcedEmit.d.ts +75 -0
- package/dist/audit/contracts/schemaEnforcedEmit.d.ts.map +1 -0
- package/dist/audit/contracts/schemaEnforcedEmit.js +131 -0
- package/dist/audit/contracts/schemaEnforcedEmit.js.map +1 -0
- package/dist/audit/contracts/workerSchemas.d.ts +22 -4
- package/dist/audit/contracts/workerSchemas.d.ts.map +1 -1
- package/dist/audit/contracts/wrapperResponse.d.ts +18 -18
- package/dist/audit/extractors/analyzers/acquisitionEngine.d.ts +140 -0
- package/dist/audit/extractors/analyzers/acquisitionEngine.d.ts.map +1 -0
- package/dist/audit/extractors/analyzers/acquisitionEngine.js +262 -0
- package/dist/audit/extractors/analyzers/acquisitionEngine.js.map +1 -0
- package/dist/audit/extractors/analyzers/registry.d.ts +2 -0
- package/dist/audit/extractors/analyzers/registry.d.ts.map +1 -1
- package/dist/audit/extractors/analyzers/registry.js +5 -0
- package/dist/audit/extractors/analyzers/registry.js.map +1 -1
- package/dist/audit/extractors/gitHistory.d.ts +46 -0
- package/dist/audit/extractors/gitHistory.d.ts.map +1 -0
- package/dist/audit/extractors/gitHistory.js +97 -0
- package/dist/audit/extractors/gitHistory.js.map +1 -0
- package/dist/audit/extractors/graph.d.ts +19 -1
- package/dist/audit/extractors/graph.d.ts.map +1 -1
- package/dist/audit/extractors/graph.js +31 -0
- package/dist/audit/extractors/graph.js.map +1 -1
- package/dist/audit/extractors/risk.d.ts +16 -0
- package/dist/audit/extractors/risk.d.ts.map +1 -1
- package/dist/audit/extractors/risk.js +28 -0
- package/dist/audit/extractors/risk.js.map +1 -1
- package/dist/audit/io/artifacts.d.ts +3 -1
- package/dist/audit/io/artifacts.d.ts.map +1 -1
- package/dist/audit/io/artifacts.js +1 -0
- package/dist/audit/io/artifacts.js.map +1 -1
- package/dist/audit/orchestrator/artifactFreshness.d.ts +2 -1
- package/dist/audit/orchestrator/artifactFreshness.d.ts.map +1 -1
- package/dist/audit/orchestrator/artifactFreshness.js +5 -15
- package/dist/audit/orchestrator/artifactFreshness.js.map +1 -1
- package/dist/audit/orchestrator/artifactMetadata.d.ts.map +1 -1
- package/dist/audit/orchestrator/artifactMetadata.js +24 -3
- package/dist/audit/orchestrator/artifactMetadata.js.map +1 -1
- package/dist/audit/orchestrator/dependencyMap.d.ts +7 -0
- package/dist/audit/orchestrator/dependencyMap.d.ts.map +1 -1
- package/dist/audit/orchestrator/dependencyMap.js +5 -1
- package/dist/audit/orchestrator/dependencyMap.js.map +1 -1
- package/dist/audit/orchestrator/executorRunners.d.ts.map +1 -1
- package/dist/audit/orchestrator/executorRunners.js +10 -9
- package/dist/audit/orchestrator/executorRunners.js.map +1 -1
- package/dist/audit/orchestrator/ingestionExecutors.d.ts.map +1 -1
- package/dist/audit/orchestrator/ingestionExecutors.js +5 -1
- package/dist/audit/orchestrator/ingestionExecutors.js.map +1 -1
- package/dist/audit/orchestrator/intentCheckpointGate.d.ts +129 -0
- package/dist/audit/orchestrator/intentCheckpointGate.d.ts.map +1 -0
- package/dist/audit/orchestrator/intentCheckpointGate.js +193 -0
- package/dist/audit/orchestrator/intentCheckpointGate.js.map +1 -0
- package/dist/audit/orchestrator/ledger.d.ts +30 -0
- package/dist/audit/orchestrator/ledger.d.ts.map +1 -0
- package/dist/audit/orchestrator/ledger.js +126 -0
- package/dist/audit/orchestrator/ledger.js.map +1 -0
- package/dist/audit/orchestrator/nextStep.d.ts +11 -29
- package/dist/audit/orchestrator/nextStep.d.ts.map +1 -1
- package/dist/audit/orchestrator/nextStep.js +11 -29
- package/dist/audit/orchestrator/nextStep.js.map +1 -1
- package/dist/audit/orchestrator/resultBaseline.d.ts +136 -0
- package/dist/audit/orchestrator/resultBaseline.d.ts.map +1 -0
- package/dist/audit/orchestrator/resultBaseline.js +138 -0
- package/dist/audit/orchestrator/resultBaseline.js.map +1 -0
- package/dist/audit/orchestrator/staleness.d.ts.map +1 -1
- package/dist/audit/orchestrator/staleness.js +25 -1
- package/dist/audit/orchestrator/staleness.js.map +1 -1
- package/dist/audit/quota/index.d.ts +32 -32
- package/dist/audit/types/artifactMetadata.d.ts +34 -0
- package/dist/audit/types/artifactMetadata.d.ts.map +1 -1
- package/dist/audit/types/artifactMetadata.js +10 -1
- package/dist/audit/types/artifactMetadata.js.map +1 -1
- package/dist/audit/types.d.ts +13 -4
- package/dist/audit/types.d.ts.map +1 -1
- package/dist/audit/types.js +8 -0
- package/dist/audit/types.js.map +1 -1
- package/dist/remediate/steps/nextStep.d.ts +11 -23
- package/dist/remediate/steps/nextStep.d.ts.map +1 -1
- package/dist/remediate/steps/nextStep.js +45 -43
- package/dist/remediate/steps/nextStep.js.map +1 -1
- package/dist/shared/contentKey.d.ts +83 -0
- package/dist/shared/contentKey.d.ts.map +1 -0
- package/dist/shared/contentKey.js +163 -0
- package/dist/shared/contentKey.js.map +1 -0
- package/dist/shared/friction/captureFrictionEvent.d.ts +50 -0
- package/dist/shared/friction/captureFrictionEvent.d.ts.map +1 -0
- package/dist/shared/friction/captureFrictionEvent.js +34 -0
- package/dist/shared/friction/captureFrictionEvent.js.map +1 -0
- package/dist/shared/friction/triage.d.ts +126 -0
- package/dist/shared/friction/triage.d.ts.map +1 -0
- package/dist/shared/friction/triage.js +149 -0
- package/dist/shared/friction/triage.js.map +1 -0
- package/dist/shared/git.d.ts +41 -0
- package/dist/shared/git.d.ts.map +1 -1
- package/dist/shared/git.js +119 -0
- package/dist/shared/git.js.map +1 -1
- package/dist/shared/index.d.ts +17 -5
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/index.js +11 -4
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/io/auditToolsPaths.d.ts +9 -0
- package/dist/shared/io/auditToolsPaths.d.ts.map +1 -1
- package/dist/shared/io/auditToolsPaths.js +11 -0
- package/dist/shared/io/auditToolsPaths.js.map +1 -1
- package/dist/shared/io/frictionCapture.d.ts +2 -0
- package/dist/shared/io/frictionCapture.d.ts.map +1 -1
- package/dist/shared/io/frictionCapture.js +1 -1
- package/dist/shared/io/frictionCapture.js.map +1 -1
- package/dist/shared/providers/providerFactory.d.ts +16 -1
- package/dist/shared/providers/providerFactory.d.ts.map +1 -1
- package/dist/shared/providers/providerFactory.js +43 -0
- package/dist/shared/providers/providerFactory.js.map +1 -1
- package/dist/shared/providers/types.d.ts +40 -0
- package/dist/shared/providers/types.d.ts.map +1 -1
- package/dist/shared/quota/capacity.d.ts +12 -12
- package/dist/shared/quota/quotaSource.d.ts +2 -2
- package/dist/shared/quota/types.d.ts +4 -4
- package/dist/shared/repair/brokeredDispatch.d.ts +147 -0
- package/dist/shared/repair/brokeredDispatch.d.ts.map +1 -0
- package/dist/shared/repair/brokeredDispatch.js +220 -0
- package/dist/shared/repair/brokeredDispatch.js.map +1 -0
- package/dist/shared/repair/emitValidateRepair.d.ts +124 -0
- package/dist/shared/repair/emitValidateRepair.d.ts.map +1 -0
- package/dist/shared/repair/emitValidateRepair.js +179 -0
- package/dist/shared/repair/emitValidateRepair.js.map +1 -0
- package/dist/shared/repair/index.d.ts +10 -0
- package/dist/shared/repair/index.d.ts.map +1 -0
- package/dist/shared/repair/index.js +3 -0
- package/dist/shared/repair/index.js.map +1 -0
- package/dist/shared/stableStringify.d.ts +14 -0
- package/dist/shared/stableStringify.d.ts.map +1 -0
- package/dist/shared/stableStringify.js +28 -0
- package/dist/shared/stableStringify.js.map +1 -0
- package/package.json +1 -1
- package/schemas/audit_result.schema.json +9 -0
- package/schemas/audit_results.schema.json +9 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { FrictionCaptureArtifact } from '../io/frictionCapture.js';
|
|
2
|
+
/** A normalized validation error the seam reasons over (validator-agnostic). */
|
|
3
|
+
export interface RepairValidationError {
|
|
4
|
+
/** Dotted path to the offending field (validator's own path token). */
|
|
5
|
+
path: string;
|
|
6
|
+
/** Human-readable message. */
|
|
7
|
+
message: string;
|
|
8
|
+
/**
|
|
9
|
+
* Whether this error sits on a REQUIRED field. Only REQUIRED errors gate stage
|
|
10
|
+
* escalation; an OPTIONAL-field error is something stage1 coercion is allowed
|
|
11
|
+
* to clear by dropping the sub-object.
|
|
12
|
+
*/
|
|
13
|
+
required: boolean;
|
|
14
|
+
}
|
|
15
|
+
/** Outcome of running the canonical validator over a payload. */
|
|
16
|
+
export interface RepairValidationResult {
|
|
17
|
+
/** All errors (required + optional). Empty ⟹ clean. */
|
|
18
|
+
errors: RepairValidationError[];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Classification + deterministic coercion for one contract. The seam asks the
|
|
22
|
+
* contract to coerce its own OPTIONAL sub-objects and backfill its own
|
|
23
|
+
* recoverable identity — the seam owns the staging policy, the contract owns the
|
|
24
|
+
* field semantics.
|
|
25
|
+
*/
|
|
26
|
+
export interface RepairCoercion {
|
|
27
|
+
/**
|
|
28
|
+
* Deterministically coerce the payload in a NON-DESTRUCTIVE, OPTIONAL-only way:
|
|
29
|
+
* drop/empty optional sub-objects that fail validation, and backfill tool-owned
|
|
30
|
+
* identity that is RECOVERABLE PER ELEMENT. Must NEVER mutate a required
|
|
31
|
+
* identity coordinate by homogenizing across elements.
|
|
32
|
+
*
|
|
33
|
+
* Returns the (possibly new) payload plus the structured record of what it did,
|
|
34
|
+
* so the seam can emit one friction event per change and decide escalation.
|
|
35
|
+
*/
|
|
36
|
+
coerce(payload: unknown): RepairCoercionResult;
|
|
37
|
+
}
|
|
38
|
+
/** What stage1 coercion did to a payload. */
|
|
39
|
+
export interface RepairCoercionResult {
|
|
40
|
+
/** The coerced payload (same reference allowed if nothing changed). */
|
|
41
|
+
payload: unknown;
|
|
42
|
+
/** OPTIONAL sub-objects dropped/emptied, by path. */
|
|
43
|
+
drops: string[];
|
|
44
|
+
/** Tool-owned identity fields backfilled per element, by path. */
|
|
45
|
+
backfills: string[];
|
|
46
|
+
/**
|
|
47
|
+
* Set true when a REQUIRED identity field is missing on a MULTI-element array
|
|
48
|
+
* and is NOT recoverable per element — the payload must escalate straight to
|
|
49
|
+
* `unrepairable` rather than be homogenized (INV-o3-2, fail-2).
|
|
50
|
+
*/
|
|
51
|
+
unrecoverableIdentity: boolean;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The errors-only bounded LLM patcher (stage2). Everything-agnostic: the caller
|
|
55
|
+
* wires whatever provider/model it likes. Receives ONLY the current payload and
|
|
56
|
+
* the remaining errors; returns a patched payload (or the same payload if it
|
|
57
|
+
* could not help). MUST be invoked outside any held artifact-tree lock — the seam
|
|
58
|
+
* holds none and does no artifact-tree IO.
|
|
59
|
+
*/
|
|
60
|
+
export type RepairPatcher = (payload: unknown, errors: RepairValidationError[]) => Promise<unknown>;
|
|
61
|
+
/** A registered contract: one validator, one classification/coercion policy. */
|
|
62
|
+
export interface RepairContract {
|
|
63
|
+
/** Stable contract id (e.g. 'audit_results', 'implement_worker_result'). */
|
|
64
|
+
contractId: string;
|
|
65
|
+
/** The ONE canonical validator, re-run after every stage. Never forked. */
|
|
66
|
+
validate(payload: unknown): RepairValidationResult;
|
|
67
|
+
/** Deterministic OPTIONAL-only coercion + recoverable-identity backfill. */
|
|
68
|
+
coercion: RepairCoercion;
|
|
69
|
+
}
|
|
70
|
+
export type RepairStatus = 'clean' | 'coerced' | 'patched' | 'unrepairable';
|
|
71
|
+
/** A repair stage actually applied, in order. */
|
|
72
|
+
export type RepairStage = 'validate' | 'coerce' | 'llm_patch' | 'redispatch';
|
|
73
|
+
/** Re-dispatch signal surfaced when the seam exhausts cheaper stages. */
|
|
74
|
+
export interface RepairRedispatch {
|
|
75
|
+
/**
|
|
76
|
+
* The 1-based attempt counter for the NEXT dispatch. The caller feeds this to
|
|
77
|
+
* `buildResultContentDiscriminator({ source: 'redispatch', attempt })` so the
|
|
78
|
+
* re-dispatched result carries a distinct discriminator (and idempotencyKey).
|
|
79
|
+
*/
|
|
80
|
+
attempt: number;
|
|
81
|
+
}
|
|
82
|
+
/** The single result shape of the seam (OBL-...-o3-contract). */
|
|
83
|
+
export interface RepairOutcome {
|
|
84
|
+
/** The repaired payload (identity-preserving for clean/coerced/patched). */
|
|
85
|
+
repaired_payload: unknown;
|
|
86
|
+
/** Terminal status. */
|
|
87
|
+
status: RepairStatus;
|
|
88
|
+
/** Non-empty whenever status !== 'clean'. */
|
|
89
|
+
warnings: string[];
|
|
90
|
+
/** Remaining REQUIRED-field errors after the last stage (empty unless unrepairable). */
|
|
91
|
+
remaining_errors: RepairValidationError[];
|
|
92
|
+
/** Stages applied, in order. Always begins with 'validate'. */
|
|
93
|
+
stages_applied: RepairStage[];
|
|
94
|
+
/** Present only when status === 'unrepairable': the re-dispatch signal. */
|
|
95
|
+
redispatch?: RepairRedispatch;
|
|
96
|
+
}
|
|
97
|
+
/** Options for one repair run. */
|
|
98
|
+
export interface RunEmitValidateRepairOptions {
|
|
99
|
+
/** The registered contract (validator + coercion). */
|
|
100
|
+
contract: RepairContract;
|
|
101
|
+
/** The worker payload to repair. */
|
|
102
|
+
payload: unknown;
|
|
103
|
+
/** Artifacts dir for friction capture (best-effort). */
|
|
104
|
+
artifactsDir: string;
|
|
105
|
+
/** Per-run id for friction capture keying. */
|
|
106
|
+
runId: string;
|
|
107
|
+
/** Which orchestrator is calling (friction record `tool` field). */
|
|
108
|
+
tool?: FrictionCaptureArtifact['tool'];
|
|
109
|
+
/** Optional bounded LLM patcher (stage2). Omitted ⟹ stage2 is skipped. */
|
|
110
|
+
patcher?: RepairPatcher;
|
|
111
|
+
/** Max bounded LLM attempts (default 1). */
|
|
112
|
+
maxLlmAttempts?: number;
|
|
113
|
+
/**
|
|
114
|
+
* 1-based current attempt counter (default 1). The re-dispatch signal advances
|
|
115
|
+
* it by one so the next attempt carries a distinct discriminator.
|
|
116
|
+
*/
|
|
117
|
+
attempt?: number;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Run the cheapest-first monotonic emit-validate-repair pipeline over one
|
|
121
|
+
* payload. See the module header for the full stage contract.
|
|
122
|
+
*/
|
|
123
|
+
export declare function runEmitValidateRepair(opts: RunEmitValidateRepairOptions): Promise<RepairOutcome>;
|
|
124
|
+
//# sourceMappingURL=emitValidateRepair.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emitValidateRepair.d.ts","sourceRoot":"","sources":["../../../src/shared/repair/emitValidateRepair.ts"],"names":[],"mappings":"AAuDA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAExE,gFAAgF;AAChF,MAAM,WAAW,qBAAqB;IACpC,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,8BAA8B;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,iEAAiE;AACjE,MAAM,WAAW,sBAAsB;IACrC,uDAAuD;IACvD,MAAM,EAAE,qBAAqB,EAAE,CAAC;CACjC;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;;;;OAQG;IACH,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,oBAAoB,CAAC;CAChD;AAED,6CAA6C;AAC7C,MAAM,WAAW,oBAAoB;IACnC,uEAAuE;IACvE,OAAO,EAAE,OAAO,CAAC;IACjB,qDAAqD;IACrD,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,kEAAkE;IAClE,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB;;;;OAIG;IACH,qBAAqB,EAAE,OAAO,CAAC;CAChC;AAED;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GAAG,CAC1B,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,qBAAqB,EAAE,KAC5B,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtB,gFAAgF;AAChF,MAAM,WAAW,cAAc;IAC7B,4EAA4E;IAC5E,UAAU,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,sBAAsB,CAAC;IACnD,4EAA4E;IAC5E,QAAQ,EAAE,cAAc,CAAC;CAC1B;AAED,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,cAAc,CAAC;AAE5E,iDAAiD;AACjD,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,QAAQ,GAAG,WAAW,GAAG,YAAY,CAAC;AAE7E,yEAAyE;AACzE,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,iEAAiE;AACjE,MAAM,WAAW,aAAa;IAC5B,4EAA4E;IAC5E,gBAAgB,EAAE,OAAO,CAAC;IAC1B,uBAAuB;IACvB,MAAM,EAAE,YAAY,CAAC;IACrB,6CAA6C;IAC7C,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,wFAAwF;IACxF,gBAAgB,EAAE,qBAAqB,EAAE,CAAC;IAC1C,+DAA+D;IAC/D,cAAc,EAAE,WAAW,EAAE,CAAC;IAC9B,2EAA2E;IAC3E,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AAED,kCAAkC;AAClC,MAAM,WAAW,4BAA4B;IAC3C,sDAAsD;IACtD,QAAQ,EAAE,cAAc,CAAC;IACzB,oCAAoC;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,wDAAwD;IACxD,YAAY,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,IAAI,CAAC,EAAE,uBAAuB,CAAC,MAAM,CAAC,CAAC;IACvC,0EAA0E;IAC1E,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,4CAA4C;IAC5C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AA2BD;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,4BAA4B,GACjC,OAAO,CAAC,aAAa,CAAC,CAyIxB"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shared emit-validate-repair seam (O3) — the SOLE definition of the
|
|
3
|
+
* cheapest-first monotonic repair pipeline that every contract's worker result
|
|
4
|
+
* passes through before it is accepted (OBL-emit-validate-repair-seam-o3-contract).
|
|
5
|
+
*
|
|
6
|
+
* The seam is EVERYTHING-AGNOSTIC: it hardcodes no contract id, no validator, no
|
|
7
|
+
* field classification, no model, and no provider. A caller registers a
|
|
8
|
+
* {@link RepairContract} — `{ validate, classifyError, identity }` — for a
|
|
9
|
+
* contract id, then drives a payload through {@link runEmitValidateRepair}. A new
|
|
10
|
+
* contract id therefore registers a validator + classification WITHOUT editing the
|
|
11
|
+
* seam (INV-o3-3 / everything-agnostic).
|
|
12
|
+
*
|
|
13
|
+
* CHEAPEST-FIRST MONOTONIC STAGES (a stage runs only if the prior left a
|
|
14
|
+
* REQUIRED-field error; no LLM call when coercion alone yields clean):
|
|
15
|
+
*
|
|
16
|
+
* stage1 — deterministic coercion (INV-o3-1):
|
|
17
|
+
* - drops/empties OPTIONAL sub-objects ONLY (never touches a REQUIRED field);
|
|
18
|
+
* - backfills tool-owned identity that is RECOVERABLE PER ELEMENT (e.g. the
|
|
19
|
+
* coordinate is uniform across a single-element array);
|
|
20
|
+
* - a missing per-element `unit_id` (or any non-recoverable required identity)
|
|
21
|
+
* on a MULTI-element array escalates the whole payload to `unrepairable` —
|
|
22
|
+
* it is NEVER homogenized by copying a sibling's id (INV-o3-2, fail-2).
|
|
23
|
+
*
|
|
24
|
+
* stage2 — bounded ~1-attempt errors-only LLM patch (INV-o3-4):
|
|
25
|
+
* - runs ONLY if stage1 left REQUIRED-field errors and a patcher is supplied;
|
|
26
|
+
* - the patch prompt carries ONLY the remaining errors + the payload, never
|
|
27
|
+
* the whole contract — cheapest viable LLM touch;
|
|
28
|
+
* - bounded to a single attempt (the caller may set `maxLlmAttempts`, default
|
|
29
|
+
* 1); the validator re-runs after it.
|
|
30
|
+
* - The patcher MUST run OUTSIDE any held artifact-tree `withFileLock`: the
|
|
31
|
+
* seam holds no lock and performs no artifact-tree IO, so a caller that
|
|
32
|
+
* holds the lock must release it before invoking the seam (enforced by the
|
|
33
|
+
* lock-free contract of this module — it never imports the file lock).
|
|
34
|
+
*
|
|
35
|
+
* stage3 — re-dispatch signal (INV-o3-5):
|
|
36
|
+
* - if REQUIRED-field errors remain after stage2, the seam returns
|
|
37
|
+
* `status: 'unrepairable'` with `stages_applied` ending in `redispatch`,
|
|
38
|
+
* the SIGNAL the caller turns into a fresh dispatch. The re-dispatched
|
|
39
|
+
* attempt carries a DISTINCT `result_content_discriminator` (the seam
|
|
40
|
+
* surfaces the next discriminator via {@link RepairOutcome.redispatch}),
|
|
41
|
+
* so its idempotencyKey differs from the attempt it replaces.
|
|
42
|
+
*
|
|
43
|
+
* ONE VALIDATOR (INV-o3-6): the seam re-runs the SAME injected canonical
|
|
44
|
+
* `validate` after every stage — it never forks or re-implements validation.
|
|
45
|
+
*
|
|
46
|
+
* IDENTITY PRESERVATION (INV-o3-7): coercion only drops/backfills; it never
|
|
47
|
+
* rewrites the emitted tool-owned identity coordinate, so identityKey /
|
|
48
|
+
* idempotencyKey computed off the repaired payload are UNCHANGED. Only a stage3
|
|
49
|
+
* re-dispatch changes identity, and only via a distinct discriminator.
|
|
50
|
+
*
|
|
51
|
+
* FRICTION (fail-1..7): every drop, backfill, escalation, LLM patch, and repeated
|
|
52
|
+
* repair is recorded through the O1 `captureFrictionEvent` sink (best-effort,
|
|
53
|
+
* never fatal). `warnings` is non-empty whenever `status !== 'clean'`.
|
|
54
|
+
*/
|
|
55
|
+
import { captureFrictionEvent } from '../friction/captureFrictionEvent.js';
|
|
56
|
+
function requiredErrors(result) {
|
|
57
|
+
return result.errors.filter((e) => e.required);
|
|
58
|
+
}
|
|
59
|
+
/** Emit one best-effort, de-duped friction event for a repair action. */
|
|
60
|
+
async function captureRepair(opts, idSuffix, note, severity) {
|
|
61
|
+
await captureFrictionEvent(opts.artifactsDir, opts.runId, {
|
|
62
|
+
id: `repair:${opts.contract.contractId}:attempt-${opts.attempt ?? 1}:${idSuffix}`,
|
|
63
|
+
note,
|
|
64
|
+
severity,
|
|
65
|
+
category: 'trap',
|
|
66
|
+
area: opts.contract.contractId,
|
|
67
|
+
}, opts.tool ?? 'remediate-code');
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Run the cheapest-first monotonic emit-validate-repair pipeline over one
|
|
71
|
+
* payload. See the module header for the full stage contract.
|
|
72
|
+
*/
|
|
73
|
+
export async function runEmitValidateRepair(opts) {
|
|
74
|
+
const { contract } = opts;
|
|
75
|
+
const attempt = opts.attempt ?? 1;
|
|
76
|
+
const maxLlmAttempts = Math.max(0, opts.maxLlmAttempts ?? 1);
|
|
77
|
+
const stages_applied = ['validate'];
|
|
78
|
+
const warnings = [];
|
|
79
|
+
// A repeated repair (attempt > 1) is itself friction worth recording (fail-7).
|
|
80
|
+
if (attempt > 1) {
|
|
81
|
+
await captureRepair(opts, 'repeated', `Repeated repair pass (attempt ${attempt}) for ${contract.contractId}.`, 'low');
|
|
82
|
+
}
|
|
83
|
+
// --- stage0: validate as emitted. Clean ⟹ no work, identity untouched. ---
|
|
84
|
+
let payload = opts.payload;
|
|
85
|
+
let validation = contract.validate(payload);
|
|
86
|
+
if (requiredErrors(validation).length === 0 && validation.errors.length === 0) {
|
|
87
|
+
return {
|
|
88
|
+
repaired_payload: payload,
|
|
89
|
+
status: 'clean',
|
|
90
|
+
warnings,
|
|
91
|
+
remaining_errors: [],
|
|
92
|
+
stages_applied,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
// --- stage1: deterministic OPTIONAL-only coercion + recoverable backfill. ---
|
|
96
|
+
const coerced = contract.coercion.coerce(payload);
|
|
97
|
+
stages_applied.push('coerce');
|
|
98
|
+
if (coerced.unrecoverableIdentity) {
|
|
99
|
+
// Multi-element missing required identity → escalate; never homogenize.
|
|
100
|
+
await captureRepair(opts, 'unrecoverable-identity', `Unrecoverable per-element identity in ${contract.contractId}; escalating to re-dispatch rather than homogenizing.`, 'high');
|
|
101
|
+
warnings.push('Required per-element identity missing on a multi-element payload; cannot be recovered deterministically.');
|
|
102
|
+
const remaining = requiredErrors(contract.validate(coerced.payload));
|
|
103
|
+
stages_applied.push('redispatch');
|
|
104
|
+
return {
|
|
105
|
+
repaired_payload: coerced.payload,
|
|
106
|
+
status: 'unrepairable',
|
|
107
|
+
warnings,
|
|
108
|
+
remaining_errors: remaining,
|
|
109
|
+
stages_applied,
|
|
110
|
+
redispatch: { attempt: attempt + 1 },
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
payload = coerced.payload;
|
|
114
|
+
for (const drop of coerced.drops) {
|
|
115
|
+
warnings.push(`Dropped invalid OPTIONAL sub-object at ${drop}.`);
|
|
116
|
+
await captureRepair(opts, `drop:${drop}`, `Dropped invalid OPTIONAL sub-object at ${drop} in ${contract.contractId}.`, 'low');
|
|
117
|
+
}
|
|
118
|
+
for (const backfill of coerced.backfills) {
|
|
119
|
+
warnings.push(`Backfilled recoverable tool-owned identity at ${backfill}.`);
|
|
120
|
+
await captureRepair(opts, `backfill:${backfill}`, `Backfilled recoverable tool-owned identity at ${backfill} in ${contract.contractId}.`, 'info');
|
|
121
|
+
}
|
|
122
|
+
validation = contract.validate(payload);
|
|
123
|
+
let remaining = requiredErrors(validation);
|
|
124
|
+
if (remaining.length === 0) {
|
|
125
|
+
// Coercion alone cleared every REQUIRED error → NO LLM call (cheapest-first).
|
|
126
|
+
return {
|
|
127
|
+
repaired_payload: payload,
|
|
128
|
+
status: 'coerced',
|
|
129
|
+
warnings: warnings.length > 0
|
|
130
|
+
? warnings
|
|
131
|
+
: ['Payload required deterministic coercion to validate.'],
|
|
132
|
+
remaining_errors: [],
|
|
133
|
+
stages_applied,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
// --- stage2: bounded errors-only LLM patch (lock-free). ---
|
|
137
|
+
if (opts.patcher && maxLlmAttempts > 0) {
|
|
138
|
+
let llmRound = 0;
|
|
139
|
+
while (llmRound < maxLlmAttempts && remaining.length > 0) {
|
|
140
|
+
llmRound += 1;
|
|
141
|
+
stages_applied.push('llm_patch');
|
|
142
|
+
await captureRepair(opts, `llm-patch-${llmRound}`, `Bounded errors-only LLM patch (round ${llmRound}) for ${contract.contractId}.`, 'medium');
|
|
143
|
+
let patched;
|
|
144
|
+
try {
|
|
145
|
+
patched = await opts.patcher(payload, remaining);
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
// A failed patch leaves the payload as-is; fall through to re-dispatch.
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
payload = patched;
|
|
152
|
+
validation = contract.validate(payload);
|
|
153
|
+
remaining = requiredErrors(validation);
|
|
154
|
+
}
|
|
155
|
+
if (remaining.length === 0) {
|
|
156
|
+
warnings.push('Payload required a bounded LLM patch to validate.');
|
|
157
|
+
return {
|
|
158
|
+
repaired_payload: payload,
|
|
159
|
+
status: 'patched',
|
|
160
|
+
warnings,
|
|
161
|
+
remaining_errors: [],
|
|
162
|
+
stages_applied,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// --- stage3: re-dispatch signal. ---
|
|
167
|
+
stages_applied.push('redispatch');
|
|
168
|
+
warnings.push(`Repair exhausted coercion${opts.patcher ? ' and bounded LLM patch' : ''}; ${remaining.length} required error(s) remain — re-dispatch required.`);
|
|
169
|
+
await captureRepair(opts, 'redispatch', `Repair exhausted cheaper stages for ${contract.contractId}; signalling re-dispatch (next attempt ${attempt + 1}).`, 'high');
|
|
170
|
+
return {
|
|
171
|
+
repaired_payload: payload,
|
|
172
|
+
status: 'unrepairable',
|
|
173
|
+
warnings,
|
|
174
|
+
remaining_errors: remaining,
|
|
175
|
+
stages_applied,
|
|
176
|
+
redispatch: { attempt: attempt + 1 },
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=emitValidateRepair.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emitValidateRepair.js","sourceRoot":"","sources":["../../../src/shared/repair/emitValidateRepair.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `audit-tools/shared/repair` — the single-sourced emit-validate-repair seam (O3).
|
|
3
|
+
* Both orchestrators import the seam from here so the staged repair policy cannot
|
|
4
|
+
* drift between the two halves of the pipeline.
|
|
5
|
+
*/
|
|
6
|
+
export type { RepairValidationError, RepairValidationResult, RepairCoercion, RepairCoercionResult, RepairPatcher, RepairContract, RepairStatus, RepairStage, RepairRedispatch, RepairOutcome, RunEmitValidateRepairOptions, } from './emitValidateRepair.js';
|
|
7
|
+
export { runEmitValidateRepair } from './emitValidateRepair.js';
|
|
8
|
+
export type { BrokeredDispatchSlot, BrokerAdmission, BrokeredDispatchDecision, BrokeredCompletion, BrokerDispatchInput, BrokeredRepairDispatch, } from './brokeredDispatch.js';
|
|
9
|
+
export { createBrokeredRepairDispatch, estimateSlotTokens, classifyCapableHost, } from './brokeredDispatch.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shared/repair/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,YAAY,EACV,qBAAqB,EACrB,sBAAsB,EACtB,cAAc,EACd,oBAAoB,EACpB,aAAa,EACb,cAAc,EACd,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,aAAa,EACb,4BAA4B,GAC7B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAGhE,YAAY,EACV,oBAAoB,EACpB,eAAe,EACf,wBAAwB,EACxB,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,4BAA4B,EAC5B,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/shared/repair/index.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAWhE,OAAO,EACL,4BAA4B,EAC5B,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single deterministic JSON serializer for content hashing across the
|
|
3
|
+
* codebase (INV-CK-2 / content-key-seam-fail-2). Object keys are sorted, so two
|
|
4
|
+
* structurally-equal values with differently-ordered keys serialize identically.
|
|
5
|
+
* `undefined` is normalized to `null` (both top-level and inside arrays) so a
|
|
6
|
+
* present-but-undefined field can never change the hash.
|
|
7
|
+
*
|
|
8
|
+
* There must be exactly ONE such serializer — never write a second. Both the
|
|
9
|
+
* artifact-freshness metadata hash (`src/audit/orchestrator/artifactFreshness.ts`,
|
|
10
|
+
* which re-exports this) and the content-key seam (`src/shared/contentKey.ts`)
|
|
11
|
+
* route through this function.
|
|
12
|
+
*/
|
|
13
|
+
export declare function stableStringify(value: unknown): string;
|
|
14
|
+
//# sourceMappingURL=stableStringify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stableStringify.d.ts","sourceRoot":"","sources":["../../src/shared/stableStringify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CActD"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single deterministic JSON serializer for content hashing across the
|
|
3
|
+
* codebase (INV-CK-2 / content-key-seam-fail-2). Object keys are sorted, so two
|
|
4
|
+
* structurally-equal values with differently-ordered keys serialize identically.
|
|
5
|
+
* `undefined` is normalized to `null` (both top-level and inside arrays) so a
|
|
6
|
+
* present-but-undefined field can never change the hash.
|
|
7
|
+
*
|
|
8
|
+
* There must be exactly ONE such serializer — never write a second. Both the
|
|
9
|
+
* artifact-freshness metadata hash (`src/audit/orchestrator/artifactFreshness.ts`,
|
|
10
|
+
* which re-exports this) and the content-key seam (`src/shared/contentKey.ts`)
|
|
11
|
+
* route through this function.
|
|
12
|
+
*/
|
|
13
|
+
export function stableStringify(value) {
|
|
14
|
+
if (value === undefined) {
|
|
15
|
+
return "null";
|
|
16
|
+
}
|
|
17
|
+
if (value === null || typeof value !== "object") {
|
|
18
|
+
return JSON.stringify(value);
|
|
19
|
+
}
|
|
20
|
+
if (Array.isArray(value)) {
|
|
21
|
+
return `[${value.map((item) => stableStringify(item ?? null)).join(",")}]`;
|
|
22
|
+
}
|
|
23
|
+
const entries = Object.entries(value)
|
|
24
|
+
.filter(([, item]) => item !== undefined)
|
|
25
|
+
.sort(([a], [b]) => a.localeCompare(b));
|
|
26
|
+
return `{${entries.map(([key, item]) => `${JSON.stringify(key)}:${stableStringify(item)}`).join(",")}}`;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=stableStringify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stableStringify.js","sourceRoot":"","sources":["../../src/shared/stableStringify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,eAAe,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IAC7E,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC;SAC7D,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,SAAS,CAAC;SACxC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;AAC1G,CAAC"}
|
package/package.json
CHANGED
|
@@ -496,6 +496,15 @@
|
|
|
496
496
|
"submitted_at": {
|
|
497
497
|
"type": "string",
|
|
498
498
|
"format": "date-time"
|
|
499
|
+
},
|
|
500
|
+
"instance_id": {
|
|
501
|
+
"type": "string"
|
|
502
|
+
},
|
|
503
|
+
"identity_key": {
|
|
504
|
+
"type": "string"
|
|
505
|
+
},
|
|
506
|
+
"idempotency_key": {
|
|
507
|
+
"type": "string"
|
|
499
508
|
}
|
|
500
509
|
},
|
|
501
510
|
"required": [
|
|
@@ -498,6 +498,15 @@
|
|
|
498
498
|
"submitted_at": {
|
|
499
499
|
"type": "string",
|
|
500
500
|
"format": "date-time"
|
|
501
|
+
},
|
|
502
|
+
"instance_id": {
|
|
503
|
+
"type": "string"
|
|
504
|
+
},
|
|
505
|
+
"identity_key": {
|
|
506
|
+
"type": "string"
|
|
507
|
+
},
|
|
508
|
+
"idempotency_key": {
|
|
509
|
+
"type": "string"
|
|
501
510
|
}
|
|
502
511
|
},
|
|
503
512
|
"required": [
|