@lcv-ideas-software/cross-review 4.2.4 → 4.3.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.
@@ -1,5 +1,5 @@
1
1
  import type { AppConfig, PeerId } from "./types.js";
2
- export declare const VERSION = "4.2.4";
2
+ export declare const VERSION = "4.3.0";
3
3
  export declare const RELEASE_DATE = "2026-06-05";
4
4
  export declare const DEFAULT_MAX_OUTPUT_TOKENS = 20000;
5
5
  export declare function getLastFileConfigResult(): import("./file-config.js").ApplyFileConfigResult | undefined;
@@ -17,7 +17,7 @@ function expandHome(rawPath) {
17
17
  }
18
18
  return rawPath;
19
19
  }
20
- export const VERSION = "4.2.4";
20
+ export const VERSION = "4.3.0";
21
21
  export const RELEASE_DATE = "2026-06-05";
22
22
  export const DEFAULT_MAX_OUTPUT_TOKENS = 20_000;
23
23
  const COST_RATE_ENV_PREFIX = {
@@ -7,7 +7,7 @@ import { missingFinancialControlVars, RELEASE_DATE } from "./config.js";
7
7
  import { checkConvergence, isSkippableFailure } from "./convergence.js";
8
8
  import { estimateCacheSavings } from "./cost.js";
9
9
  import { assertLeadPeerNotCaller, resolveLeadPeer } from "./relator-lottery.js";
10
- import { sessionReportMarkdown } from "./reports.js";
10
+ import { sessionReportMarkdown, unresolvedEvidenceItems } from "./reports.js";
11
11
  import { SessionStore } from "./session-store.js";
12
12
  import { decisionQualityFromStatus } from "./status.js";
13
13
  import { PEERS } from "./types.js";
@@ -323,6 +323,14 @@ const FABRICATED_ASSERTION_PATTERNS = [
323
323
  { pattern: /cargo\s+test\b/g, label: "cargo_test_assertion" },
324
324
  { pattern: /npm\s+run\s+(?:build|test|typecheck)\b/g, label: "npm_run_assertion" },
325
325
  { pattern: /index\s+[a-f0-9]{6,}\.{2}[a-f0-9]{6,}/g, label: "git_diff_index_hash" },
326
+ {
327
+ pattern: /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/gi,
328
+ label: "session_id_reference",
329
+ },
330
+ {
331
+ pattern: /https:\/\/github\.com\/[^\s)\]}>"']+/gi,
332
+ label: "github_url_reference",
333
+ },
326
334
  {
327
335
  pattern: /\b(?:workflow\s+(?:launched|started|dispatched|created)|(?:launched|started|dispatched)\s+(?:a\s+)?workflow)\b/gi,
328
336
  label: "workflow_dispatch_claim",
@@ -588,7 +596,9 @@ export function truthfulnessPreflight(params) {
588
596
  const pass = contradictions.length === 0 && unsupportedClaims.length === 0;
589
597
  const detail = [...contradictions, ...unsupportedClaims].join("; ");
590
598
  const evidenceState = `attachments_present=${params.attachmentsPresent}; ` +
591
- `structured_evidence_supplied=${structuredEvidenceSupplied}`;
599
+ `structured_evidence_supplied=${structuredEvidenceSupplied}; ` +
600
+ `source_marker_found=${sourceMarkerFound}; ` +
601
+ `runtime_facts_available=${runtimeFactsAvailable}`;
592
602
  const remediation = "attach raw snapshot evidence with session_attach_evidence or pass a structured evidence field, then retry the truthfulness preflight";
593
603
  return {
594
604
  pass,
@@ -632,7 +642,7 @@ function leadShipModeDirective() {
632
642
  // relator is free to synthesize ANALYSIS (interpretation, design
633
643
  // rationale, prose) but MUST refuse to invent operational facts.
634
644
  "## Evidence Provenance Lock (HARD)",
635
- "Operational evidence — git SHAs, content hashes, build outputs, test counts (e.g. `147 passed`), diff hunks, `git diff --check passed` style assertions, vite asset filenames with hex suffixes, `cargo test`/`npm run build`/`npm run typecheck` result lines, `git rev-parse HEAD` output, timestamps, file paths — has a PROVENANCE level. Two levels exist:",
645
+ "Operational evidence — git SHAs, content hashes, build outputs, test counts (e.g. `147 passed`), diff hunks, `git diff --check passed` style assertions, vite asset filenames with hex suffixes, `cargo test`/`npm run build`/`npm run typecheck` result lines, `git rev-parse HEAD` output, session IDs, GitHub URLs, timestamps, file paths — has a PROVENANCE level. Two levels exist:",
636
646
  " - PROVENANCE-GRADE: raw command/tool output persisted via `session_attach_evidence` (visible to you below as `## Attached Evidence`), or a verbatim file slice with explicit path:line refs.",
637
647
  " - NARRATIVE: the caller's natural-language summary in the task or in a prior draft (e.g. `I ran cargo test, 147 passed`).",
638
648
  "NARRATIVE is NOT evidence. The caller's claim that a command produced a specific result is unverified until the raw output is attached. You MUST NOT quote NARRATIVE operational claims as if they were verified evidence. You MAY summarize that the caller claims X; you MUST NOT assert that X happened.",
@@ -2635,7 +2645,32 @@ export class CrossReviewOrchestrator {
2635
2645
  let updated = this.store.read(session.session_id);
2636
2646
  if (convergence.converged) {
2637
2647
  this.store.saveFinal(session.session_id, input.draft);
2638
- updated = await this.store.finalize(session.session_id, "converged", convergence.recovery_converged ? "recovered_unanimity" : "unanimous_ready");
2648
+ const unresolvedEvidence = unresolvedEvidenceItems(updated);
2649
+ const baseReason = convergence.recovery_converged ? "recovered_unanimity" : "unanimous_ready";
2650
+ const outcomeReason = unresolvedEvidence.length > 0 ? `${baseReason}_with_unresolved_evidence` : baseReason;
2651
+ if (unresolvedEvidence.length > 0) {
2652
+ this.emit({
2653
+ type: "session.evidence_checklist_unresolved_on_finalize",
2654
+ session_id: session.session_id,
2655
+ round: round.round,
2656
+ message: `${unresolvedEvidence.length} unresolved evidence item(s) remain at convergence; finalizing with explicit unresolved-evidence reason.`,
2657
+ data: {
2658
+ outcome_reason: outcomeReason,
2659
+ unresolved_count: unresolvedEvidence.length,
2660
+ open_count: unresolvedEvidence.filter((item) => (item.status ?? "open") === "open")
2661
+ .length,
2662
+ not_resurfaced_count: unresolvedEvidence.filter((item) => item.status === "not_resurfaced").length,
2663
+ items: unresolvedEvidence.slice(0, 20).map((item) => ({
2664
+ id: item.id,
2665
+ peer: item.peer,
2666
+ status: item.status ?? "open",
2667
+ ask: item.ask,
2668
+ round_count: item.round_count,
2669
+ })),
2670
+ },
2671
+ });
2672
+ }
2673
+ updated = await this.store.finalize(session.session_id, "converged", outcomeReason);
2639
2674
  }
2640
2675
  this.store.saveReport(session.session_id, sessionReportMarkdown(this.store.read(session.session_id), this.store.readEvents(session.session_id)));
2641
2676
  this.emit({