| name | aspirations-spark |
| description | Runs the Spark Check (Phase 6) and Immediate Learning (Phase 6.5) of the aspirations loop: adaptive spark questions, all sq-XXX handlers (including sq-012 self-purpose update), aspiration-level spark, and immediate capture of reasoning-bank entries, guardrails, and forge awareness. Use whenever a goal completes — this is the recursive self-improvement mechanism that captures learning in-flight instead of deferring to /reflect. Internal sub-skill of /aspirations. |
| user-invocable | false |
| parent-skill | aspirations |
| triggers | ["run_spark_check()","run_aspiration_spark()"] |
| conventions | ["aspirations","spark-questions","reasoning-guardrails","experience"] |
| minimum_mode | autonomous |
| revision_id | skill-bootstrap-aspirations-spark-e160b8 |
| previous_revision_id | null |
Spark Check (Micro-Evolution) and Immediate Learning
Invoked after every goal completion as Phase 6 (spark check) and Phase 6.5 (immediate learning) of the aspirations loop. The spark check is the recursive self-improvement mechanism. Phase 6.5 captures reasoning bank entries, guardrails, and forge awareness immediately during execution rather than waiting for /reflect.
Abbreviation Policy
Mandatory writes for this obligation: see core/config/obligation-schema.yaml
→ obligations.spark. Spark has no mandatory writes — it's discretionary
by design — but abbreviation is explicitly permitted when
outcome_class == routine. When skipping, log one line in the NARRATIVE
daily journal (agents/<agent>/journal/YYYY/MM/YYYY-MM-DD.md — plain text;
NEVER journal.jsonl, a JSON-per-line index that one raw text line corrupts —
2026-07-16 line-309 incident, every subsequent daemon append 500'd):
OBLIGATION ABBREVIATED: spark — {condition}. The learning-gate audit
(Phase 9.5d) verifies the claimed condition was true at iteration time.
Handoff Goal Protocol (Item 3)
When Phase 6.5 or any sq-XXX handler creates a goal that another agent should
pick up (e.g., a planner agent filing "Apply: ..." work for an implementer
agent), set the handoff fields so Item 3's scoring routes the goal correctly:
{
"title": "Apply: {what the target agent must do}",
"participants": ["agent"],
"handoff_to": "<target-agent-name>",
"handoff_from": "{current MIND_AGENT}",
"handoff_created_at": "{ISO timestamp now}",
...
}
The target agent must be reachable via participants — [agent] (shown
above, visible to all agents), [agent, user], or explicit [<name>] all
qualify. handoff_to is the routing preference; participants is the
visibility gate. Handoff fields are additive — goals without them keep
baseline scoring. See core/config/conventions/goal-schemas.md
§ Cross-Agent Handoff Fields.
Without these fields, the goal lands in the shared world queue with baseline
priority and may rot. With them, the target agent's boot surfaces it
(▸ N pending handoff(s) for you) and the selector's handoff_bonus scoring
(default +0.30) prioritizes it above unrelated work.
Inputs
source: Queue origin ("world" or "agent") — pass --source {source} to all aspirations-*.sh calls
Step 0: Load Conventions — Bash: load-conventions.sh with each name from the conventions: front matter. Read only the paths returned (files not yet in context). If output is empty, all conventions already loaded — proceed to next step.
Step 0.5: Record this spark firing for sentinel dedup (g-115-1203) — both
fire paths for this skill funnel through here: (1) the in-turn FAST path, where
the LLM fires Skill(aspirations-spark) directly from recurring-close.sh's
stdout outcome-aware imperative, and (2) the pending_phase_6_spark sentinel,
consumed by aspirations/SKILL.md Phase -0.5c.2 on next-iteration entry. Without
a shared record, the fast path double-fires (fire #1 in-turn + fire #2 from the
still-set sentinel). Recording the firing here lets Phase -0.5c.2's check skip
the redundant re-fire. One-shot, fail-open — a dedup-record error must never
block the spark.
goal_id = the just-completed goal this spark is evaluating (explicit on the
sentinel path via Phase -0.5c.2's goal_id arg; the current loop goal
on the fast path).
IF goal_id is in context:
# Pipe the wm slot THROUGH the dedup helper in ONE bash call: wm-read emits
# the current map, spark-fire-dedup.py stamps goal_id and emits the new map,
# wm-set replaces the slot. The helper is pure stdin->stdout (it must NOT
# spawn `bash wm-*.sh` itself — that hangs, rb-225/rb-247).
Bash: bash core/scripts/wm-read.sh spark_fired_session --json | py -3 core/scripts/spark-fire-dedup.py record <goal_id> | bash core/scripts/wm-set.sh spark_fired_session
# No goal_id (rare — e.g. a manual non-goal-scoped invocation): skip the record.
Phase 6.5: Immediate Learning (reasoning bank + guardrails + pattern outcomes)
If this goal's outcome produced a clear, reusable reasoning insight or
a safety lesson, capture it NOW — don't wait for /reflect.
This is for lessons learned during EXECUTION, not hypothesis resolution
(which /reflect handles separately).
SKIP: goal outcome was routine/expected with no new insight.
Exception: the Operational Gotcha Auto-Detection block always runs (it uses
structural keyword signals, not agent judgment about novelty).
PLACEMENT CHECK (before creating ANY guardrail or rb entry below): if the
prescriptive rule's applies_to is domain — i.e., it names a brand, a
product, a specific external service, or domain-specific infrastructure —
the rule belongs in a world/conventions/*.md file or as a domain-scoped
guardrail entry, NOT in a core .claude/rules/*.md file. Core rules and
core conventions must remain domain-agnostic per
.claude/rules/domain-free-examples.md. Pick applies_to honestly: if in
doubt between framework and domain, pick domain.
IF goal outcome revealed a reusable reasoning pattern (heuristic, procedure,
diagnostic, or causal insight) that would help with FUTURE similar goals:
# Duplicate/contradiction check before creating reasoning bank entry
existing_rb = Bash: reasoning-bank-read.sh --category {goal.category}
IF proposed entry semantically overlaps with an existing entry:
Strengthen existing: Bash: reasoning-bank-increment.sh {entry.id} utilization.times_helpful
Log: "Phase 6.5: Strengthened existing {entry.id} instead of creating duplicate"
SKIP creation
IF proposed entry contradicts an existing entry:
Retire old: Bash: reasoning-bank-update-field.sh {entry.id} status retired
Proceed to create new entry (supersedes old)
Create reasoning bank entry via reasoning-bank-add.sh:
# `id` and `created` auto-set by the script inside the file lock.
# Omit both — capture the assigned id from stdout's full-record JSON.
title: concise name for the insight
type: success | failure # success if from a working approach; failure if from debugging/fixing
category: goal's category
# Differentiated extraction prompt by type (g-306-23, ReasoningBank §3:
# success and failure carry different reusable signal, so prompt them apart):
# type==success → EXTRACT-VALIDATED-STRATEGIES: name the reusable
# strategy/heuristic that WORKED, the preconditions under which it
# applies, and WHY it succeeded — framed as a pattern to REPEAT.
# ("What is the validated, transferable approach here?")
# type==failure → EXTRACT-COUNTERFACTUAL-PITFALLS: name the specific
# pitfall to AVOID, what went wrong, and the counterfactual — the
# corrective action that SHOULD have been taken instead.
# ("What is the avoidable pitfall, and what should have happened?")
content: per the type-matched prompt above — a validated strategy to repeat
(success) OR a counterfactual pitfall + its correction (failure)
applies_to: <any|framework|domain|specific> # REQUIRED. any=cross-cutting methodology; framework=this framework's skills/scripts/gates; domain=this agent's deployment domain (the specific services, products, workflows the agent is deployed into); specific=single-incident
when_to_use: when this insight applies
source_goal: goal.id
source_reflection_id: "ref-{goal.id}-{timestamp}" # MR-Search: enables reflection quality tracking
poignancy: <1-10> # g-306-26 producer (BRD Gap 1a / Generative Agents 2304.03442):
# LLM-rated importance at write so the field populates (else the
# g-306-08 retrieve blend stays a permanent no-op on an all-null corpus).
# 1-3 routine/expected · 4-6 useful · 7-8 pivotal/surprising · 9-10 mission-altering.
# Rate how durable + impactful this lesson is for FUTURE retrieval.
Log in journal: "Immediate learning: created {rb-id from stdout} from {goal.id}"
IF goal outcome revealed a safety hazard, a mistake to avoid, or a
precondition that MUST be checked in future similar work:
# Duplicate/contradiction check before creating guardrail
existing_guards = Bash: guardrails-read.sh --category {goal.category}
IF proposed guardrail semantically overlaps with an existing guardrail:
Strengthen existing: Bash: guardrails-increment.sh {guard.id} utilization.times_active
Log: "Phase 6.5: Strengthened existing {guard.id} instead of creating duplicate"
SKIP creation
IF proposed guardrail contradicts an existing guardrail:
Retire old: Bash: guardrails-update-field.sh {guard.id} status retired
Proceed to create new guardrail (supersedes old)
Create guardrail via guardrails-add.sh:
# `id` and `created` auto-set by the script — omit both; capture
# assigned id from stdout's full-record JSON.
rule: what to check or avoid
category: goal's category
trigger_condition: when this guardrail applies
source: goal.id
source_reflection_id: "ref-{goal.id}-{timestamp}" # MR-Search: enables reflection quality tracking
Log in journal: "Immediate guardrail: created {guard-id from stdout} from {goal.id}"
# ── Operational Gotcha Auto-Detection (MANDATORY) ──────────────────
# Structural trigger: if execution involved debugging/fixing an error,
# the resolution pattern MUST be encoded. Not optional agent judgment.
# Uses keyword scan on execution context (same pattern as Step 8.5).
#
# Signal detection (scan goal outcome summary + execution trace):
# error_then_fix: (error|exception|traceback|failed|refused|permission denied|not found)
# AND (fixed by|resolved by|workaround|solution|the fix|root cause|turned out)
# explicit_gotcha: (must use|always use|never use|don't forget|gotcha|caveat|pitfall|footgun)
# environment_issue: (environment|env var|export|path|config|permission|port|firewall)
# AND (issue|problem|wrong|missing|incorrect|unexpected)
#
IF any gotcha signal detected in execution context:
# Determine store: prescriptive ("always/never/must") → guardrail; diagnostic → reasoning bank
IF lesson matches prescriptive pattern (always|never|must|do not):
existing_guards = Bash: guardrails-read.sh --category {goal.category}
IF semantic overlap with existing:
Bash: guardrails-increment.sh {guard.id} utilization.times_active
Log: "OPS GOTCHA: Strengthened existing {guard.id}"
ELIF no semantic overlap:
Create guardrail via guardrails-add.sh:
# `id` and `created` auto-set — omit both; capture from stdout.
rule: the prescriptive lesson
category: goal's category
trigger_condition: when this gotcha applies
source: goal.id
tags: ["ops-gotcha"]
Log: "OPS GOTCHA (guardrail): {rule} from {goal.id}"
ELSE:
existing_rb = Bash: reasoning-bank-read.sh --category {goal.category}
IF no semantic overlap with existing:
Create reasoning bank entry via reasoning-bank-add.sh:
# `id` and `created` auto-set — omit both; capture from stdout.
title: "Gotcha: {concise description}"
type: failure
category: goal's category
content: what happened, why, and how it was fixed
applies_to: <any|framework|domain|specific> # REQUIRED. ops gotchas about external services / domain infra → domain; framework-internal gotchas → framework; cross-cutting → any
when_to_use: {conditions: ["{error pattern or symptom}"], category: "{goal.category}"}
source_goal: goal.id
tags: ["ops-gotcha"]
poignancy: <1-10> # g-306-26 producer — see the 1-10 rubric in the
# reusable-reasoning-pattern block above. Ops gotchas
# are typically 5-8 (a reusable pitfall worth retrieving).
Log: "OPS GOTCHA (reasoning bank): {title} from {goal.id}"
ELIF semantic overlap found:
Bash: reasoning-bank-increment.sh {entry.id} utilization.times_helpful
Log: "OPS GOTCHA: Strengthened existing {entry.id}"
# Forge awareness: detect recurring manual procedures that should be skills
IF goal execution required a manual multi-step procedure that was repeated
across goals, OR that would clearly benefit FUTURE goals as a discoverable
skill (entry point) rather than inline code:
Bash: meta-read.sh skill-gaps.yaml
IF gap already exists for this procedure:
Increment times_encountered, append to encounter_log
ELSE:
Register new gap: id: gap-{next}, status: registered,
times_encountered: 1, procedure_name, estimated_value
Write updated skill-gaps.yaml via meta-set.sh
# Check forge criteria immediately
# GUARD: skip already-forged gaps (Phase 9.2 also checks this)
IF gap.status == "forged": skip forge criteria check
# Registry cross-check (g-326-09 incident; mirrors evolve Step 9): before trusting
# gap.status, grep world/forged-skills.yaml for `gap_ref: {gap.id}`. If a forged skill
# already references this gap, the local skill-gaps.yaml status is STALE (observed 11
# days stale for gap-006 despite a daemon-routed read) — SKIP the gap.
# forged-skills.yaml is the authoritative cross-agent registry; it is low-write-frequency
# and far less divergence-prone than skill-gaps.yaml (guard-1163 family).
Bash: grep -q "gap_ref: {gap.id}" "$WORLD_DIR/forged-skills.yaml" && SKIP this gap (already forged by another agent)
Read core/config/skill-gaps.yaml → forge_threshold (default: 2)
Read agents/<agent>/developmental-stage.yaml → current stage
# Curriculum contract gate (g-115-1801): the stricter gate /forge-skill enforces at its
# Step 1. Dev-stage >= EXPLOIT (competence axis) can pass while the curriculum contract
# (capability-unlock axis) still blocks forging — gate on BOTH so we never queue a forge
# goal that /forge-skill will ABORT. Exit 0 = permitted, exit 1 = blocked by curriculum stage.
Bash: curriculum-contract-check.sh --action allow_forge_skill
IF gap.times_encountered >= forge_threshold
AND gap.estimated_value >= "medium"
AND developmental stage >= EXPLOIT (developing+)
AND curriculum-contract-check exit code == 0:
# Live-store dedup (g-115-2284 — replaces compact-search; the in-context compact is
# doubly stale: context-read dedup + local-mirror render):
Bash: aspirations-query.sh --goal-field origin_signal "idea:forge-ready-{gap.id}"
Bash: aspirations-query.sh --title-contains "Forge skill: {gap.procedure_name}"
# (second probe catches legacy datestamped origin_signal variants)
IF either probe returns a pending/in-progress goal: SKIP — duplicate exists.
IF either probe ERRORS (non-zero exit or unparseable output): WARN loudly + SKIP —
suppression gates fail CLOSED (guard-487); a missed filing re-detects on the
next encounter, a cross-box duplicate does not self-heal.
IF both probes returned clean-empty ([]):
Route to target aspiration (current → matching category → /create-aspiration)
Build goal: title "Forge skill: {gap.procedure_name}",
skill "/forge-skill", args "skill {gap.id}", priority "MEDIUM",
origin_signal EXACTLY "idea:forge-ready-{gap.id}" — canonical form, NO
datestamp suffix (a datestamped variant defeats the duplication-gate's
Strategy-1 exact match; g-115-2284 incident g-115-2279-vs-g-307-54)
Add via aspirations-add-goal.sh --source {source} {asp.id} (goal JSON on stdin —
the canonical gated single-goal writer; replaces aspirations-update.sh here so
the goal-duplication-gate baseline fires at this site too, matching Step 9)
Post-filing read-back: re-run the origin_signal probe; only log "forge goal
filed" when the goal reads back (own-cloud can silently swallow the write while
echoing success — insight msg-20260714-213836-echo-3288). IF read-back empty:
WARN + retry the add once, then file-or-fail loudly.
Log in journal: "Forge-ready gap detected during execution: {gap.id}"
Log: echo '{"date":"...","event":"forge-ready","details":"Gap {gap.id} detected in Phase 6.5 from {goal.id}","trigger_reason":"immediate-learning-forge"}' | bash core/scripts/evolution-log-append.sh
# -- Pattern-Outcome Recording (wire retrieved-and-applied signatures, g-115-1442) --
# Closes the loop the utilization-feedback path deliberately skips
# (pattern_signatures have NO utilization increment path --
# utilization-feedback.py:187 "pattern_signatures don't have utilization
# increment paths") and that reflect-on-outcome covers ONLY for
# hypothesis-linked patterns (its CONFIRMED/CORRECTED calls fire from ABC
# chains). Without this step a pattern RETRIEVED and APPLIED during ordinary
# goal execution -- never tied to a resolving hypothesis -- accrues
# retrieval_count while outcome_stats.total stays 0 forever, so calibration
# measures tracking-presence, not pattern value (g-115-1441 finding: 14/19
# active patterns unwired; this is the g-115-1442 fix). The recording API
# (pattern-signatures-record-outcome.sh) already exists; this is the missing
# AUTOMATIC TRIGGER for the non-hypothesis path. Record VALUE, not presence
# (rb-1554): a retrieved pattern you did NOT apply records NOTHING.
#
# SKIP entirely IF trivial_mode OR outcome_class == routine (no deliberation
# worth judging). Otherwise:
Bash: cat agents/<agent>/session/retrieval-session.json # may be absent
IF file absent OR retrieval_performed == false: SKIP this block
retrieved_sigs = [e["id"] for e in (session.supplementary_detail or [])
if e.get("type") == "pattern_signature"]
IF retrieved_sigs is empty: SKIP this block # common case: no Step-4 patterns
FOR EACH sig_id in retrieved_sigs that you APPLIED to shape this execution
(the Step 4 Memory Deliberation ACTIVE set -- NOT merely retrieved):
# guard-575: a meta-pattern (one that predicts a prediction-error class,
# e.g. sig-003) is recorded via hypothesis resolution in
# reflect-on-outcome, NOT here -- skip those to avoid double-counting.
IF sig_id names a meta-pattern: continue
Judge against the ACTUAL outcome of this goal:
- the signature's expected_outcome / lesson HELD here -> CONFIRMED
- reality diverged / the lesson was wrong here -> CORRECTED
Bash: pattern-signatures-record-outcome.sh {sig_id} {CONFIRMED|CORRECTED}
Log: "Pattern outcome: {sig_id} {verdict} from {goal.id}"
# A pattern retrieved but NOT applied records nothing -- not-applicable is
# not CORRECTED, and recording it would inflate outcome_stats.total with
# noise (the exact failure mode g-115-1441 warned against).
Spark Check (Micro-Evolution)
Run after EVERY goal completion. This is the recursive self-improvement mechanism.
Program-Alignment Response (boost_generative_sparks consumer)
The aspirations-select Program-alignment probe (see aspirations-select/SKILL.md
§ Program-alignment probe, lines 156-185) reads world/program.md every
check_interval_goals iterations, asks the LLM whether the top-ranked goal
materially serves The Program, and increments program_misalignment_streak
in working memory on misalignment. When the streak reaches 3, the probe sets
boost_generative_sparks = true. This phase is the consumer for that flag —
without it, the probe's terminal action is a dead signal and the framework-vs-
domain self-correction mechanism never fires.
# CRITICAL: --json mode is load-bearing. The writer in aspirations-select
# stores a JSON bool (`echo 'true' | wm-set.sh ...`). Non-JSON wm-read.sh
# would serialize that as Python's `True` (capital T) while --json emits
# lowercase `true`. Comparing to the string "true" ONLY works in JSON mode.
# wm-read.sh prints `null` + exit 0 on missing slot — no fallback needed;
# `"null" != "true"` is the intended pass-through when the probe hasn't fired.
Bash: boost = wm-read.sh boost_generative_sparks --json
IF boost.strip() == "true":
Log: "▸ Program-alignment misalignment streak triggered — forcing aspiration_generation spark with product-domain bias"
# Clear the flag FIRST (atomic, idempotent). Even if subsequent steps
# error, the flag must not re-fire on the next iteration — otherwise a
# single misalignment escalation loops forever.
# CRITICAL: clear with `echo 'false'` (JSON bool) to match the writer's
# type. `echo '"false"'` would store a JSON string, breaking the bool
# round-trip that the --json read above depends on.
Bash: echo 'false' | wm-set.sh boost_generative_sparks
# Fire sq-007 (aspiration_generation) unconditionally — bypasses the
# routine-spark filter's escalation gate. The bias toward product-domain is
# communicated through the in-turn LLM question prompt below; the
# Extended layer (E1 in the aspiration-management plan) will formalize
# the bias via aspiration-generation-strategy.yaml domain_class_targets.
Ask sq-007: "The Program-alignment probe detected a misalignment streak
of 3 — my recent goals have drifted from The Program's primary
product focus (read world/program.md for the current domain) toward
framework-meta work. What new PRODUCT-DOMAIN aspiration would
materially serve The Program right now? Consider domain-specific
quality improvements, end-user-facing pipeline work, integration
work, or competitive-landscape response — whatever The Program
identifies as its primary value surface. Do NOT propose framework-
meta, agent-health, or cognitive-core aspirations — those are what
triggered the streak."
Bash: spark-questions-increment.sh sq-007 times_asked
IF sq-007 produces a concrete aspiration candidate:
Bash: spark-questions-increment.sh sq-007 sparks_generated
Invoke /create-aspiration from-self --plan with the candidate
description and explicit product-domain framing. The LLM passes the
product-domain preference through the candidate text; Phase B of
create-aspiration evaluates it normally.
# Log the causal chain so future reflection can attribute outcomes to
# the alignment intervention. Posted as a finding so correlations
# between probe firing and spark-generated aspirations are discoverable
# cross-agent. (journal-add.sh takes stdin JSON with a journal_file key
# — it is not a free-form telemetry sink; board-post fits this one-line
# event better.)
Bash: echo "Misalignment streak consumed: sq-007 fired with product-domain bias; outcome={candidate_created|no_candidate}" | board-post.sh --channel findings --type finding --tags "program-alignment,spark,sq-007"
Goal-Level Spark
Routine Spark Mode
When outcome_class == "routine_spark", evaluate creative + hypothesis questions.
This keeps the hypothesis pipeline alive AND surfaces non-obvious insights from
routine work. The expanded set is still limited (6 categories, self-selecting)
so cost is bounded. Principle: we are here to learn — never skip.
IF outcome_class == "routine_spark":
Bash: spark-questions-read.sh --active
all_active_questions = result # save — result will be overwritten by later reads
creative_routine_questions = [q for q in all_active_questions if q.category in (
"hypothesis_generation", # sq-009 — testable predictions
"forward_prediction", # sq-011 — what would break/change
"experiential_hypothesis", # sq-c09 — player perspective
"first_principles", # sq-016 — inherited assumptions
"transfer", # sq-003 — cross-domain transfer
"surprise", # sq-004 — did the outcome surprise us
"self_evolution" # sq-012 — does this outcome change my core purpose?
)]
Log: "▸ Routine spark: evaluating {len(creative_routine_questions)} creative+hypothesis questions"
For each question in creative_routine_questions:
Ask the question about the just-completed goal
Bash: spark-questions-increment.sh <question.id> times_asked
If spark generated:
Bash: spark-questions-increment.sh <question.id> sparks_generated
Execute the spark action (hypothesis creation via sq-009 handler,
or first-principles via sq-016 handler, or transfer insight log)
If any spark fires → log via:
echo '{"event":"routine_spark","details":"Goal {id} routine-sparked: {description}","date":"<today>"}' | bash core/scripts/evolution-log-append.sh
# ── Phase R2: Signal-escalated work discovery ──
# If any creative spark fired, the recurring goal's output was interesting enough
# to warrant checking whether it suggests new aspirations or actionable work.
# Also check for strategic scan signals in working memory — these enrich the
# spark evaluation even for seemingly routine outcomes.
Bash: wm-read.sh strategic_scan_signals --json
has_scan_signals = (result is not null and result != "null" and len(result) > 0)
IF any_spark_fired OR has_scan_signals:
# Escalate to generative sparks that were skipped by the routine filter
generative_questions = [q for q in all_active_questions if q.category in (
"aspiration_generation", # sq-007 — "Does this outcome justify a NEW ASPIRATION?"
"work_discovery" # sq-013 — "Did this reveal actionable work?"
)]
Log: "▸ Routine spark ESCALATION: evaluating {len(generative_questions)} generative questions"
For each question in generative_questions:
Ask the question about the just-completed goal
(include scan signal context from working memory if available)
Bash: spark-questions-increment.sh <question.id> times_asked
If spark generated:
Bash: spark-questions-increment.sh <question.id> sparks_generated
Execute the spark action (sq-007 handler creates aspiration,
sq-013 handler creates goals or aspiration)
RETURN # Skip full spark evaluation and Phase 6.5
Adaptive Spark Questions
Read active spark questions via script instead of using hardcoded spark questions.
bash core/scripts/spark-questions-read.sh --active → get active questions as JSON
- Ask each active question about the just-completed goal
- If a spark is generated:
bash core/scripts/spark-questions-increment.sh <id> sparks_generated
- Always:
bash core/scripts/spark-questions-increment.sh <id> times_asked (script auto-recomputes yield_rate)
Every evolution_rules.review_interval_sessions sessions:
- Retire questions with yield_rate < retire_threshold AND times_asked >= min_asks_before_retire
- Promote highest-priority candidate to replace retired question
- Log the change via
echo '<json>' | bash core/scripts/evolution-log-append.sh
Bash: spark-questions-read.sh --active
# ALL active spark questions evaluated for deep outcomes.
# No question count gating — full treatment regardless of outcome tier.
Log: "▸ Spark: evaluating ALL {len(result)} questions (outcome: {outcome_class})"
For each question in result:
Ask the question about the just-completed goal
Bash: spark-questions-increment.sh <question.id> times_asked
If spark generated:
Bash: spark-questions-increment.sh <question.id> sparks_generated
Execute the spark action (add source, create article, log gap, etc.)
# yield_rate is auto-recomputed by the increment script — no manual update needed
If any spark fires → log via:
echo '{"event":"spark","details":"Goal {id} sparked: {description of change}","date":"<today>"}' | bash core/scripts/evolution-log-append.sh
Hypothesis Generation via sq-009
When sq-009 (or sq-c09 experiential variant) fires, it creates a hypothesis goal:
0. Load domain context for informed hypothesis formation:
Bash: retrieve.sh --category {goal.category} --depth shallow
Bash: pipeline-read.sh --stage active
Bash: pipeline-read.sh --stage discovered
Check retrieved active/discovered hypotheses for semantic overlap with the proposed prediction.
IF a hypothesis already covers this prediction → SKIP creation, log: "sq-009: Duplicate of {existing_id}, skipped"
0.1. Category steering (BEFORE forming the prediction):
Review the categories of existing active+discovered hypotheses from Step 0.
Count hypotheses per category.
IF 3+ existing hypotheses share the same category (e.g., "code", "infrastructure"):
Log: "sq-009: Category '{saturated_category}' saturated ({count} hypotheses) — steering toward under-represented categories"
Prefer forming predictions in under-represented categories, especially:
user-experience, system-behavior, domain-quality, engagement
over already-saturated categories like: code, infrastructure, pipeline
Reformulate: what USER-FACING or EXPERIENTIAL consequence follows from this work?
0.5. Calibration gate (BEFORE assigning confidence):
a. Read recent accuracy: Bash: pipeline-read.sh --stage resolved
- Count CONFIRMED vs CORRECTED in this category (or overall if <3 in category)
- If total == 0: SKIP gate (no track record yet), proceed to Step 0.7
- Compute recent_accuracy = confirmed / total
b. Apply confidence ceiling:
- If recent_accuracy < 0.40: cap at 0.55
- If recent_accuracy >= 0.40 and < 0.60: cap at 0.65
- If recent_accuracy >= 0.60 and < 0.80: cap at 0.80
- If recent_accuracy >= 0.80: no cap
- Log: "Calibration gate: {N} resolved, {accuracy}% accurate → cap {cap}"
c. The agent MAY assign confidence below the cap freely.
The cap only prevents overconfidence, not underconfidence.
0.7. Adversarial pre-mortem (required when proposed confidence > 0.65):
Before finalizing confidence, articulate:
a. "The strongest reason this prediction could be WRONG is: ___"
b. "The code/system might actually handle this because: ___"
c. If (b) identifies a plausible mechanism the code already handles it,
reduce confidence by 0.15 (the "well-engineered codebase" prior).
d. Scope-quantifier decomposition (g-115-2576; runs at ANY proposed
confidence, not just > 0.65 — the 2026-07-18 replay found the failure
band at 0.5-0.68): if the claim contains a scope quantifier — "single
cause", "all N", "every", "systemic", "complete", "fleet-wide",
"none", "pure" — decompose it per-conjunct / per-member (rb-2572) and
price confidence off the WEAKEST conjunct, or NARROW the claim to the
members actually evidenced. 5 of 10 replayed CORRECTED hypotheses
shared exactly this shape: single-cause→multi-mechanism, systemic→
isolated, all-N→1-of-N, fleet-wide→one-box-over. A quantified claim
is a conjunction; its confidence is bounded by its weakest member.
e. Discriminating-power check (rb-4133; g-001-51, 2026-07-19) — the
mirror of (d): where (d) guards OVER-claiming breadth (CORRECTED-prone),
this guards a criterion with ZERO discriminating power (CONFIRMED-prone,
and therefore useless). If the prediction claims an intervention CHANGED
something, ask "could this criterion have come out the OTHER way?" The
criterion MUST then be a rate, mix, or before/after comparison — NEVER an
existence test, because the thing being tested is a DIFFERENCE and an
existence test has no difference in it. Cheap tell: if the criterion is
satisfiable WITHOUT the intervention existing (baseline behavior already
produces it), it measures the baseline, not the intervention — replace
it. Second tell: skipping a rate/mix measurement in favor of a binary
one on "sharpness" grounds trades power for comfort — the mix
measurement is the one that can embarrass you, which is exactly why it
is the informative one. Unambiguity is not discriminating power.
f. Record the pre-mortem in the experience archive (Step 2.5 content).
SKIP this step only if the prediction is about external systems
(AWS behavior, third-party APIs) rather than project code quality —
and even then, clause (d) still applies to the claim's own quantifiers,
and clause (e) still applies to any claim that an intervention changed
something.
-
Create pipeline record: echo '<record-json>' | bash core/scripts/pipeline-add.sh (stage defaults to discovered)
-
Add goal to aspiration: read current aspiration via aspirations-read.sh --id <asp-id>,
add new goal with hypothesis fields, then pipe updated aspiration JSON to
echo '<aspiration-json>' | bash core/scripts/aspirations-update.sh --source {source} <asp-id>
Goal fields:
participants: [agent]
skill: "/review-hypotheses --hypothesis {hypothesis_id}"
hypothesis_id linking to the pipeline file
horizon — select using decision tree below
resolves_no_earlier_than, resolves_by from default windows for chosen horizon
priority: MEDIUM (default, agent can adjust)
Horizon selection (pick the FIRST that matches):
- long — prediction about a trend, scaling limit, or outcome that needs weeks+ to observe
Example: "Storage rotation threshold will need adjustment as data volume grows"
- short — prediction about what will happen after a future change (next commit, deploy, refactor)
Example: "Refactoring auth caching will require service health-check interval changes"
Also use short when predicting: user's next likely focus area, whether a pattern holds
across future aspirations, or consequences of a known TODO/tech-debt item
- session — prediction verifiable NOW by reading current state
Example: "The service uses two-phase scheduling"
Bias toward short/long: If the prediction is about current state, it's probably already
captured by a goal outcome — don't duplicate it as a session hypothesis. Prefer forming
predictions about what WILL change or what WOULD happen IF something changes.
2.4. Move to active: bash core/scripts/pipeline-move.sh <hypothesis_id> active
(Without this, the record stays in discovered forever — /review-hypotheses reads active-only.
Mirrors /decompose Step 3.)
2.5. Archive hypothesis formation context:
experience_id = "exp-{hypothesis_id}"
Write agents//experience/{experience_id}.md with:
- Full context manifest content (what was actually read, not just paths)
- Evidence consulted and reasoning chain
- Why this confidence level was chosen
- What would change the prediction
echo '' | bash core/scripts/experience-add.sh
Experience JSON:
id: "{experience_id}"
type: "hypothesis_formation"
created: "{ISO timestamp}"
category: "{hypothesis category}"
summary: "Hypothesis: {claim} (confidence: {N})"
goal_id: "{goal.id}" # CANONICAL join key (experience.md schema). The recurring-close 4.25 canary and experience-read --goal match on THIS field — omitting it made template-written entries invisible to both (g-115-2511: writers drifted to source_goal by analogy with the rb/guardrail stores, false-firing force_experience_archival on deep closes)
hypothesis_id: "{hypothesis_id}"
tree_nodes_related: [nodes from context manifest]
verbatim_anchors: [key evidence excerpts that informed the prediction]
content_path: "agents//experience/{experience_id}.md"
Set experience_ref on pipeline record:
bash core/scripts/pipeline-update-field.sh {hypothesis_id} experience_ref "{experience_id}"
3. Move pipeline file from discovered/ to active/ (it's immediately actionable)
4. Log spark via echo '<json>' | bash core/scripts/evolution-log-append.sh
Self-Evolution Spark Handler
sq-012: "Does this outcome change how I think about my core purpose? Should my Self evolve?"
When sq-012 fires after goal completion:
- Read
agents/<agent>/self.md — current Self content
- Assess: does the goal outcome suggest a refinement, expansion, or course correction?
2.5. CONTRACT CHECK (before acting on Self):
Bash:
curriculum-contract-check.sh --action allow_self_edits
IF exit code 1 (not permitted):
Log: "sq-012: Self edit blocked by curriculum stage {stage_name from JSON output}"
Skip to step 4 — increment sparks_generated but DO NOT edit Self or write pending question
- IF YES — classify signal strength and change size (enforced by guard-380):
Both last_updated and last_update_trigger MUST be set in the SAME
Edit so the front-matter audit trail stays accurate. Setting only the
trigger leaves last_updated stale and the change becomes invisible to
any reader checking "when was Self last touched." Mirror sites that
MUST stay in sync with this pattern: respond/SKILL.md (user-correction),
felt-sense-checkin/SKILL.md (Material lane), encode-session/SKILL.md
(Lane 7). After Phase 7b collapse, this site no longer has a manual
forged-notification invocation — evolution-complete.py (Phase 5) handles
decisions-board posting AND user email for material self edits automatically.
a. STRONG signal + COSMETIC change (wording, typo, formatting only):
Edit agents/<agent>/self.md — update body AND front matter:
last_updated: <today (YYYY-MM-DD)>
last_update_trigger: self_evolution
The Phase 2 hooks (evolution-prepare -> evolution-record) captured the
Edit as a self-evolution.jsonl stub with status=awaiting_completion.
Finalize via the canonical primitive (cosmetic edits auto-skip email):
Bash: bash core/scripts/evolution-complete.sh
--revision-id <stub-rev-from-self-evolution.jsonl>
--reasoning "<>=80-char rationale citing sq-012 cosmetic signal>"
--signal-source sq-012
--signal-evidence '[{"type":"spark_question","id":"sq-012","outcome":"cosmetic"}]'
Log: "SELF EVOLUTION (cosmetic, audited via self-evolution stream): {summary}"
b. STRONG signal + MATERIAL change (new/removed drive, principle, role,
agent-provisionable action, or multi-paragraph rewrite — when in doubt,
treat as material):
Edit agents/<agent>/self.md — update body AND front matter:
last_updated: <today (YYYY-MM-DD)>
last_update_trigger: self_evolution
The Phase 2 hooks (evolution-prepare -> evolution-record) captured the
Edit as a self-evolution.jsonl stub with status=awaiting_completion.
Finalize via the canonical primitive (Phase 5 auto-posts decisions board
AND auto-emails user for material self edits — no manual forged-skill
invocation needed here):
Bash: bash core/scripts/evolution-complete.sh
--revision-id <stub-rev-from-self-evolution.jsonl>
--reasoning "<>=80-char rationale citing sq-012 signal + goal outcome>"
--signal-source sq-012
--signal-evidence '[{"type":"spark_question","id":"sq-012","outcome":"confirmed"}]'
Log: "SELF EVOLUTION (material, audited via self-evolution stream): {summary}"
c. WEAK / uncertain signal: DO NOT edit self.md on sq-012 alone.
Record the tentative signal for /reflect-on-self or /fresh-eyes-review
to cross-reference against other signals before acting.
Log: "sq-012: weak signal — deferred to cross-signal review"
(No pending-question pre-approval path — guard-380 replaced it with
post-notification on 2026-04-22. Pre-approval is no longer written here.)
- Increment
sparks_generated on the spark question
Data Acquisition Spark Handler
sq-c05: "Does my knowledge tree reference external data sources, systems, files, APIs, or environments that I haven't directly accessed? What would I learn from obtaining that data?"
When sq-c05 fires after goal completion:
- Bash: world-cat.sh knowledge/tree/_tree.yaml # scan node summaries for data source references
- Read entity_index — look for external system references (SSH endpoints, file paths, APIs, databases)
- Identify accessible but unaccessed data sources
- IF found:
invoke /create-aspiration from-self (Phase B will pick up the data acquisition opportunity)
- Increment
sparks_generated on the spark question
Memory Curation Spark Handlers
sq-014: "Did completing this goal make any of our existing STRATEGIES, GUARDRAILS, or PATTERN SIGNATURES obsolete or irrelevant?"
When sq-014 fires after goal completion:
- Identify the completed goal's category/domain
- Scan that category for strategies, guardrails, and pattern signatures
- For each item: "Does this goal's outcome make this artifact obsolete or irrelevant?"
- If YES to any: invoke
/reflect --curate-memory scoped to that category
- Increment
sparks_generated on the spark question
sq-c04: "Is there knowledge in our memory tree that CONTRADICTS what we just learned, or that we now know is STALE?"
When sq-c04 fires after goal completion:
- Load tree nodes for the completed goal's category using
tree-read.sh --leaves-under {category_key}
- For each leaf node with articles: check if key insights conflict with the goal's outcome
- If contradiction found: flag article for re-research:
echo '"<article_key> contradicts goal outcome: "' | wm-append.sh knowledge_debt
- If a belief is affected: weaken it via existing belief weakening logic (Step 7.6 or equivalent)
- Increment
sparks_generated on the spark question
Work Discovery Spark Handler
sq-013: "Did executing this goal reveal actionable work — a requirement, dependency, follow-up, fix, capability gap, or opportunity — that isn't already tracked?"
When sq-013 fires after goal completion:
- Classify the discovery:
requirement | dependency | follow-up | fix | capability_gap | opportunity
- Determine target aspiration:
a. Default: current aspiration (if the work fits its scope/motivation)
b. If out of scope: scan active aspirations (
aspirations-read.sh --summary)
for one whose motivation covers this work → use that aspiration
c. If no existing aspiration fits: invoke /create-aspiration with the discovery
context (title, description, category) — skip to step 9 (log + increment)
- Read target aspiration:
bash core/scripts/aspirations-read.sh --id <target-asp-id>
- Compute next goal ID: find max
g-NNN-NN sequence in target's goals, increment by 1
- Build goal object:
id: computed next goal ID
title: concise description of the discovered work
description: what was discovered and why it matters
status: pending
skill: appropriate skill for the work
priority: dependency/requirement/fix → HIGH, follow-up/capability_gap → MEDIUM, opportunity → LOW
verification: outcomes + checks + preconditions
discovered_by: the completed goal ID that triggered this spark
discovery_type: the classification from step 1
origin_signal is gate-required — origin-signal-gate.py rejects
agent-sourced goals without one. The mapping below codifies the
discovery_type → origin_signal correspondence so future passes pick
the right value without re-deriving it; the table is the single
source of truth for sq-013-filed goals.
origin_signal: derive from discovery_type (use the prefix form with
a short slug — typically g-NNN-NN-<short-tag> or the discovered work's
identifier):
requirement | dependency | fix → "maintain:<tag>" or "unblock:<tag>"
follow-up | capability_gap → "investigate:<tag>" or "idea:<tag>"
opportunity → "idea:<tag>"
5.5. Quality gate for project+ aspirations (scope-aware goal addition):
IF target aspiration's scope is "project" or "initiative"
AND discovery_type NOT in ("fix", "dependency"): # cognitive primitives exempt
description MUST include: what was discovered, why it matters, and brief tree consultation
(Bash: tree-find-node.sh --text "{goal.title}" --leaf-only --top 1 — enrich with existing knowledge)
verification.outcomes MUST include meaningful success criteria (not just "task completed")
- For
capability_gap or opportunity discoveries: consider whether a companion
test/verification goal should also be created (same pattern as Step 4c in create-aspiration)
- Add new goal to the target aspiration's
goals array
- Pipe the updated aspiration JSON to:
bash core/scripts/aspirations-update.sh --source {source} <target-asp-id>
- If discovery type is
dependency: add new goal ID to blocked_by on dependent goals
- Log spark event:
echo '{"event":"spark","details":"sq-013: Goal <completed-id> discovered <type>: <title> → <target-asp-id>","date":"<today>"}' | bash core/scripts/evolution-log-append.sh
- Increment
sparks_generated on the spark question
Integration Path Coverage Spark Handler
sq-019: "Does the test coverage verify the INTEGRATION PATH (trigger -> handler -> side effect), or only the extracted function in isolation?"
When sq-019 fires after goal completion:
- Did this goal produce or modify code (Edit/Write to source files)? If no → SKIP (not applicable)
- Trace the integration path from the change point:
- What triggers the changed code? (API call, event bus message, scheduler, user action)
- What side effects does it produce? (state change, message publish, file write)
- Is there a test that exercises trigger → changed code → side effect?
- IF no integration path test exists:
Create investigation goal (via Cognitive Primitives):
- Title:
"Investigate: integration path coverage for {changed module}"
- Priority: MEDIUM, category: from goal's category
- Verification outcome: "Integration path traced with test gap documented or closed"
discovered_by: the completed goal ID
- ELIF integration path test exists but is incomplete:
Create idea goal:
"Idea: extend integration test for {module} to cover {gap}"
- ELSE: integration path is covered — no spark generated, SKIP to step 7
- Log spark event:
echo '{"event":"spark","details":"sq-019: Goal <completed-id> integration path check for <module>","date":"<today>"}' | bash core/scripts/evolution-log-append.sh
- Increment
sparks_generated on the spark question ONLY if step 3 or 4 created a goal
Aspiration Generation Spark Handler
sq-007: "Does this outcome justify a NEW ASPIRATION (multi-goal initiative) — not just a single follow-up Idea/Investigate goal?"
When sq-007 fires after goal completion:
- Assess: does the goal's outcome suggest an entirely new direction that doesn't fit within any existing aspiration?
- If YES: invoke
/create-aspiration from-self — the skill reads Self, scans for purpose gaps, and generates aligned aspirations
- Log spark event:
echo '{"event":"spark","details":"sq-007: Goal <completed-id> suggested new aspiration direction: <brief description>","date":"<today>"}' | bash core/scripts/evolution-log-append.sh
- Increment
sparks_generated on the spark question
sq-015: Meta-Improvement Spark
Handler for sq-015 — "Did this outcome suggest a better improvement PROCEDURE?"
When sq-015 fires after goal completion:
- Bash: meta-cat.sh improvement-instructions.md
- Compare: did the approach used in this goal deviate from the documented procedure?
- Deviated AND succeeded: procedure may be outdated → note for evolve phase
- Deviated AND failed: procedure may be correct → reinforcing signal
- Followed AND succeeded: procedure validated → reinforcing signal
- Followed AND failed: procedure may need revision → note for evolve phase
- IF meta-insight found:
- Append to meta/meta-log.jsonl via meta-log-append.sh:
{"date":"","event":"meta_spark","goal_id":"<goal.id>",
"insight":"","procedure_match":"<deviated|followed>",
"outcome":"<succeeded|failed>"}
- Log: "META SPARK: {insight} from {goal.id}"
- Bash: spark-questions-increment.sh sq-015 sparks_generated
sq-018: Verify-Learning Maintenance Spark
Handler for sq-018 — "Did this work suggest a NEW test/check/assertion to add to /verify-learning?"
This catches regressions in framework-relevant code (core/, .claude/skills/,
.claude/rules/, world/conventions/, .claude/settings.json) by proposing an
explicit assertion in /verify-learning Step 3 BEFORE the next regression hits.
When sq-018 fires after goal completion:
-
SCOPE FILTER — was this goal framework-touching?
Bash: git diff --name-only HEAD@{1} HEAD 2>/dev/null | grep -E '^(core/(scripts|config)|.claude/(skills|rules)|world/conventions|.claude/settings.json)' | head -20
IF empty: SKIP — do NOT increment sparks_generated. Pure non-framework
goals (domain-specific code, application logic, product features) have
no /verify-learning surface.
-
For each changed framework file, identify a check that catches the same regression:
- New script invariant → grep-based assertion ("file X must contain Y")
- New file expected → existence check (test -f / test -d)
- New behavior → command_check + expected stdout/stderr
- New convention rule → assertion that the documented rule holds in code
- New hook / integration → run-once verification that wiring is live
-
FILE the check as a Maintain-style goal under asp-115 (framework hygiene). The goal
exists for SCOPE-DISCIPLINE -- adding the check inline during THIS goal's spark would
be scope creep (implementation-discipline.md) -- NOT because the agent lacks authority.
.claude/skills/verify-learning/SKILL.md is an agent-editable framework file
(.claude/skills/**); its executor applies the check by DIRECT EDIT, routing
participants: [agent], with care (mirror an existing Step-2 sibling check, validate
before/after). Do NOT route to the user -- user-gating a verify-learning patch is the
g-115-792 anti-pattern (.claude/rules/capability-before-user.md; rb-1993).
origin_signal MUST come from the canonical list enforced by
core/scripts/origin-signal-gate.py. Bare "sq-018" is rejected — use the
"maintain:" prefix form with a short tag. The tag MUST be UNIQUE per
goal (e.g. "maintain:sq-018-") — the
goal-duplication gate's origin_signal strategy exact-matches, so a
fixed literal here makes every later sq-018 goal false-block against
every earlier one (observed 2026-07-11: marker-check goal blocked
against the unrelated g-115-1993 evolution-capture checks).
aspirations-add-goal.sh reads JSON from STDIN (BODY="$(cat)" at line 103);
positional JSON args are silently discarded.
echo '{"title":"Maintain: add verify-learning check for ",
"description":"What changed during <goal.id>, why a check is needed, suggested check form",
"status":"pending","priority":"MEDIUM","category":"framework-hygiene",
"participants":["agent"],
"discovered_by":"<goal.id>",
"discovery_type":"capability_gap",
"origin_signal":"maintain:sq-018-"}'
| bash core/scripts/aspirations-add-goal.sh --source world asp-115
-
Log: echo '{"event":"spark","details":"sq-018: Goal <goal-id> proposed verify-learning check for <file>","date":"<today>"}' | bash core/scripts/evolution-log-append.sh
-
Bash: spark-questions-increment.sh sq-018 sparks_generated
sq-016: First-Principles Spark
Handler for sq-016 — "Did this goal's approach rest on inherited assumptions rather than verified ground truth?"
When sq-016 fires after goal completion:
- Identify the goal's execution approach and framing
- Surface 2-3 assumptions embedded in the approach:
- What was taken for granted?
- What conventional wisdom was applied without verification?
- What "standard approach" was used because it is standard, not because it was derived?
- For each assumption, classify:
- VERIFIED: agent has direct evidence for this assumption (from tree, experience, or execution)
- INHERITED: assumption came from documentation, convention, or prior framing without independent verification
- UNTESTED: assumption was neither verified nor consciously inherited — it was implicit
- IF any assumption is INHERITED or UNTESTED:
a. Check existing reasoning bank for entries about this assumption:
Bash: reasoning-bank-read.sh --category {goal.category}
b. IF no existing entry covers this assumption:
Create reasoning bank entry via reasoning-bank-add.sh:
#
id and created auto-set — omit both; capture from stdout.
title: "Assumption: {concise description of the inherited assumption}"
type: failure
category: goal's category
content: "Goal {goal.id} used this assumption without verification: {assumption}. The approach {did/did not} succeed, but the assumption remains unverified. Ground truth check: {what would need to be true for this to be verified}."
applies_to: any # surfaced assumptions are methodological — they apply across domains
when_to_use: "{conditions where this assumption is relevant}"
source_goal: goal.id
source_horizon: micro # g-303-34 / rb-876 attribution gap: first-principles spark RBs are micro-horizon-originated; stamping makes the origin traceable. Passthrough field — reasoning-bank-add.sh forwards the full JSON, apply_defaults preserves extras, and the rb validator has no unknown-field gate, so this persists without a store-contract change.
tags: ["first-principles", "inherited-assumption"]
Log: "FIRST PRINCIPLES: Surfaced inherited assumption from {goal.id}: {assumption}"
c. IF assumption is UNTESTED AND goal succeeded:
Most dangerous case — success reinforces unchecked assumptions
Create a micro-hypothesis in working memory. resolves_when + consumer are
REQUIRED (g-303-34, zeta audit g-303-14): the dominant micro-hyp failure is
NON-RESOLUTION + NO-CONSUMER (71% never settle, 0% consumed). A micro-hyp
that cannot name BOTH a concrete later settling signal AND a downstream
consumer is noise — do NOT file it. resolves_when = the concrete later
signal that settles it (keep ASCII — this JSON is piped to wm-append.sh).
consumer = which decision/goal/encoding will use the resolution.
echo '{"claim":"Goal {goal.id} succeeded despite untested assumption: {assumption}. This assumption may fail when {condition}.","confidence":0.40,"source_goal":"{goal.id}","source_step":"sq-016","horizon":"session","resolves_when":"next {goal.category} goal that relies on {assumption}: observe whether it fails under {condition}","consumer":"reasoning-bank entry under {goal.category} gating future reliance on {assumption} if it fails"}' | Bash: wm-append.sh micro_hypotheses
Log: "FIRST PRINCIPLES -> HYPOTHESIS: untested assumption '{assumption}' may fail under {condition}"
Only count as spark if at least one assumption was surfaced (step 4b or 4c fired)
Bash: spark-questions-increment.sh sq-016 sparks_generated
Failure Stepping-Stone Spark Handler (OMNI-EPIC-inspired)
sq-c08 (candidate): "Did this goal fail in a way that suggests an easier stepping-stone variant?"
Inspired by OMNI-EPIC's failure-informed difficulty adjustment (arXiv 2405.15568):
when a task fails, generate an easier variant rather than retrying or abandoning.
This creates natural curriculum progression without explicit difficulty parameters.
When sq-c08 fires after a FAILED goal:
-
Analyze the failure mode:
- Was it too ambitious? (scope exceeded current capability level)
- Was it missing prerequisites? (knowledge gap, infrastructure dependency)
- Was it unclear? (poorly specified, ambiguous verification criteria)
- Was it blocked by external factors? (user action needed, service unavailable)
-
If the failure suggests a simpler version would succeed:
Generate a stepping-stone goal that:
- Addresses the SAME domain/category as the failed goal
- Has reduced scope (narrower question, smaller artifact, fewer components)
- Includes the prerequisite the original was missing
- Explicitly references the failed goal in description:
"Stepping stone for {failed.title} — {what makes this version simpler}"
-
Add via aspirations-add-goal.sh to the same aspiration:
echo '{"title":"Stepping stone: {simpler variant title}","description":"Easier variant of {failed.id}: {failed.title}. {what makes this simpler}. Original failure mode: {failure_analysis}.","priority":"{same as failed}","category":"{failed.category}","participants":["agent"],"origin_signal":"unblock:{failed.id}"}' | Bash: aspirations-add-goal.sh --source {source} {asp.id}
-
Log: echo '{"date":"<today>","event":"stepping_stone_created","details":"Easier variant of {failed.id} → {new.title}","trigger_reason":"sq-c08 failure stepping-stone"}' | bash core/scripts/evolution-log-append.sh
-
Bash: spark-questions-increment.sh sq-c08 sparks_generated
When NOT to create a stepping stone:
- Failure was due to infrastructure issues (transient — retry is appropriate)
- Failure was due to blocked_by dependency (wait, don't simplify)
- The goal is already a stepping stone (avoid infinite regression)
- The failed goal's title starts with "Stepping stone:" → SKIP
Aspiration-Level Spark (when entire aspiration completes)
Ask these 3 questions:
1. What did we learn from completing this entire aspiration?
→ Write reflection to journal
2. Does this completion unlock a new strategic direction?
→ YES: Create new aspiration via gap analysis
3. Should the system's self-model update?
→ YES: Update meta/meta-knowledge/_index.yaml
4. Did completing this aspiration teach us something about HOW we generate aspirations?
→ IF yes:
Bash: curriculum-contract-check.sh --action allow_meta_edits
IF permitted: Read via meta-read.sh and update via meta-set.sh: aspiration-generation-strategy.yaml with learned heuristic.
Bash: echo '{"date":"<today>","event":"aspiration_meta_learning","aspiration":"<asp-id>","insight":"<insight>"}' | meta-log-append.sh
Replacement aspiration generation is handled by Phase 7 archival in aspirations/SKILL.md
(with --plan for full planning treatment). Do NOT duplicate generation here.
Return Protocol
See .claude/rules/return-protocol.md — last action must be a tool call, not text.