synergyspec-selfevolving 2.1.5 → 2.1.7

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/dist/commands/learn.js +80 -24
  2. package/dist/commands/self-evolution-dream.d.ts +15 -1
  3. package/dist/commands/self-evolution-dream.js +111 -6
  4. package/dist/commands/self-evolution-episode.d.ts +3 -0
  5. package/dist/commands/self-evolution-episode.js +157 -108
  6. package/dist/commands/workflow/status.js +4 -0
  7. package/dist/core/archive.js +17 -9
  8. package/dist/core/change-readiness.d.ts +16 -1
  9. package/dist/core/change-readiness.js +441 -15
  10. package/dist/core/fitness/loss.d.ts +3 -5
  11. package/dist/core/fitness/loss.js +2 -2
  12. package/dist/core/fitness/test-metrics.d.ts +1 -0
  13. package/dist/core/fitness/test-metrics.js +49 -0
  14. package/dist/core/learn.js +129 -11
  15. package/dist/core/migration.d.ts +6 -14
  16. package/dist/core/migration.js +63 -21
  17. package/dist/core/runner-evidence.d.ts +53 -0
  18. package/dist/core/runner-evidence.js +613 -0
  19. package/dist/core/self-evolution/candidates.js +0 -2
  20. package/dist/core/self-evolution/dream.d.ts +57 -3
  21. package/dist/core/self-evolution/dream.js +480 -9
  22. package/dist/core/self-evolution/episode-orchestrator.d.ts +2 -0
  23. package/dist/core/self-evolution/episode-orchestrator.js +17 -5
  24. package/dist/core/self-evolution/episode-store.d.ts +5 -0
  25. package/dist/core/self-evolution/episode-store.js +6 -2
  26. package/dist/core/self-evolution/evolving-agent.d.ts +33 -4
  27. package/dist/core/self-evolution/evolving-agent.js +138 -11
  28. package/dist/core/self-evolution/host-harness.d.ts +35 -12
  29. package/dist/core/self-evolution/host-harness.js +188 -49
  30. package/dist/core/self-evolution/reward-aggregator.js +2 -2
  31. package/dist/core/templates/workflows/archive-change.js +18 -18
  32. package/dist/core/templates/workflows/dream.js +57 -47
  33. package/dist/core/templates/workflows/learn.js +7 -5
  34. package/dist/core/templates/workflows/run-tests.js +48 -29
  35. package/dist/core/templates/workflows/self-evolving.js +11 -8
  36. package/dist/core/trajectory/facts.d.ts +1 -1
  37. package/dist/core/trajectory/registry.js +39 -8
  38. package/package.json +1 -1
