@lnilluv/pi-ralph-loop 0.1.4-dev.0 → 0.1.4-dev.1

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.
Files changed (38) hide show
  1. package/README.md +63 -12
  2. package/package.json +1 -1
  3. package/src/index.ts +1034 -168
  4. package/src/ralph-draft-llm.ts +35 -7
  5. package/src/ralph-draft.ts +1 -1
  6. package/src/ralph.ts +708 -51
  7. package/src/runner-rpc.ts +434 -0
  8. package/src/runner-state.ts +822 -0
  9. package/src/runner.ts +957 -0
  10. package/tests/fixtures/parity/migrate/OPEN_QUESTIONS.md +3 -0
  11. package/tests/fixtures/parity/migrate/RALPH.md +27 -0
  12. package/tests/fixtures/parity/migrate/golden/MIGRATED.md +15 -0
  13. package/tests/fixtures/parity/migrate/legacy/source.md +6 -0
  14. package/tests/fixtures/parity/migrate/legacy/source.yaml +3 -0
  15. package/tests/fixtures/parity/migrate/scripts/show-legacy.sh +10 -0
  16. package/tests/fixtures/parity/migrate/scripts/verify.sh +15 -0
  17. package/tests/fixtures/parity/research/OPEN_QUESTIONS.md +3 -0
  18. package/tests/fixtures/parity/research/RALPH.md +45 -0
  19. package/tests/fixtures/parity/research/claim-evidence-checklist.md +15 -0
  20. package/tests/fixtures/parity/research/expected-outputs.md +22 -0
  21. package/tests/fixtures/parity/research/scripts/show-snapshots.sh +13 -0
  22. package/tests/fixtures/parity/research/scripts/verify.sh +55 -0
  23. package/tests/fixtures/parity/research/snapshots/app-factory-ai-cli.md +11 -0
  24. package/tests/fixtures/parity/research/snapshots/docs-factory-ai-cli-features-missions.md +11 -0
  25. package/tests/fixtures/parity/research/snapshots/factory-ai-news-missions.md +11 -0
  26. package/tests/fixtures/parity/research/source-manifest.md +20 -0
  27. package/tests/index.test.ts +3169 -104
  28. package/tests/parity/README.md +9 -0
  29. package/tests/parity/harness.py +526 -0
  30. package/tests/parity-harness.test.ts +42 -0
  31. package/tests/parity-research-fixture.test.ts +34 -0
  32. package/tests/ralph-draft-llm.test.ts +82 -9
  33. package/tests/ralph-draft.test.ts +1 -1
  34. package/tests/ralph.test.ts +1265 -36
  35. package/tests/runner-event-contract.test.ts +235 -0
  36. package/tests/runner-rpc.test.ts +358 -0
  37. package/tests/runner-state.test.ts +553 -0
  38. package/tests/runner.test.ts +1347 -0
@@ -2,6 +2,8 @@ import { complete, type AssistantMessage, type Context, type Model } from "@mari
2
2
  import { basename } from "node:path";
3
3
  import { filterSecretBearingTopLevelNames } from "./secret-paths.ts";
