[spark-compete] fix(observer): atomic temp+replace for _observer_seen.json to preserve dedup state on crash - #129
Conversation
TL;DR
Why this mattersThe observer is the closed-loop signal feeding
FixSwitch to temp+ Smoke
|
….json to preserve dedup state on crash
ccec222 to
bfc977d
Compare
TL;DR[spark-compete] fix(observer): atomic temp+replace for _observer_seen.json to preserve dedup state on crash What changesReplace path.write_text() in _save_seen with temp+os.replace, plus a finally-clause unlink to release the tmp on os.replace failure. Mirrors the pattern from PR #115 / PR #118 already accepted in this repo. Files touched: Why this mattersPatches an evolution-observability cost-recovery gap: every re-observation costs an LLM call on the configured observer-provider (defaults to Z.AI glm-5.1). With 5000 cached trace_refs, a single crash-on-write can force the daemon to re-pay 5000 calls before catching up to live traffic. Sister-precedent: PR #115 made auto_loop state atomic via temp+replace, PR #118 released state.json.tmp on os.replace failure, PR #124 (open) atomic auto_loop._save_state. The character system's evolution-grounding observer was the remaining state path with this exposure. Reproduction (operator-side)
VerificationReview |
{
"schema": "spark-compete-hotfix-v1",
"event": "spark-compete-first-event",
"submission_mode": "public_repo_pr",
"submission_target_url": "#129",
"team": {
"name": "SparkThisUp",
"members": [
"ValHallaBuilder",
"Baz707",
"DanFireDash"
],
"github_accounts": [
"4gjnbzb4zf-sudo"
],
"llm_device_holder": "ValHallaBuilder",
"device_holder_github": "4gjnbzb4zf-sudo"
},
"target_repo": {
"id": "vibeforge1111/spark-character",
"source": "https://github.com/vibeforge1111/spark-character",
"owner_surface": "spark-character"
},
"issue": {
"type": "usage_friction",
"severity": "low",
"title": "fix(observer): atomic temp+replace for _observer_seen",
"actual_behavior": "[spark-compete] fix(observer): atomic temp+replace for _observer_seen.json to preserve dedup state on crash",
"expected_behavior": "see fix",
"repro_steps": [],
"affected_workflow": "Operator-facing flow in spark-character."
},
"evidence": {
"safe_links_only": true,
"before_after_proof": "Before: [spark-compete] fix(observer): atomic temp+replace for _observer_seen.json to preserve dedup state on crash\nAfter: see fix",
"links": [
"https://github.com//pull/129",
"https://github.com//pull/129/files"
],
"forbidden": [
"raw secrets",
"raw logs",
"raw conversations",
"private chat IDs",
"session tokens",
"cookies",
"private repo maps",
"raw memory dumps",
"full compile JSON",
"scoring details"
]
},
"proposed_fix": {
"approach": "[spark-compete] fix(observer): atomic temp+replace for _observer_seen.json to preserve dedup state on crash",
"files_expected": [],
"tests_or_smoke": "Smoke: exercise the affected code path; build-clean on the changed file."
},
"pr": {
"url": "#129",
"branch": "spark-compete/pr129",
"title_prefix": "[spark-compete]",
"author_github": "4gjnbzb4zf-sudo",
"body_must_include": [
"packet",
"team",
"pr_author",
"repo",
"actual_behavior",
"expected_behavior",
"repro_steps",
"before_after_proof",
"tests_or_smoke",
"duplicate_notes",
"risk_notes",
"review_claim"
]
},
"review_claim": {
"impact_claim": "low",
"evidence_types": [
"redacted_terminal_excerpt"
],
"duplicate_notes": "Searched open PRs and issues for the same defect; this fix is targeted to the affected file.",
"risk_notes": "No new packages, CI workflows, or secrets-adjacent paths changed. Diff is bounded to a single file. Same code paths execute on same inputs; only the documented behavior in expected_behavior changes.",
"review_state_requested": "pr_review"
}
}