@@ -19,17 +19,19 @@ This is the review-and-learn step after \`/synspec:apply\` and \`/synspec:verify
19
19
  The runner starts with NO conversation context, so collect every handle it needs:
20
20
  - **Project root**: the absolute path of the current working directory.
21
21
  - **Change name**: from step 1.
22
- - **Harness**: read the \`harness:\` key from \`synergyspec-selfevolving/changes/<name>/.synergyspec-selfevolving.yaml\`; if absent, use \`unknown\`.
23
- - **Mode**: always \`apply\` — the episode runs the full loop (score, decide, and the 演进智能体's ONE bounded edit) autonomously, with no confirmation prompt. There is NO read-only episode and NO \`--preview\` flag. If the user wants a read-only look (no rollback, no evolution), do NOT run an episode: use the read-only view \`synergyspec-selfevolving self-evolution policy show\` (or a plain \`synergyspec-selfevolving learn <name>\` without \`--apply\`) instead.
24
- - **Session handle (optional)**: if your harness exposes this session's id or transcript path, capture it; otherwise omit it (the 主智能体 MAIN AGENT arm's trajectory discovery then uses the change window).
22
+ - **Harness**: resolve the CURRENT host runtime, not the change metadata. If this skill is running in Codex, use \`codex\`; in Claude Code, use \`claude\`; in OpenCode, use \`opencode\`. Use \`unknown\` only when the host is genuinely unidentified after checking the active session/tooling. Do NOT read \`harness:\` from the per-change YAML for this field: that metadata is historical provenance, not the runtime that will spawn the loop-v2 agents.
23
+ - **Mode**: always \`apply\` — the episode runs the full loop (score, decide, and the 演进智能体's ONE bounded edit) autonomously, with no confirmation prompt. There is NO read-only episode and NO \`--preview\` flag. If the user wants a read-only look (no rollback, no evolution), do NOT run an episode: use the read-only view \`synergyspec-selfevolving self-evolution policy show\` (or a plain \`synergyspec-selfevolving learn <name>\` without \`--apply\`) instead.
24
+ - **Force-new episode**: \`yes\` only when the user explicitly asked to rerun / force a fresh episode; otherwise \`no\`. A normal learn run must not invent a rerun.
25
+ - **Isolation**: \`fresh-context subagent\` for the spawned runner.
26
+ - **Session handle (optional)**: if your harness exposes this session's id or transcript path, capture it; otherwise omit it (the 主智能体 MAIN AGENT arm's trajectory discovery then uses the change window).
25
27
 
26
28
  3. **Spawn the runner**
27
29
 
28
- Use the host's available general-purpose Task/subagent runner (for example \`general-purpose\` on Claude or \`general\` on hosts that expose that type), prompt: "Use Skill tool to invoke synergyspec-selfevolving-self-evolving for change '<name>'. Project root: <root>. Harness: <harness>. Mode: apply. Session-id: <id>. Transcript: <path>. Trigger the loop-v2 self-evolution episode autonomously, do not ask the user questions, and end with the '## Episode Verdict' block."
30
+ Use the host's available general-purpose Task/subagent runner (for example \`general-purpose\` on Claude or \`general\` on hosts that expose that type), prompt: "Use Skill tool to invoke synergyspec-selfevolving-self-evolving for change '<name>'. Project root: <root>. Harness: <harness>. Mode: apply. Force-new: <yes|no>. Isolation: fresh-context subagent. Session-id: <id>. Transcript: <path>. Trigger the loop-v2 self-evolution episode autonomously, do not ask the user questions, and end with the '## Episode Verdict' block."
29
31
 
30
32
  Include the \`Session-id: <id>.\` / \`Transcript: <path>.\` segment only when the session handle from step 2 is known — omit it entirely when unknown.
31
33
 
32
- The runner triggers exactly one CLI command — \`synergyspec-selfevolving self-evolution episode --change "<name>" --session-id <id>\` — and the orchestrator CODE-SPAWNS the 奖励智能体 REWARD AGENT + 演进智能体 EVOLVING AGENT (+ optional CRITIC AGENT(基线智能体)). Neither you nor the runner grades or edits canonical files.
34
+ The runner triggers exactly one CLI command — \`synergyspec-selfevolving self-evolution episode --change "<name>" --harness <harness> --session-id <id> --rerun\` when force-new is \`yes\`; omit \`--rerun\` when force-new is \`no\`; omit \`--harness\` when it is \`unknown\` — and the orchestrator CODE-SPAWNS the 奖励智能体 REWARD AGENT + 演进智能体 EVOLVING AGENT (+ optional CRITIC AGENT(基线智能体)). Neither you nor the runner grades or edits canonical files.
33
35
 
34
36
  Guardrails:
35
37
  - Do NOT trigger the episode yourself in this session — it must run from a fresh context.
@@ -38,35 +38,53 @@ const INSTRUCTIONS_BODY = `**Input**: Optionally specify a change name. If omitt
38
38
  "startedAt": "<ISO timestamp>",
39
39
  "finishedAt": "<ISO timestamp>",
40
40
  "exitCode": 0,
41
- "signal": null,
42
- "stdoutLog": "synergyspec-selfevolving/changes/<name>/test-evidence/<timestamp>/runner.stdout.log",
43
- "stderrLog": "synergyspec-selfevolving/changes/<name>/test-evidence/<timestamp>/runner.stderr.log",
44
- "workspaceIdentity": {
45
- "changeName": "<name>",
46
- "taskId": "<benchmark task id, if any>",
47
- "cwd": "<absolute working directory>",
48
- "pyproject": {
49
- "path": "pyproject.toml",
50
- "name": "<[project].name, or null>",
51
- "sha256": "<sha256 of pyproject.toml, or null>"
52
- },
53
- "packageJson": {
54
- "path": "package.json",
55
- "name": "<package.json name, or null>",
56
- "sha256": "<sha256 of package.json, or null>"
57
- }
58
- },
59
- "junitXml": null,
60
- "coverageSummary": null,
61
- "coverageLcov": null,
62
- "coverageHtml": null
41
+ "signal": null,
42
+ "stdoutLog": "synergyspec-selfevolving/changes/<name>/test-evidence/<timestamp>/runner.stdout.log",
43
+ "stderrLog": "synergyspec-selfevolving/changes/<name>/test-evidence/<timestamp>/runner.stderr.log",
44
+ "stdoutLogSha256": "<sha256 of runner.stdout.log>",
45
+ "stderrLogSha256": "<sha256 of runner.stderr.log>",
46
+ "workspaceIdentity": {
47
+ "changeName": "<name>",
48
+ "taskId": "<benchmark task id, if any>",
49
+ "cwd": "<absolute working directory>",
50
+ "pyproject": null,
51
+ "packageJson": null
52
+ },
53
+ "testMetrics": {
54
+ "total": 29,
55
+ "passed": 29,
56
+ "failed": 0,
57
+ "passRate": 1
58
+ },
59
+ "junitXml": null,
60
+ "coverageSummary": null,
61
+ "coverageLcov": null,
62
+ "coverageHtml": null
63
63
  }
