gentle-pi 2.1.2 → 2.2.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/README.md +70 -12
- package/assets/agents/gentle-ai-worker.md +7 -3
- package/assets/agents/jd-fix-agent.md +1 -1
- package/assets/agents/jd-judge-a.md +3 -1
- package/assets/agents/jd-judge-b.md +3 -1
- package/assets/agents/review-readability.md +4 -1
- package/assets/agents/review-reliability.md +4 -1
- package/assets/agents/review-resilience.md +4 -1
- package/assets/agents/review-risk.md +4 -1
- package/assets/agents/sdd-apply.md +6 -1
- package/assets/agents/sdd-archive.md +6 -1
- package/assets/agents/sdd-design.md +6 -1
- package/assets/agents/sdd-explore.md +6 -2
- package/assets/agents/sdd-init.md +10 -2
- package/assets/agents/sdd-onboard.md +6 -1
- package/assets/agents/sdd-proposal.md +6 -1
- package/assets/agents/sdd-spec.md +6 -1
- package/assets/agents/sdd-status.md +6 -1
- package/assets/agents/sdd-sync.md +6 -1
- package/assets/agents/sdd-tasks.md +6 -1
- package/assets/agents/sdd-verify.md +6 -1
- package/assets/chains/4r-review.chain.md +2 -0
- package/assets/chains/sdd-full.chain.md +1 -1
- package/assets/chains/sdd-plan.chain.md +1 -1
- package/assets/chains/sdd-verify.chain.md +1 -1
- package/assets/orchestrator-delegation.md +246 -67
- package/assets/orchestrator.md +7 -14
- package/assets/sdd-orchestrator-workflow.md +154 -9
- package/assets/support/sdd-status-contract.md +19 -1
- package/contracts/review-integration/v1/fixtures/consent.fixture.json +3 -3
- package/contracts/review-integration/v1/fixtures/start-v2.fixture.json +19 -28
- package/contracts/review-integration/v1/fixtures/start.fixture.json +1 -10
- package/contracts/review-integration/v1/fixtures/status-v2.fixture.json +12 -21
- package/contracts/review-integration/v1/schemas/correction-plan-request.schema.json +49 -0
- package/contracts/review-integration/v1/schemas/operation.schema.json +76 -0
- package/contracts/review-integration/v1/schemas/repair.schema.json +39 -0
- package/contracts/review-integration/v1/schemas/status-v2.schema.json +4 -2
- package/contracts/review-integration/v1/schemas/status.schema.json +4 -2
- package/contracts/review-integration/v2/fixtures/consent.fixture.json +1 -1
- package/contracts/review-integration/v2/fixtures/start.fixture.json +1 -10
- package/contracts/review-integration/v2/fixtures/status.fixture.json +1 -10
- package/contracts/review-integration/v2/schemas/failure.schema.json +5 -1
- package/contracts/review-integration/v2/schemas/operation.schema.json +6 -1
- package/contracts/review-integration/v2/schemas/repair.schema.json +4 -2
- package/contracts/review-integration/v2/schemas/start.schema.json +5 -2
- package/contracts/review-integration/v2/schemas/status.schema.json +4 -2
- package/contracts/review-provider-contract-mirror/provider-contract.lock.json +30 -0
- package/contracts/review-provider-contract-mirror/v1.1.0/bundle/README.md +12 -0
- package/contracts/review-provider-contract-mirror/v1.1.0/bundle/manifest.json +65 -0
- package/contracts/review-provider-contract-mirror/v1.1.0/bundle/schemas/lens.schema.json +16 -0
- package/contracts/review-provider-contract-mirror/v1.1.0/bundle/schemas/refuter.schema.json +1 -0
- package/contracts/review-provider-contract-mirror/v1.1.0/bundle/schemas/targeted-validator.schema.json +1 -0
- package/contracts/review-provider-contract-mirror/v1.1.0/bundle/vectors/lens.json +1 -0
- package/contracts/review-provider-contract-mirror/v1.1.0/bundle/vectors/refuter.json +1 -0
- package/contracts/review-provider-contract-mirror/v1.1.0/bundle/vectors/targeted-validator.json +1 -0
- package/contracts/review-provider-contract-mirror/v1.1.0/generated/provider-capabilities.baseline.json +15 -0
- package/contracts/review-provider-contract-mirror/v1.1.0/generated/provider-roles.baseline.json +42 -0
- package/docs/native-authority-architecture.md +5 -5
- package/docs/review-integration.md +22 -2
- package/extensions/gentle-ai.ts +1595 -201
- package/extensions/sdd-init.ts +19 -6
- package/extensions/skill-registry.ts +10 -2
- package/extensions/startup-banner.ts +10 -4
- package/lib/gentle-ai-binary.ts +173 -2
- package/lib/git-commit-transaction.ts +77 -17
- package/lib/native-review-cli.ts +528 -65
- package/lib/provider-contract-bundle.ts +704 -0
- package/lib/review-candidate-view.ts +527 -18
- package/lib/review-compact-contract.ts +59 -248
- package/lib/review-host-relay.ts +436 -0
- package/lib/review-integration-v2.ts +537 -36
- package/lib/review-relay-contract.ts +16 -0
- package/lib/sdd-preflight.ts +53 -1
- package/package.json +5 -2
- package/runtime/gentle-ai-binary.mjs +173 -2
- package/runtime/git-commit-transaction.mjs +75 -15
- package/runtime/native-review-cli.mjs +524 -61
- package/runtime/review-integration-v2.mjs +536 -35
- package/runtime/review-relay-contract.mjs +17 -0
- package/scripts/build-git-commit-transaction-runner.mjs +1 -0
- package/scripts/check-provider-contract.mjs +138 -0
- package/scripts/gentle-ai-installer.mjs +23 -13
- package/scripts/maintainer/provider-relay-matrix.mjs +219 -0
- package/scripts/mirror-provider-contract.mjs +143 -0
- package/scripts/test-packed-runner.mjs +16 -2
- package/scripts/verify-package-files.mjs +110 -33
- package/skills/_shared/review-ledger-contract.md +4 -6
- package/skills/gentle-ai/SKILL.md +4 -4
- package/skills/issue-creation/SKILL.md +94 -168
- package/skills/judgment-day/SKILL.md +7 -1
- package/skills/judgment-day/references/prompts-and-formats.md +2 -0
- package/skills/rdd-defect-workflow/SKILL.md +54 -0
- package/tests/background-subagents.test.ts +771 -0
- package/tests/crosslane/cross-lane.mjs +1169 -0
- package/tests/delegated-key-learnings-contract.test.ts +238 -0
- package/tests/fixtures/devbinary/capabilities-v2.1.derived.json +331 -0
- package/tests/fixtures/devbinary/capabilities-v2.2.captured.json +340 -0
- package/tests/fixtures/devbinary/consent-v3.captured.json +37 -0
- package/tests/fixtures/devbinary/failure-v2-capture-evidence.captured.json +16 -0
- package/tests/fixtures/devbinary/result-artifact-v2-path.captured.json +12 -0
- package/tests/fixtures/devbinary/result-artifact-v2.captured.json +12 -0
- package/tests/fixtures/devbinary/start-v3-consent-declined.captured.json +19 -0
- package/tests/fixtures/devbinary/start-v3-consent-granted.captured.json +109 -0
- package/tests/fixtures/devbinary/status-v5-capture-result-submission.captured.json +184 -0
- package/tests/fixtures/devbinary/status-v5-repository-context.captured.json +138 -0
- package/tests/fixtures/devbinary/status-v5.captured.json +88 -0
- package/tests/fixtures/provider-contract-bundle/v1.1.0/README.md +12 -0
- package/tests/fixtures/provider-contract-bundle/v1.1.0/manifest.json +65 -0
- package/tests/fixtures/provider-contract-bundle/v1.1.0/schemas/lens.schema.json +16 -0
- package/tests/fixtures/provider-contract-bundle/v1.1.0/schemas/refuter.schema.json +1 -0
- package/tests/fixtures/provider-contract-bundle/v1.1.0/schemas/targeted-validator.schema.json +1 -0
- package/tests/fixtures/provider-contract-bundle/v1.1.0/vectors/lens.json +1 -0
- package/tests/fixtures/provider-contract-bundle/v1.1.0/vectors/refuter.json +1 -0
- package/tests/fixtures/provider-contract-bundle/v1.1.0/vectors/targeted-validator.json +1 -0
- package/tests/gentle-ai-binary.test.ts +1 -1
- package/tests/gentle-ai-dev-binary-surfacing.test.ts +195 -0
- package/tests/gentle-ai-dev-binary.test.ts +336 -0
- package/tests/gentle-ai-installer.test.ts +46 -46
- package/tests/git-commit-transaction.test.ts +229 -1
- package/tests/maintainer/provider-relay.maintest.ts +265 -0
- package/tests/native-review-capability-contract.test.ts +48 -2
- package/tests/native-review-cli.test.ts +56 -0
- package/tests/native-review-consent.test.ts +164 -3
- package/tests/native-review-parity-runtime.test.ts +37 -0
- package/tests/native-review-parity.test.ts +218 -15
- package/tests/native-sdd-attempt-authority.test.ts +235 -0
- package/tests/orchestrator-budget.test.ts +30 -5
- package/tests/package-manifest.test.ts +98 -72
- package/tests/provider-contract-bundle.test.ts +385 -0
- package/tests/provider-contract-mirror.test.ts +206 -0
- package/tests/provider-defect-handoff.test.ts +355 -0
- package/tests/review-actor-tool-deny.test.ts +12 -13
- package/tests/review-candidate-view.test.ts +489 -9
- package/tests/review-compact-contract.test.ts +52 -119
- package/tests/review-controller-native-recovery.test.ts +643 -47
- package/tests/review-controller-native-routing.test.ts +1667 -222
- package/tests/review-controller-workspace-root.test.ts +17 -2
- package/tests/review-corrected-finalize-binding.test.ts +175 -0
- package/tests/review-dispatch-hydration-gap.test.ts +197 -0
- package/tests/review-host-relay-routing.test.ts +317 -0
- package/tests/review-host-relay.test.ts +520 -0
- package/tests/review-integration-v2-forward.test.ts +631 -0
- package/tests/review-integration-v2.test.ts +114 -0
- package/tests/review-ledger-contract.test.ts +12 -28
- package/tests/review-recovered-lineage-routing.test.ts +246 -0
- package/tests/review-relay-transport-agent.test.ts +249 -0
- package/tests/runtime-harness.mjs +242 -14
- package/tests/sdd-agent-tools.test.ts +18 -33
- package/tests/skill-collision-prefixes.test.ts +1 -0
- package/tests/skill-registry.test.ts +50 -1
- package/tests/verify-package-files.test.ts +62 -0
- package/assets/agents/review-refuter.md +0 -40
- package/assets/agents/review-validator.md +0 -23
- package/lib/native-review-remediation.ts +0 -49
- package/lib/review-compact.ts +0 -947
- package/lib/review-refuter-adapter.ts +0 -129
- package/lib/review-runtime-contract.ts +0 -68
- package/prompts/gcl.md +0 -54
- package/prompts/gis.md +0 -25
- package/prompts/gpr.md +0 -41
- package/prompts/gwr.md +0 -31
- package/tests/fixtures/native-review-cli/v2.1.2/bind-sdd.json +0 -25
- package/tests/fixtures/native-review-cli/v2.1.2/finalize.json +0 -8
- package/tests/fixtures/native-review-cli/v2.1.2/sdd-status-engram.json +0 -139
- package/tests/fixtures/native-review-cli/v2.1.2/sdd-status.json +0 -200
- package/tests/fixtures/native-review-cli/v2.1.2/start.json +0 -12
- package/tests/fixtures/native-review-cli/v2.1.2/validate-allow.json +0 -24
- package/tests/fixtures/native-review-cli/v2.1.2/validate-deny-empty-context.json +0 -20
- package/tests/fixtures/native-review-cli/v2.1.2/validate-deny.json +0 -28
- package/tests/review-compact.test.ts +0 -243
- package/tests/review-refuter-adapter.test.ts +0 -89
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
import { canonicalJsonV1, domainHashV1 } from "./review-canonical.ts";
|
|
15
|
-
import { normalizeRefuterBatch, type RefuterBatch } from "./review-refuter-adapter.ts";
|
|
1
|
+
// The reduced Pi FINALIZE input contract (gentle-pi#311 P5).
|
|
2
|
+
//
|
|
3
|
+
// Pi no longer authors or transports reviewer, refuter, or validator
|
|
4
|
+
// verdicts: lens results are admitted natively through the pi host relay,
|
|
5
|
+
// the adversarial roles execute through Go-owned pi processes via
|
|
6
|
+
// provider-rendered self-contained vectors, and the terminal FINALIZE runs
|
|
7
|
+
// the provider's own negotiated transition (captured-results discovery).
|
|
8
|
+
// What remains here are the negotiated collection ANSWERS the pinned
|
|
9
|
+
// provider still consumes from the host: the pre-edit correction forecast,
|
|
10
|
+
// the targeted validation document requested by the exact
|
|
11
|
+
// `external.run_targeted_validation` collection input, and the final
|
|
12
|
+
// verification evidence with its explicit outcome.
|
|
13
|
+
|
|
16
14
|
import { CORRECTION_OUTCOMES, type CorrectionOutcome } from "./review-correction-lifecycle.ts";
|
|
17
15
|
|
|
18
16
|
const DIGEST = /^[0-9a-f]{64}$/;
|
|
@@ -30,51 +28,46 @@ export class CompactReviewContractError extends Error {
|
|
|
30
28
|
}
|
|
31
29
|
}
|
|
32
30
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
// Relocated from the deleted lib/review-compact.ts (gentle-pi#311 P5): the
|
|
32
|
+
// only compact shapes with surviving production consumers are the targeted
|
|
33
|
+
// validation document and its component rows.
|
|
34
|
+
export interface CompactValidationCheckInput {
|
|
35
|
+
passed: boolean;
|
|
36
|
+
evidence: string[];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface CompactFollowUp {
|
|
40
|
+
finding_id: string;
|
|
41
|
+
location: string;
|
|
42
|
+
summary: string;
|
|
43
|
+
proof_refs: string[];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface CompactTargetedValidationInput {
|
|
47
|
+
request_hash: string;
|
|
48
|
+
correction_ids: string[];
|
|
49
|
+
original_criteria: CompactValidationCheckInput;
|
|
50
|
+
correction_regression: CompactValidationCheckInput;
|
|
51
|
+
fix_caused_findings?: unknown[];
|
|
52
|
+
follow_ups: CompactFollowUp[];
|
|
38
53
|
}
|
|
39
54
|
|
|
40
55
|
export interface CompactFinalizeContractInput {
|
|
41
56
|
cwd: string;
|
|
42
57
|
lineageId?: string;
|
|
43
|
-
review_result?: CompactReviewResultInput;
|
|
44
58
|
correction_line_forecast?: number;
|
|
45
|
-
validation_proof?: CompactValidationProofInput;
|
|
46
59
|
validation?: CompactTargetedValidationInput;
|
|
47
60
|
final_evidence?: string;
|
|
48
61
|
final_verification_passed?: boolean;
|
|
49
62
|
final_verification_outcome?: CorrectionOutcome;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
export interface NativeRefuterRequest {
|
|
60
|
-
request_hash: string;
|
|
61
|
-
findings: CompactFinding[];
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export interface NativeValidationRequestInput {
|
|
65
|
-
lineageId: string;
|
|
66
|
-
candidateTree: string;
|
|
67
|
-
state: unknown;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export interface NativeValidationRequest {
|
|
71
|
-
request_hash: string;
|
|
72
|
-
lineage_id: string;
|
|
73
|
-
blocking_finding_ids: string[];
|
|
74
|
-
fix_finding_ids: string[];
|
|
75
|
-
correction_candidate_tree: string;
|
|
76
|
-
correction_identity: string;
|
|
77
|
-
validation_criteria: readonly string[];
|
|
63
|
+
/**
|
|
64
|
+
* Explicit acknowledgement that this FINALIZE may spend real model tokens:
|
|
65
|
+
* a provider host-relay slot runs one locked-down `pi` reviewer subprocess
|
|
66
|
+
* per outstanding lens. Absent, FINALIZE forecasts the run and spends
|
|
67
|
+
* nothing. Same shape as the existing `committedOnly` acknowledgement — the
|
|
68
|
+
* caller states the consequence it accepts.
|
|
69
|
+
*/
|
|
70
|
+
reviewer_run_acknowledged?: boolean;
|
|
78
71
|
}
|
|
79
72
|
|
|
80
73
|
function fail(area: string, code: string, message: string): never {
|
|
@@ -112,70 +105,12 @@ function strings(value: unknown, area: string): string[] {
|
|
|
112
105
|
return parsed;
|
|
113
106
|
}
|
|
114
107
|
|
|
115
|
-
function enumValue<T extends Record<string, string>>(value: unknown, values: T, area: string): T[keyof T] {
|
|
116
|
-
const parsed = string(value, area);
|
|
117
|
-
if (!Object.values(values).includes(parsed)) return fail(area, "enum", "contains an unsupported value");
|
|
118
|
-
return parsed as T[keyof T];
|
|
119
|
-
}
|
|
120
|
-
|
|
121
108
|
function optionalLineage(value: unknown, area: string): string | undefined {
|
|
122
109
|
const parsed = optionalString(value, area);
|
|
123
110
|
if (parsed !== undefined && !LINEAGE_ID.test(parsed)) fail(area, "lineage", "is malformed");
|
|
124
111
|
return parsed;
|
|
125
112
|
}
|
|
126
113
|
|
|
127
|
-
function parseFinding(value: unknown, area: string) {
|
|
128
|
-
const row = exact(value, area, ["location", "severity", "claim", "proof_refs"], ["id", "lens", "evidence_class", "causal_disposition"]);
|
|
129
|
-
const severity = enumValue(row.severity, COMPACT_SEVERITY, `${area}.severity`);
|
|
130
|
-
const severe = severity === COMPACT_SEVERITY.BLOCKER || severity === COMPACT_SEVERITY.CRITICAL;
|
|
131
|
-
if (severe && (row.evidence_class === undefined || row.causal_disposition === undefined)) fail(area, "required", "severe findings require evidence_class and causal_disposition");
|
|
132
|
-
return {
|
|
133
|
-
...(row.id === undefined ? {} : { id: string(row.id, `${area}.id`) }),
|
|
134
|
-
...(row.lens === undefined ? {} : { lens: enumValue(row.lens, REVIEW_LENS, `${area}.lens`) }),
|
|
135
|
-
location: string(row.location, `${area}.location`),
|
|
136
|
-
severity,
|
|
137
|
-
claim: string(row.claim, `${area}.claim`),
|
|
138
|
-
...(row.evidence_class === undefined ? {} : { evidence_class: enumValue(row.evidence_class, COMPACT_EVIDENCE_CLASS, `${area}.evidence_class`) }),
|
|
139
|
-
...(row.causal_disposition === undefined ? {} : { causal_disposition: enumValue(row.causal_disposition, CAUSAL_DISPOSITION, `${area}.causal_disposition`) }),
|
|
140
|
-
proof_refs: strings(row.proof_refs, `${area}.proof_refs`),
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function parseReviewResult(value: unknown, area: string): CompactReviewResultInput {
|
|
145
|
-
const input = exact(value, area, ["lens_results"], ["refuter_request_hash", "refuter_results"]);
|
|
146
|
-
if (!Array.isArray(input.lens_results)) fail(`${area}.lens_results`, "type", "must be an array");
|
|
147
|
-
const lens_results = input.lens_results.map((item, index) => {
|
|
148
|
-
const row = exact(item, `${area}.lens_results[${index}]`, ["findings", "evidence"], ["lens"]);
|
|
149
|
-
if (!Array.isArray(row.findings)) fail(`${area}.lens_results[${index}].findings`, "type", "must be an array");
|
|
150
|
-
return {
|
|
151
|
-
...(row.lens === undefined ? {} : { lens: enumValue(row.lens, REVIEW_LENS, `${area}.lens_results[${index}].lens`) }),
|
|
152
|
-
findings: row.findings.map((finding, findingIndex) => parseFinding(finding, `${area}.lens_results[${index}].findings[${findingIndex}]`)),
|
|
153
|
-
evidence: strings(row.evidence, `${area}.lens_results[${index}].evidence`),
|
|
154
|
-
};
|
|
155
|
-
});
|
|
156
|
-
const refuter_request_hash = optionalString(input.refuter_request_hash, `${area}.refuter_request_hash`);
|
|
157
|
-
if (refuter_request_hash !== undefined && !DIGEST.test(refuter_request_hash)) fail(`${area}.refuter_request_hash`, "digest", "is malformed");
|
|
158
|
-
let refuter_results: CompactRefuterResultInput[] | undefined;
|
|
159
|
-
if (input.refuter_results !== undefined) {
|
|
160
|
-
if (!Array.isArray(input.refuter_results)) fail(`${area}.refuter_results`, "type", "must be an array");
|
|
161
|
-
refuter_results = input.refuter_results.map((item, index) => {
|
|
162
|
-
const row = exact(item, `${area}.refuter_results[${index}]`, ["finding_id", "outcome", "proof_refs"]);
|
|
163
|
-
return { finding_id: string(row.finding_id, `${area}.refuter_results[${index}].finding_id`), outcome: enumValue(row.outcome, COMPACT_FINDING_OUTCOME, `${area}.refuter_results[${index}].outcome`), proof_refs: strings(row.proof_refs, `${area}.refuter_results[${index}].proof_refs`) };
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
return { lens_results, ...(refuter_request_hash === undefined ? {} : { refuter_request_hash }), ...(refuter_results === undefined ? {} : { refuter_results }) };
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function parseValidationProof(value: unknown, area: string): CompactValidationProofInput {
|
|
170
|
-
const input = exact(value, area, ["original_criteria", "correction_regression"]);
|
|
171
|
-
const check = (item: unknown, label: string) => {
|
|
172
|
-
const row = exact(item, label, ["passed", "evidence"]);
|
|
173
|
-
if (typeof row.passed !== "boolean") fail(`${label}.passed`, "type", "must be boolean");
|
|
174
|
-
return { passed: row.passed, evidence: strings(row.evidence, `${label}.evidence`) };
|
|
175
|
-
};
|
|
176
|
-
return { original_criteria: check(input.original_criteria, `${area}.original_criteria`), correction_regression: check(input.correction_regression, `${area}.correction_regression`) };
|
|
177
|
-
}
|
|
178
|
-
|
|
179
114
|
function parseValidation(value: unknown, area: string): CompactTargetedValidationInput {
|
|
180
115
|
const input = exact(value, area, ["request_hash", "correction_ids", "original_criteria", "correction_regression", "fix_caused_findings", "follow_ups"]);
|
|
181
116
|
const check = (item: unknown, label: string) => {
|
|
@@ -194,78 +129,9 @@ function parseValidation(value: unknown, area: string): CompactTargetedValidatio
|
|
|
194
129
|
return { request_hash, correction_ids: strings(input.correction_ids, `${area}.correction_ids`), original_criteria: check(input.original_criteria, `${area}.original_criteria`), correction_regression: check(input.correction_regression, `${area}.correction_regression`), fix_caused_findings: [], follow_ups };
|
|
195
130
|
}
|
|
196
131
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
CAUSAL_DISPOSITION.WORSENED,
|
|
201
|
-
]);
|
|
202
|
-
|
|
203
|
-
export function deriveNativeRefuterRequest(input: NativeRefuterRequestInput): NativeRefuterRequest | undefined {
|
|
204
|
-
const lens_results = input.reviewResult.lens_results.map((result, index) => ({
|
|
205
|
-
lens: result.lens ?? `lens-${index}`,
|
|
206
|
-
findings: result.findings.map((finding) => ({ ...finding, proof_refs: [...finding.proof_refs].toSorted() })).toSorted((left, right) => (left.id ?? "").localeCompare(right.id ?? "")),
|
|
207
|
-
evidence: [...result.evidence].toSorted(),
|
|
208
|
-
})).toSorted((left, right) => left.lens.localeCompare(right.lens));
|
|
209
|
-
const findings = lens_results.flatMap(({ findings }) => findings).filter((finding) =>
|
|
210
|
-
(finding.severity === COMPACT_SEVERITY.BLOCKER || finding.severity === COMPACT_SEVERITY.CRITICAL) &&
|
|
211
|
-
finding.evidence_class === COMPACT_EVIDENCE_CLASS.INFERENTIAL &&
|
|
212
|
-
CANDIDATE_CAUSAL_DISPOSITIONS.has(finding.causal_disposition ?? ""),
|
|
213
|
-
);
|
|
214
|
-
if (findings.some((finding) => finding.id === undefined || finding.lens === undefined)) fail("review/finalize.review_result", "finding-id", "inferential severe findings require stable IDs and lenses for refuter derivation");
|
|
215
|
-
if (findings.length === 0) return undefined;
|
|
216
|
-
if (input.candidateTree === undefined) fail("review/finalize", "candidate-tree", "requires a frozen candidate tree for refuter derivation");
|
|
217
|
-
return {
|
|
218
|
-
request_hash: domainHashV1("compact-refuter-request", {
|
|
219
|
-
lineage_id: input.lineageId,
|
|
220
|
-
candidate_tree: input.candidateTree,
|
|
221
|
-
lens_results,
|
|
222
|
-
finding_ids: findings.map(({ id }) => id),
|
|
223
|
-
}),
|
|
224
|
-
findings: findings as CompactFinding[],
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
export function deriveNativeValidationRequest(input: NativeValidationRequestInput): NativeValidationRequest {
|
|
229
|
-
const state = record(input.state, "review/finalize.validation-request");
|
|
230
|
-
if (string(state.lineage_id, "review/finalize.validation-request.lineage_id") !== input.lineageId || state.state !== "correction_required") fail("review/finalize.validation-request", "state", "requires the authoritative correction-required lineage");
|
|
231
|
-
const initial = record(state.initial_snapshot, "review/finalize.validation-request.initial_snapshot");
|
|
232
|
-
const initialCandidateTree = string(initial.candidate_tree, "review/finalize.validation-request.initial_snapshot.candidate_tree");
|
|
233
|
-
const fix_finding_ids = strings(state.fix_finding_ids, "review/finalize.validation-request.fix_finding_ids");
|
|
234
|
-
if (!Array.isArray(state.findings)) fail("review/finalize.validation-request.findings", "type", "must be an array");
|
|
235
|
-
const outcomes = state.outcomes === undefined ? undefined : record(state.outcomes, "review/finalize.validation-request.outcomes");
|
|
236
|
-
const blocking_finding_ids = state.findings.flatMap((finding, index) => {
|
|
237
|
-
const row = record(finding, `review/finalize.validation-request.findings[${index}]`);
|
|
238
|
-
if (row.severity !== COMPACT_SEVERITY.BLOCKER && row.severity !== COMPACT_SEVERITY.CRITICAL) return [];
|
|
239
|
-
const id = string(row.id, `review/finalize.validation-request.findings[${index}].id`);
|
|
240
|
-
// Mirror native FINALIZE semantics (#171): only corroborated severe findings
|
|
241
|
-
// block correction validation. Severe findings classified pre-existing or
|
|
242
|
-
// base-only carry the non-blocking `info` outcome, are routed to follow-ups,
|
|
243
|
-
// and must stay inert in the targeted-validation request.
|
|
244
|
-
if (outcomes === undefined) return [id];
|
|
245
|
-
const outcome = outcomes[id] === undefined ? undefined : enumValue(outcomes[id], COMPACT_FINDING_OUTCOME, `review/finalize.validation-request.outcomes.${id}`);
|
|
246
|
-
return outcome === COMPACT_FINDING_OUTCOME.CORROBORATED ? [id] : [];
|
|
247
|
-
});
|
|
248
|
-
if (canonicalJsonV1(fix_finding_ids.toSorted()) !== canonicalJsonV1(blocking_finding_ids.toSorted())) fail("review/finalize.validation-request", "finding-ids", "fix IDs must exactly match frozen blocking findings");
|
|
249
|
-
const correction_identity = domainHashV1("compact-correction-identity", { initial_candidate_tree: initialCandidateTree, correction_candidate_tree: input.candidateTree });
|
|
250
|
-
const validation_criteria = ["original_criteria", "correction_regression", "follow_ups"] as const;
|
|
251
|
-
return { lineage_id: input.lineageId, blocking_finding_ids, fix_finding_ids, correction_candidate_tree: input.candidateTree, correction_identity, validation_criteria, request_hash: domainHashV1("compact-validation-request", { lineage_id: input.lineageId, blocking_finding_ids, fix_finding_ids, correction_identity, validation_criteria }) };
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
export function parseCompactStartInput(value: unknown): CompactStartContractInput {
|
|
255
|
-
const input = exact(value, "review/start", ["cwd", "policyHash"], ["lineageId", "projection"]);
|
|
256
|
-
const policyHash = string(input.policyHash, "review/start.policyHash");
|
|
257
|
-
if (!DIGEST.test(policyHash)) fail("review/start.policyHash", "digest", "is malformed");
|
|
258
|
-
let projection: { kind: "complete" } | undefined;
|
|
259
|
-
if (input.projection !== undefined) {
|
|
260
|
-
const raw = exact(input.projection, "review/start.projection", ["kind"]);
|
|
261
|
-
if (raw.kind !== "complete") fail("review/start.projection.kind", "enum", "must be complete");
|
|
262
|
-
projection = { kind: "complete" };
|
|
263
|
-
}
|
|
264
|
-
return { cwd: string(input.cwd, "review/start.cwd"), ...(optionalLineage(input.lineageId, "review/start.lineageId") === undefined ? {} : { lineageId: optionalLineage(input.lineageId, "review/start.lineageId")! }), policyHash, ...(projection === undefined ? {} : { projection }) };
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
function parseCompactFinalizeInputValue(value: unknown, preserveFinalEvidence: boolean): CompactFinalizeContractInput {
|
|
268
|
-
const input = exact(value, "review/finalize", ["cwd"], ["lineageId", "review_result", "correction_line_forecast", "validation_proof", "validation", "final_evidence", "final_verification_passed", "final_verification_outcome", "refuter_batch"]);
|
|
132
|
+
function parseCompactFinalizeInputValue(value: unknown): CompactFinalizeContractInput {
|
|
133
|
+
const input = exact(value, "review/finalize", ["cwd"], ["lineageId", "correction_line_forecast", "validation", "final_evidence", "final_verification_passed", "final_verification_outcome", "reviewer_run_acknowledged"]);
|
|
134
|
+
if (input.reviewer_run_acknowledged !== undefined && typeof input.reviewer_run_acknowledged !== "boolean") fail("review/finalize.reviewer_run_acknowledged", "type", "must be boolean");
|
|
269
135
|
const outcomeFields = Number(input.final_verification_passed !== undefined) + Number(input.final_verification_outcome !== undefined);
|
|
270
136
|
if ((input.final_evidence === undefined && outcomeFields !== 0) || (input.final_evidence !== undefined && outcomeFields !== 1)) fail("review/finalize", "field-pair", "final evidence requires exactly one verification result or outcome");
|
|
271
137
|
let correction_line_forecast: number | undefined;
|
|
@@ -282,83 +148,28 @@ function parseCompactFinalizeInputValue(value: unknown, preserveFinalEvidence: b
|
|
|
282
148
|
}
|
|
283
149
|
let final_evidence: string | undefined;
|
|
284
150
|
if (input.final_evidence !== undefined) {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
}
|
|
151
|
+
// Final evidence is preserved BYTE-FOR-BYTE: it is staged into the native
|
|
152
|
+
// --evidence file untouched, so the canonical trimmed-string rule does
|
|
153
|
+
// not apply — only zero-length evidence is refused.
|
|
154
|
+
if (typeof input.final_evidence !== "string" || input.final_evidence.length === 0) fail("review/finalize.final_evidence", "empty", "must contain at least one byte");
|
|
155
|
+
final_evidence = input.final_evidence;
|
|
291
156
|
}
|
|
292
|
-
return { cwd: string(input.cwd, "review/finalize.cwd"), ...(optionalLineage(input.lineageId, "review/finalize.lineageId") === undefined ? {} : { lineageId: optionalLineage(input.lineageId, "review/finalize.lineageId")! }), ...(
|
|
157
|
+
return { cwd: string(input.cwd, "review/finalize.cwd"), ...(optionalLineage(input.lineageId, "review/finalize.lineageId") === undefined ? {} : { lineageId: optionalLineage(input.lineageId, "review/finalize.lineageId")! }), ...(correction_line_forecast === undefined ? {} : { correction_line_forecast }), ...(input.validation === undefined ? {} : { validation: parseValidation(input.validation, "review/finalize.validation") }), ...(final_evidence === undefined ? {} : { final_evidence }), ...(input.final_verification_passed === undefined ? {} : { final_verification_passed: input.final_verification_passed }), ...(final_verification_outcome === undefined ? {} : { final_verification_outcome }), ...(input.reviewer_run_acknowledged === undefined ? {} : { reviewer_run_acknowledged: input.reviewer_run_acknowledged as boolean }) };
|
|
293
158
|
}
|
|
294
159
|
|
|
295
|
-
export function
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
export function parseNativeCompactFinalizeInput(value: unknown): CompactFinalizeContractInput & { refuter_batch?: RefuterBatch } {
|
|
300
|
-
const input = parseCompactFinalizeInputValue(value, true);
|
|
301
|
-
for (const lens of input.review_result?.lens_results ?? []) {
|
|
302
|
-
if (lens.evidence.length === 0 || lens.findings.some((finding) => finding.proof_refs?.length === 0)) fail("review/finalize.review_result", "empty", "reviewer evidence and proof_refs must be non-empty");
|
|
303
|
-
if (lens.findings.some((finding) => finding.evidence_class === COMPACT_EVIDENCE_CLASS.INFO)) fail("review/finalize.review_result", "enum", "reviewer evidence_class must match the published native schema");
|
|
304
|
-
}
|
|
305
|
-
for (const validation of [input.validation_proof, input.validation]) {
|
|
306
|
-
if (validation && (validation.original_criteria.evidence.length === 0 || validation.correction_regression.evidence.length === 0)) fail("review/finalize.validation", "empty", "validator evidence must be non-empty");
|
|
160
|
+
export function parseNativeCompactFinalizeInput(value: unknown): CompactFinalizeContractInput {
|
|
161
|
+
const input = parseCompactFinalizeInputValue(value);
|
|
162
|
+
if (input.validation && (input.validation.original_criteria.evidence.length === 0 || input.validation.correction_regression.evidence.length === 0)) {
|
|
163
|
+
fail("review/finalize.validation", "empty", "validator evidence must be non-empty");
|
|
307
164
|
}
|
|
308
165
|
if (input.validation?.follow_ups.some((row) => row.proof_refs.length === 0)) fail("review/finalize.validation.follow_ups", "empty", "follow-up proof_refs must be non-empty");
|
|
309
|
-
|
|
310
|
-
if (input.refuter_batch !== undefined) {
|
|
311
|
-
const reviewResult = input.review_result;
|
|
312
|
-
if (reviewResult?.refuter_request_hash === undefined) fail("review/finalize.refuter_batch", "request-hash", "requires the expected review_result.refuter_request_hash");
|
|
313
|
-
const candidateCausality = new Set<string>([CAUSAL_DISPOSITION.INTRODUCED, CAUSAL_DISPOSITION.BEHAVIOR_ACTIVATED, CAUSAL_DISPOSITION.WORSENED]);
|
|
314
|
-
const findings: CompactFinding[] = [];
|
|
315
|
-
for (const lens of reviewResult.lens_results) {
|
|
316
|
-
for (const finding of lens.findings) {
|
|
317
|
-
if ((finding.severity !== COMPACT_SEVERITY.BLOCKER && finding.severity !== COMPACT_SEVERITY.CRITICAL) || finding.evidence_class !== COMPACT_EVIDENCE_CLASS.INFERENTIAL || !candidateCausality.has(finding.causal_disposition ?? "")) continue;
|
|
318
|
-
if (finding.id === undefined || (finding.lens ?? lens.lens) === undefined) fail("review/finalize.refuter_batch", "finding-id", "requires stable IDs and lenses for every refuted finding");
|
|
319
|
-
findings.push({
|
|
320
|
-
id: finding.id,
|
|
321
|
-
lens: (finding.lens ?? lens.lens)!,
|
|
322
|
-
location: finding.location!,
|
|
323
|
-
severity: finding.severity,
|
|
324
|
-
claim: finding.claim!,
|
|
325
|
-
evidence_class: finding.evidence_class,
|
|
326
|
-
causal_disposition: finding.causal_disposition!,
|
|
327
|
-
proof_refs: [...finding.proof_refs!],
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
const normalized = normalizeRefuterBatch({ request_hash: reviewResult.refuter_request_hash, findings }, input.refuter_batch);
|
|
332
|
-
if (normalized.status !== "normalized") fail("review/finalize.refuter_batch", normalized.reason_code, "must match the frozen request hash and IDs with complete concrete proof rows");
|
|
333
|
-
refuter_batch = {
|
|
334
|
-
schema: "gentle-ai.refuter-result-batch/v1",
|
|
335
|
-
request_hash: normalized.refuter_request_hash,
|
|
336
|
-
results: normalized.refuter_results,
|
|
337
|
-
};
|
|
338
|
-
}
|
|
339
|
-
return { ...input, ...(refuter_batch === undefined ? {} : { refuter_batch }) };
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
const NATIVE_REVIEWER_LENS = {
|
|
343
|
-
[REVIEW_LENS.RISK]: "risk",
|
|
344
|
-
[REVIEW_LENS.RESILIENCE]: "resilience",
|
|
345
|
-
[REVIEW_LENS.READABILITY]: "readability",
|
|
346
|
-
[REVIEW_LENS.RELIABILITY]: "reliability",
|
|
347
|
-
} as const;
|
|
348
|
-
|
|
349
|
-
export function toNativeReviewerDocument(input: CompactLensResultInput) {
|
|
350
|
-
const lens = input.lens === undefined ? undefined : NATIVE_REVIEWER_LENS[input.lens as keyof typeof NATIVE_REVIEWER_LENS];
|
|
351
|
-
return {
|
|
352
|
-
...(lens === undefined ? {} : { lens }),
|
|
353
|
-
findings: input.findings.map((finding) => ({ ...finding, ...(finding.lens === undefined ? {} : { lens: NATIVE_REVIEWER_LENS[finding.lens as keyof typeof NATIVE_REVIEWER_LENS] }) })),
|
|
354
|
-
evidence: [...input.evidence],
|
|
355
|
-
};
|
|
166
|
+
return input;
|
|
356
167
|
}
|
|
357
168
|
|
|
358
|
-
export function toNativeValidatorDocument(input:
|
|
169
|
+
export function toNativeValidatorDocument(input: CompactTargetedValidationInput) {
|
|
359
170
|
return {
|
|
360
171
|
original_criteria: input.original_criteria,
|
|
361
172
|
correction_regression: input.correction_regression,
|
|
362
|
-
follow_ups:
|
|
173
|
+
follow_ups: input.follow_ups.map((row) => ({ observation: row.summary, proof_refs: [...row.proof_refs] })),
|
|
363
174
|
};
|
|
364
175
|
}
|