4
4
  import {
5
+ acceptStrengthenedDraft,
6
+ hasFakeRuntimeEnforcementClaim,
5
7
  normalizeStrengthenedDraft,
6
8
  parseRalphMarkdown,
7
9
  validateFrontmatter,
@@ -81,9 +83,6 @@ function areFrontmattersEquivalent(
81
83
  return JSON.stringify(baseline) === JSON.stringify(strengthened);
82
84
  }
83
85
 
84
- function hasFakeRuntimeEnforcementClaim(text: string): boolean {
85
- return /read[-\s]?only enforced|write protection is enforced/i.test(text);
86
- }
87
86
 
88
87
  function isWeakStrengthenedDraftForScope(
89
88
  baseline: ParsedRalph,
@@ -143,6 +142,31 @@ function renderSelectedFilesSection(request: DraftRequest): string {
143
142
  .join("\n\n");
144
143
  }
145
144
 
145
+ function buildCompatibilityContractSection(scope: DraftStrengtheningScope): string {
146
+ if (scope !== "body-and-commands") {
147
+ return [
148
+ "Compatibility contract:",
149
+ "- body-only scope",
150
+ "- keep deterministic frontmatter unchanged",
151
+ "- edit the body only",
152
+ ].join("\n");
153
+ }
154
+
155
+ return [
156
+ "Compatibility contract:",
157
+ "- body-and-commands scope",
158
+ "- commands may only be reordered, dropped, or have timeouts reduced/kept within limits",
159
+ "- command names and run strings must match the deterministic baseline exactly",
160
+ "- max_iterations may stay the same or decrease from the deterministic baseline, never increase",
161
+ "- top-level timeout may stay the same or decrease from the deterministic baseline, never increase",
162
+ "- per-command timeout may stay the same or decrease from that command's baseline timeout, and must still be <= timeout",
163
+ "- completion_promise must remain unchanged, including remaining absent when absent from the baseline",
164
+ "- every {{ commands.<name> }} must refer to an accepted command",
165
+ "- baseline guardrails remain fixed in this phase",
166
+ "- unsupported frontmatter changes are rejected and fall back automatically",
167
+ ].join("\n");
168
+ }
169
+
146
170
  function buildStrengtheningPromptText(request: DraftRequest, scope: DraftStrengtheningScope): string {
147
171
  const repoSignals = summarizeRepoSignals(request).map((line) => `- ${line}`).join("\n");
148
172
  const selectedFiles = renderSelectedFilesSection(request);
@@ -152,6 +176,7 @@ function buildStrengtheningPromptText(request: DraftRequest, scope: DraftStrengt
152
176
  `Inferred mode: ${request.mode}`,
153
177
  `Target file: ${basename(request.target.ralphPath)}`,
154
178
  `Strengthening scope: ${scope}`,
179
+ buildCompatibilityContractSection(scope),
155
180
  "",
156
181
  "Repo signals summary:",
157
182
  repoSignals,
@@ -169,7 +194,7 @@ function buildStrengtheningPromptText(request: DraftRequest, scope: DraftStrengt
169
194
  export function buildStrengtheningPrompt(request: DraftRequest, scope: DraftStrengtheningScope): Context {
170
195
  return {
171
196
  systemPrompt:
172
- "You strengthen existing RALPH.md drafts. Return only a complete RALPH.md. Do not explain, do not wrap the output in fences, and do not omit required frontmatter.",
197
+ "You strengthen existing RALPH.md drafts. Follow the scope contract in the user message exactly. Return only a complete RALPH.md. Do not explain, do not wrap the output in fences, and do not omit required frontmatter.",
173
198
  messages: [
174
199
  {
175
200
  role: "user",
@@ -216,9 +241,6 @@ async function runCompleteWithTimeout(
216
241
  }
217
242
  }
218
243
 
219
- function isAuthFailure(result: AuthResult | AuthFailure): result is AuthFailure {
220
- return result.ok === false;
221
- }
222
244
 
223
245
  export async function strengthenDraftWithLlm(
224
246
  request: DraftRequest,
@@ -259,6 +281,12 @@ export async function strengthenDraftWithLlm(
259
281
  if (strengthened.body.trim().length === 0) return { kind: "fallback" };
260
282
  if (isWeakStrengthenedDraftForScope(baseline, strengthened, scope, rawText)) return { kind: "fallback" };
261
283
 
284
+ if (scope === "body-and-commands") {
285
+ const accepted = acceptStrengthenedDraft(request, rawText);
286
+ if (!accepted) return { kind: "fallback" };
287
+ return { kind: "llm-strengthened", draft: accepted };
288
+ }
289
+
262
290
  return {
263
291
  kind: "llm-strengthened",
264
292
  draft: normalizeStrengthenedDraft(request, rawText, scope),
@@ -25,7 +25,7 @@ export async function createDraftPlan(
25
25
  const request = buildDraftRequest(task, target, repoSignals, repoContext);
26
26
  if (runtime?.model) {
27
27
  const strengthen = options.strengthenDraftWithLlmImpl ?? strengthenDraftWithLlm;
28
- const strengthened = await strengthen(request, runtime, { scope: "body-only" });
28
+ const strengthened = await strengthen(request, runtime, { scope: "body-and-commands" });
29
29
  if (strengthened.kind === "llm-strengthened") return strengthened.draft;
30
30
  }
31
31