64
64
  \`\`\`
65
65
 
66
- If the runner produces JUnit XML or coverage artifacts, record their paths in
67
- \`runner-exit.json\`. If it does not, keep those fields \`null\`. The markdown
68
- report may summarize results, but the raw logs and exit JSON are the durable
69
- evidence that later verification must inspect.
66
+ Set each workspace identity file entry to an object ONLY when that file
67
+ exists at the project root. If \`pyproject.toml\` or \`package.json\` is absent,
68
+ leave that field \`null\` (or omit it); do not emit a \`path\` for an absent file.
69
+ Object shape for a present file:
70
+
71
+ \`\`\`json
72
+ {
73
+ "path": "pyproject.toml",
74
+ "name": "<project/package name, or null>",
75
+ "sha256": "<sha256 of the file>"
76
+ }
77
+ \`\`\`
78
+
79
+ If the runner summary exposes pass/fail counts, record them in
80
+ \`testMetrics\`; otherwise set \`testMetrics\` to \`null\` and preserve the raw
81
+ stdout/stderr logs. The \`stdoutLogSha256\` and \`stderrLogSha256\` fields MUST
82
+ be the SHA-256 hashes of the exact saved log files, computed after writing the
83
+ files and before writing \`runner-exit.json\`; do not hand-edit logs after
84
+ hashing. If the runner produces JUnit XML or coverage artifacts,
85
+ record their paths in \`runner-exit.json\`. If it does not, keep those fields
86
+ \`null\`. The markdown report may summarize results, but the raw logs and exit
87
+ JSON are the durable evidence that later verification must inspect.
70
88
 
71
89
  3b. **Promote PBT counterexamples to regression tests**
72
90
 
@@ -134,9 +152,10 @@ const INSTRUCTIONS_BODY = `**Input**: Optionally specify a change name. If omitt
134
152
  | UC1-E4a1 | Error when no grid space | ❌ failed | \`gridSize=0, widgetCount=1\` | \`test/pbt-regression-uc1-e4a1-1.test.ts\` |
135
153
  ...
136
154
 
137
- ### Test Run Results
138
- <summary from test runner output: passed/failed/skipped counts>
139
- If failures: list failing test names and errors.
155
+ ### Test Run Results
156
+ Summary: <N collected>, <N passed>, <N failed>, <N skipped>, <N collection errors>
157
+ <raw summary from test runner output: passed/failed/skipped counts>
158
+ If failures: list failing test names and errors.
140
159
 
141
160
  ### Runner Evidence
142
161
  | Evidence | Path / Value |
@@ -12,9 +12,11 @@ You are the RUNNER for a completed SynergySpec-SelfEvolving change. In loop v2 (
12
12
 
13
13
  Parse these handles from the spawning prompt:
14
14
  - **Change name** (required). If the change name is missing or does not resolve via \`synergyspec-selfevolving list --json\`, stop and report the error — do NOT prompt the user (you may have no user channel).
15
- - **Absolute project root.** Run every CLI command from it.
16
- - **Harness**: \`claude\` | \`codex\` | \`opencode\` | \`unknown\`. If a harness was provided and differs from the ambient host, set \`SYNERGYSPEC_SELFEVOLVING_HOST_HARNESS=<harness>\` for the CLI invocation below.
17
- - **Session-id / transcript path** (optional). When the spawning prompt supplied a session-id or transcript path, pass \`--session-id <id>\` / \`--transcript <path>\` to the \`episode\` command so the 主智能体 MAIN AGENT arm's trajectory discovery does not depend on the change-window fallback.
15
+ - **Absolute project root.** Run every CLI command from it.
16
+ - **Harness**: \`claude\` | \`codex\` | \`opencode\` | \`unknown\`. If a concrete harness was provided, pass \`--harness <harness>\` to the CLI invocation below. If the prompt says \`unknown\` but this runner is clearly executing inside Codex, Claude Code, or OpenCode, recover the current host and pass that concrete harness. Omit \`--harness\` only when both the prompt and the current runner host are genuinely unidentified; never set \`SYNERGYSPEC_SELFEVOLVING_HOST_HARNESS=unknown\`.
17
+ - **Force-new**: \`yes\` | \`no\` (optional; default \`no\`). If \`yes\`, append \`--rerun\` so a closed matching episode is not reused.
18
+ - **Isolation**: \`fresh-context subagent\` | \`inline fallback (degraded)\` (optional). If supplied, copy it verbatim into the verdict; otherwise infer from whether this skill is running in a spawned subagent or inline fallback.
19
+ - **Session-id / transcript path** (optional). When the spawning prompt supplied a session-id or transcript path, pass \`--session-id <id>\` / \`--transcript <path>\` to the \`episode\` command so the 主智能体 MAIN AGENT arm's trajectory discovery does not depend on the change-window fallback.
18
20
 
19
21
  **Recursion guard**
20
22
 
@@ -49,10 +51,11 @@ Everything in steps 1–6 is CODE. You do not perform any of it. You issue the c
49
51
 
50
52
  Run exactly ONE command — the loop-v2 orchestrator. It CODE-SPAWNS the 奖励智能体 REWARD AGENT + 演进智能体 EVOLVING AGENT (+ optional CRITIC AGENT(基线智能体)); you spawn nothing:
51
53
  \`\`\`bash
52
- synergyspec-selfevolving self-evolution episode --change "<change>" --json
53
- \`\`\`
54
- - Append \`--session-id <id>\` and/or \`--transcript <path>\` ONLY when the spawning prompt supplied them.
55
- - If the harness differs from the ambient host, set \`SYNERGYSPEC_SELFEVOLVING_HOST_HARNESS=<harness>\` first.
54
+ synergyspec-selfevolving self-evolution episode --change "<change>" --json
55
+ \`\`\`
56
+ - Append \`--session-id <id>\` and/or \`--transcript <path>\` ONLY when the spawning prompt supplied them.
57
+ - Append \`--harness <harness>\` when the spawning prompt supplied \`claude\`, \`codex\`, or \`opencode\`, or when the prompt supplied \`unknown\` but this runner can identify the current host as Codex, Claude Code, or OpenCode. Never append \`--harness unknown\`.
58
+ - Append \`--rerun\` ONLY when the spawning prompt supplied \`Force-new: yes\`.
56
59
 
57
60
  Do NOT grade, score, or author any edit yourself, and do NOT run \`evolve-from-edits\`, \`auto-evolve\`, or \`--agent\` / \`claude -p\` — those are not part of loop v2's host-facing path. The episode command IS the loop.
58
61
 
@@ -116,7 +119,7 @@ The session's final message MUST end with exactly this block shape:
116
119
  - Use \`busy-in-flight\` when the episode command returned the clean concurrency deferral (another in-flight episode holds the same 策略 POLICY target): advantage is null, episode id is none, 策略 POLICY version is unchanged. It is TRANSIENT and self-healing (retry after the lock clears / the 60-min stale window) — it is NOT a DEFECT, do not list it under Defects to surface, and never advise deleting \`in-flight.json\`.
117
120
  - When the episode did NOT start (Episode id is none — any not-run / busy-in-flight / error-* outcome), write \`none\` for Evolved target and Canonical file(s) changed, report Decision/Advantage as none/null, and leave 策略 POLICY version unchanged. The change's CONFIGURED target id is context only — do NOT copy it into the Evolved target field on a non-run verdict.
118
121
  - A \`kept\` / \`abstained\` outcome on a verified-green run is the CORRECT no-op, not a missed evolution — say so plainly rather than hedging.
119
- - Report \`Isolation: fresh-context subagent\` when you were spawned as a subagent; report \`Isolation: inline fallback (degraded)\` when this skill is running inline in the spawning session.`;
122
+ - Copy the supplied \`Isolation:\` value verbatim when present. If it was not supplied, report \`Isolation: fresh-context subagent\` when you were spawned as a subagent, or \`Isolation: inline fallback (degraded)\` when this skill is running inline in the spawning session.`;
120
123
  export function getSelfEvolvingSkillTemplate() {
121
124
  return {
122
125
  name: 'synergyspec-selfevolving-self-evolving',
@@ -3,7 +3,7 @@ import type { HarnessName, NormalizedTrajectory } from './model.js';
3
3
  /** One failing test observed in the graded runner result's output. */
4
4
  export type ObservedTestFailure = ParsedTestFailure;
5
5
  export interface TrajectoryFacts {
6
- harness: HarnessName;
6
+ harness: HarnessName | 'runner-evidence';
7
7
  changeName: string;
8
8
  /**
9
9
  * A recognizable test-runner invocation (vitest/pytest/go test/…) produced a
@@ -5,12 +5,11 @@
5
5
  * Selection order:
6
6
  * 1. If the change metadata stamps a `harness` (the strongest signal — see
7
7
  * `ChangeMetadata.harness`), use that adapter.
8
- * 2. Otherwise read the adapter for the harness that is ACTUALLY RUNNING this
9
- * process (`resolveHostHarness()`: the CODEX_ / OPENCODE_ env heuristic, or
10
- * the `SYNERGYSPEC_SELFEVOLVING_HOST_HARNESS` override). This makes the
11
- * observed trajectory readable on a non-Claude host. With no harness env
12
- * present it resolves to 'claude' the historical default so existing
13
- * hermetic tests stay on the Claude adapter unchanged.
8
+ * 2. Otherwise read the trusted repo/host harness signal
9
+ * (`resolveHostHarnessDetailsForRepo()`): explicit override, persisted
10
+ * sidecar, explicit session id, or the historical Claude default. An
11
+ * env-only Codex/OpenCode signal on an unstamped change is intentionally
12
+ * too weak to scan the host's whole session store.
14
13
  * 3. `trajsz` is OPT-IN (env `SYNERGYSPEC_SELFEVOLVING_TRAJSZ`): when enabled
15
14
  * and a fresh archive is present it is tried FIRST, since it already
16
15
  * normalizes all three harnesses; absent/stale, we fall back to native.
@@ -98,8 +97,9 @@ export async function resolveTrajectorySource(projectRoot, changeName, options =
98
97
  return s;
99
98
  }
100
99
  catch {
101
- // fall through to probing
100
+ // fall through to the fail-closed return below
102
101
  }
102
+ return null;
103
103
  }
104
104
  }
105
105
  // 2. No stamp: use a trusted host recovery signal, not a blind global scan.
@@ -143,7 +143,7 @@ export async function getTrajectoryForChange(projectRoot, changeName, options =
143
143
  export async function getTrajectoryResultForChange(projectRoot, changeName, options = {}) {
144
144
  const source = await resolveTrajectorySource(projectRoot, changeName, options);
145
145
  if (!source)
146
- return { trajectory: null, sourceHarness: null, reason: 'no-trajectory-source' };
146
+ return explainTrajectorySourceMiss(projectRoot, changeName, options);
147
147
  try {
148
148
  const result = source.getTrajectoryResult
149
149
  ? await source.getTrajectoryResult(changeName)
@@ -162,4 +162,35 @@ export async function getTrajectoryResultForChange(projectRoot, changeName, opti
162
162
  };
163
163
  }
164
164
  }
165
+ async function explainTrajectorySourceMiss(projectRoot, changeName, options) {
166
+ const changeProvenance = await readChangeTrajectoryProvenance(projectRoot, changeName);
167
+ const sessionIds = uniqueNonBlank([
168
+ ...(options.sessionIds ?? []),
169
+ ...changeProvenance.sessionIds,
170
+ process.env.SYNERGYSPEC_SELFEVOLVING_SESSION_ID,
171
+ ]);
172
+ if (changeProvenance.harness) {
173
+ return {
174
+ trajectory: null,
175
+ sourceHarness: changeProvenance.harness,
176
+ reason: `stamped-${changeProvenance.harness}-source-unavailable`,
177
+ };
178
+ }
179
+ const hostResolution = await resolveHostHarnessDetailsForRepo(projectRoot);
180
+ const envOnlyNativeHost = hostResolution.source === 'env' &&
181
+ hostResolution.harness !== 'claude' &&
182
+ sessionIds.length === 0;
183
+ if (envOnlyNativeHost) {
184
+ return {
185
+ trajectory: null,
186
+ sourceHarness: hostResolution.harness,
187
+ reason: `env-only-${hostResolution.harness}-requires-stamped-harness-or-session-id`,
188
+ };
189
+ }
190
+ return {
191
+ trajectory: null,
192
+ sourceHarness: hostResolution.source === 'default' ? null : hostResolution.harness,
193
+ reason: `${hostResolution.source}-${hostResolution.harness}-source-unavailable`,
194
+ };
195
+ }
165
196
  //# sourceMappingURL=registry.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synergyspec-selfevolving",
3
- "version": "2.1.5",
3
+ "version": "2.1.7",
4
4
  "description": "AI-native system for spec-driven development",
5
5
  "keywords": [
6
6
  "synergyspec-selfevolving",