Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions apps/loopover-ui/src/lib/ams-env-reference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ export const AMS_ENV_REFERENCE_ROWS: MinerEnvReferenceRow[] = [
firstReference: "lib/event-ledger.js",
defaultValue: null,
},
{
name: "LOOPOVER_MINER_FULL_EXECUTION_STUB",
firstReference: "lib/cross-repo-evaluation.js",
defaultValue: "",
},
{
name: "LOOPOVER_MINER_GOVERNOR_LEDGER_DB",
firstReference: "lib/governor-ledger.js",
Expand Down Expand Up @@ -232,6 +237,7 @@ export const AMS_ENV_REFERENCE_MARKDOWN = [
'| `LOOPOVER_MINER_DISCOVERY_SHARED_SECRET` | `lib/discovery-index-client.js` | `""` |',
'| `LOOPOVER_MINER_DISCOVERY_TELEMETRY` | `lib/discovery-index-client.js` | `""` |',
"| `LOOPOVER_MINER_EVENT_LEDGER_DB` | `lib/event-ledger.js` | (none) |",
'| `LOOPOVER_MINER_FULL_EXECUTION_STUB` | `lib/cross-repo-evaluation.js` | `""` |',
"| `LOOPOVER_MINER_GOVERNOR_LEDGER_DB` | `lib/governor-ledger.js` | (none) |",
"| `LOOPOVER_MINER_GOVERNOR_STATE_DB` | `lib/governor-state.js` | (none) |",
'| `LOOPOVER_MINER_LOG_LEVEL` | `lib/logger.js` | `""` |',
Expand Down
1 change: 1 addition & 0 deletions packages/loopover-miner/DEPLOYMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ and `LOOPOVER_MINER_CONFIG_DIR` are covered above under the fleet/state notes; t
| `LOOPOVER_MINER_AMS_POLICY_PATH` | `lib/ams-policy.js` | Path to the operator's `.loopover-ams.yml` policy spec. |
| `LOOPOVER_MINER_AMS_COLLECTOR_URL`, `LOOPOVER_MINER_AMS_COLLECTOR_TOKEN` | `lib/orb-export.js` | Endpoint + bearer for pushing fleet state to an AMS/Orb collector. |
| `LOOPOVER_MINER_CHAT_ACTIONS` | `lib/chat-action-dispatch.js` | Truthy string enables the chat-action-dispatch flag (off by default). |
| `LOOPOVER_MINER_FULL_EXECUTION_STUB` | `lib/cross-repo-evaluation.js` | Truthy string enables a synthetic one-file handoff for local full-execution demos (off by default; never invents a live coding-agent run or forge PR). |
| `LOOPOVER_MINER_LEDGER_RETENTION_DAYS`, `LOOPOVER_MINER_LEDGER_RETENTION_MAX_ROWS` | `lib/store-maintenance.js` | Opt-in ledger retention window / row cap. |
| `LOOPOVER_MINER_LOG_LEVEL` | `lib/logger.js` | Log verbosity override. |
| `LOOPOVER_MINER_NO_UPDATE_CHECK` | `lib/update-check.js` | Truthy string disables the background update check. |
Expand Down
8 changes: 5 additions & 3 deletions packages/loopover-miner/benchmarks/cross-repo/manifest.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"description": "Cross-repo evaluation benchmark set (#4788). Diverse public repos exercised by `node packages/loopover-miner/scripts/cross-repo-evaluation.mjs` after cloning into LOOPOVER_MINER_REPO_CLONE_DIR.",
"description": "Cross-repo evaluation benchmark set (#4788 readiness / #7634 full-execution). Diverse public repos exercised by `node packages/loopover-miner/scripts/cross-repo-evaluation.mjs` after cloning into LOOPOVER_MINER_REPO_CLONE_DIR. Entries with fullExecution=true are the default --full-execution subset (dry-run: no forge PR writes).",
"repos": [
{
"repoFullName": "sindresorhus/is",
Expand All @@ -8,7 +8,8 @@
{
"repoFullName": "expressjs/express",
"stackHint": "nodejs",
"requireTestCommand": true
"requireTestCommand": true,
"fullExecution": true
},
{
"repoFullName": "pallets/flask",
Expand All @@ -28,7 +29,8 @@
{
"repoFullName": "lodash/lodash",
"stackHint": "nodejs",
"requireTestCommand": true
"requireTestCommand": true,
"fullExecution": true
}
]
}
33 changes: 30 additions & 3 deletions packages/loopover-miner/docs/cross-repo-evaluation.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ Each benchmark repo receives a **pass/fail** line. Failures are categorized:
| `loopover_assumption` | Agent instructions leak loopover-specific CI assumptions |
| `clone_setup` | The repo has not been cloned to the expected cache path |
| `other` | Unexpected errors |
| `plan_formed_compile_failed` | Full-execution: local build/compile failed after a coding handoff (#7634) |
| `compiled_tests_failed` | Full-execution: build ok but the repo's own test command failed (#7634) |
| `tests_passed_noop_diff` | Full-execution: build+tests ok but the coding attempt changed no files (#7634) |
| `execution_abandon` | Full-execution: coding attempt abandoned before handoff (#7634) |

The run also reports whether a **strict majority** of repos passed and how many succeeded **without** a per-target
`.loopover-miner.yml` (the default goal spec is acceptable).
Expand All @@ -33,6 +37,8 @@ bare `"owner/repo"` string or an object:
- **`stackHint`** — documentation only (not used by the evaluator)
- **`requireTestCommand`** — when `true`, stack detection must infer a test command or the repo fails with
`execution_gap`
- **`fullExecution`** — when `true`, include this repo in the default `--full-execution` subset (#7634). At least two
shipped entries are tagged; if fewer than two are tagged, the harness falls back to all `requireTestCommand` entries.

Malformed manifest fields degrade to documented defaults with warnings (same tolerant-parser convention as the
fleet run-manifest).
Expand Down Expand Up @@ -60,19 +66,40 @@ fleet run-manifest).
- `--repo owner/repo` — evaluate a single manifest entry
- `--manifest path/to/manifest.json` — alternate benchmark set (e.g. a fixture manifest in tests)
- `--require-majority` — exit `1` unless a strict majority of repos pass (for CI-style gating)
- `--full-execution` — after readiness, run local discover→plan→code→build→test (**no forge PR writes**, #7634)

## Full-execution mode (#7634)

`--full-execution` extends readiness with a **local-only** code→build→test loop against the tagged benchmark subset
(or `--repo` for a single entry). It never opens a GitHub/GitLab PR and never calls forge write APIs against the
benchmark repos.

1. Run the same readiness checks as the default mode
2. Invoke an injectable `runCodingAttempt` seam (discover→plan→code) that must return `handoff` + `changedFiles`
3. Run the detected `buildCommand` (when present) and `testCommand` locally via `runShellCommand`
4. Fail with execution-specific categories when compile fails, tests fail, the diff is empty, or the attempt abandons

**Default coding seam:** without an injected `runCodingAttempt`, the harness abandons with `execution_abandon`
unless `LOOPOVER_MINER_FULL_EXECUTION_STUB=1` is set (synthetic one-file handoff for local demos). Real agent wiring
stays opt-in so CI and unit tests stay offline and forge-write-free.

## Library API

Pure functions live in [`lib/cross-repo-evaluation.js`](../lib/cross-repo-evaluation.js):

- `parseCrossRepoEvaluationManifest(content)`
- `evaluateRepoReadiness(entry, options)` — inject `existsSync`, `detectRepoStack`, etc. for unit tests
- `runCrossRepoEvaluation(parsed, options)`
- `evaluateRepoFullExecution(entry, options)` — readiness + local code→build→test; inject `runCodingAttempt` /
`runShellCommand` (#7634)
- `runCrossRepoEvaluation(parsed, options)` — async; pass `fullExecution: true` for the execution path
- `summarizeCrossRepoEvaluation(results)`
- `formatCrossRepoEvaluationReport(results, summary)`

## Wiring

This harness is **readiness-only**: it does not run the coding agent, open PRs, or call forge APIs. A green report
means the miner’s repo-agnostic stack-detection and coding-task-spec path is prepared for the benchmark repo; a live
**Readiness mode** does not run the coding agent, open PRs, or call forge APIs. A green report means the miner’s
repo-agnostic stack-detection and coding-task-spec path is prepared for the benchmark repo.

**Full-execution mode** still does not open PRs or call forge write APIs. A green report means a local coding
handoff produced a non-empty diff that survived the target repo’s own build and test commands. A live production
attempt still needs credentials, governor policy, and queue state as documented in [`DEPLOYMENT.md`](../DEPLOYMENT.md).
1 change: 1 addition & 0 deletions packages/loopover-miner/docs/env-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Generated by `npm run miner:env-reference`. Do not edit manually.
| `LOOPOVER_MINER_DISCOVERY_SHARED_SECRET` | `lib/discovery-index-client.js` | `""` |
| `LOOPOVER_MINER_DISCOVERY_TELEMETRY` | `lib/discovery-index-client.js` | `""` |
| `LOOPOVER_MINER_EVENT_LEDGER_DB` | `lib/event-ledger.js` | (none) |
| `LOOPOVER_MINER_FULL_EXECUTION_STUB` | `lib/cross-repo-evaluation.js` | `""` |
| `LOOPOVER_MINER_GOVERNOR_LEDGER_DB` | `lib/governor-ledger.js` | (none) |
| `LOOPOVER_MINER_GOVERNOR_STATE_DB` | `lib/governor-state.js` | (none) |
| `LOOPOVER_MINER_LOG_LEVEL` | `lib/logger.js` | `""` |
Expand Down
71 changes: 69 additions & 2 deletions packages/loopover-miner/lib/cross-repo-evaluation.d.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
import type { RepoStackResult } from "./stack-detection.js";
/** Failure taxonomy surfaced in per-repo reports (#4788). */
/** Failure taxonomy surfaced in per-repo reports (#4788 readiness + #7634 full-execution). */
export declare const CROSS_REPO_FAILURE_CATEGORY: Readonly<{
STACK_DETECTION: "stack_detection_gap";
EXECUTION: "execution_gap";
GITTENSOR_ASSUMPTION: "loopover_assumption";
CLONE_SETUP: "clone_setup";
OTHER: "other";
/** Plan/spec formed but local build/compile command failed (#7634). */
COMPILE_FAILED: "plan_formed_compile_failed";
/** Build succeeded but the repo's own test suite failed (#7634). */
TESTS_FAILED: "compiled_tests_failed";
/** Tests passed but the coding attempt produced no file changes (#7634). */
NOOP_DIFF: "tests_passed_noop_diff";
/** Coding attempt abandoned before a handoff (agent unconfigured / refused) (#7634). */
EXECUTION_ABANDON: "execution_abandon";
}>;
/** Instruction substrings that indicate a POSITIVE loopover/LoopOver CI assumption leaked into the agent prompt.
* Lines that explicitly tell the agent *not* to assume these are filtered out before scanning. */
Expand All @@ -20,6 +28,8 @@ export type CrossRepoEvaluationManifestRepo = {
repoFullName: string;
stackHint?: string;
requireTestCommand?: boolean;
/** When true, include this repo in `--full-execution` runs (#7634). */
fullExecution?: boolean;
fixturePath?: string;
};
export type ParsedCrossRepoEvaluationManifest = {
Expand Down Expand Up @@ -67,6 +77,36 @@ type EvaluateRepoReadinessOptions = {
instructions?: string;
};
};
/** Local coding-attempt outcome for `--full-execution` (#7634). Never opens a forge PR. */
export type CrossRepoCodingAttemptResult = {
outcome: "handoff" | "abandon";
changedFiles: string[];
reason?: string;
};
export type CrossRepoShellCommandResult = {
ok: boolean;
exitCode: number;
stdout?: string;
stderr?: string;
};
export type EvaluateRepoFullExecutionOptions = EvaluateRepoReadinessOptions & {
/**
* Run the local discover→plan→code step and return changed files. MUST NOT open PRs or call forge
* write APIs (#7634). Injected in unit tests; default is a no-network stub that abandons unless
* `LOOPOVER_MINER_FULL_EXECUTION_STUB=1` (synthetic handoff for local dry demos).
*/
runCodingAttempt?: (input: {
repoFullName: string;
repoPath: string;
stack: RepoStackResult;
instructions: string;
}) => CrossRepoCodingAttemptResult | Promise<CrossRepoCodingAttemptResult>;
/** Run a local shell command (build/test). Injected in unit tests. */
runShellCommand?: (input: {
command: string;
cwd: string;
}) => CrossRepoShellCommandResult | Promise<CrossRepoShellCommandResult>;
};
/** Canonical `owner/repo` with exactly one slash and safe segments; anything else → null. */
export declare function normalizeCrossRepoFullName(value: unknown): string | null;
/**
Expand All @@ -86,12 +126,39 @@ export declare function scanPositiveLoopoverAssumptions(text: string): Array<{
* Evaluate one benchmark repo's miner readiness without running a live coding agent (#4788).
*/
export declare function evaluateRepoReadiness(entry: CrossRepoEvaluationManifestRepo, options?: EvaluateRepoReadinessOptions): CrossRepoEvaluationResult;
/**
* Default coding-attempt seam for `--full-execution` (#7634). Never opens a PR.
* - `LOOPOVER_MINER_FULL_EXECUTION_STUB=1` → synthetic handoff with one changed path (local demo only).
* - Otherwise abandons with a clear reason (real agent wiring stays opt-in via `runCodingAttempt`).
*/
export declare function defaultRunCodingAttempt(input: {
repoFullName: string;
repoPath: string;
stack: RepoStackResult;
instructions: string;
env?: NodeJS.ProcessEnv;
}): CrossRepoCodingAttemptResult;
/**
* Default local shell runner for build/test commands (#7634). Sync spawn; no network.
*/
export declare function defaultRunShellCommand(input: {
command: string;
cwd: string;
}): CrossRepoShellCommandResult;
/**
* Full-execution evaluation (#7634): readiness first, then local code→build→test with no forge writes.
*/
export declare function evaluateRepoFullExecution(entry: CrossRepoEvaluationManifestRepo, options?: EvaluateRepoFullExecutionOptions): Promise<CrossRepoEvaluationResult>;
/**
* Run the harness across every repo in a parsed manifest (#4788).
* Pass `fullExecution: true` (#7634) to run local code→build→test (still no forge writes).
*/
export declare function runCrossRepoEvaluation(parsed: ParsedCrossRepoEvaluationManifest, options?: {
repoFilter?: string;
} & EvaluateRepoReadinessOptions): CrossRepoEvaluationResult[];
fullExecution?: boolean;
/** Minimum repos to include in full-execution when filtering by `fullExecution` / requireTestCommand. */
fullExecutionMinRepos?: number;
} & EvaluateRepoFullExecutionOptions): Promise<CrossRepoEvaluationResult[]>;
/**
* Reduce per-repo results to pass/fail counts and whether a strict majority passed (#4788).
*/
Expand Down
Loading
Loading