[spark-compete] fix(system_map): narrow bare except in 6 builder-state-db helpers to (sqlite3.Error, OSError)#526
Conversation
…s to (sqlite3.Error, OSError)
inspect_builder_state_db, inspect_builder_request_id_overlap,
inspect_builder_trace_ref_overlap, inspect_builder_memory_tables,
inspect_builder_event_trace, and inspect_builder_event_samples all
wrap a sqlite3.connect + read-only query block in `except Exception
as exc: out["error"] = f"{type(exc).__name__}: {exc}"`. The pattern
is identical across all six: open a read-only sqlite db, run a set
of metadata queries, store partial output, and report any failure
into out["error"].
Replace `except Exception` with `except (sqlite3.Error, OSError)`.
SQL errors (OperationalError, DatabaseError, IntegrityError, etc.,
all under sqlite3.Error) still surface into out["error"] with the
same shape. Filesystem oddities (permission denied, ENOENT) under
OSError continue to be caught. KeyboardInterrupt, SystemExit, and
programming bugs (AttributeError, NameError, TypeError) now
propagate -- they should never have been swallowed and reported as
SQL inspection failures.
Pattern-match for the exception-narrow family: same shape as the
already-merged narrow bare except work by other contributors in
spark-researcher (vibeforge1111#39, vibeforge1111#40) and spark-character (vibeforge1111#4) and
spark-personality-chip-labs (vibeforge1111#3).
QA write-up — for reviewer eyesTL;DR. Six identical SQL-introspection helpers in BeforeEach of the six helpers ends the same way: try:
conn = sqlite3.connect(f"file:{db_path}?mode=ro", uri=True)
try:
# metadata + count queries
finally:
conn.close()
except Exception as exc:
out["error"] = f"{type(exc).__name__}: {exc}"
return outIf you typo a column name inside the try body, the AttributeError ends up as Aftertry:
conn = sqlite3.connect(f"file:{db_path}?mode=ro", uri=True)
try:
# metadata + count queries
finally:
conn.close()
except (sqlite3.Error, OSError) as exc:
out["error"] = f"{type(exc).__name__}: {exc}"
return outSame SmokeThe corrupt-db case still reports cleanly through the narrow catch. Full regression: What didn't changeSix sites, six edits, byte-identical except bodies. The Pattern-match: same shape as merged narrow-bare-except work in spark-researcher #39/#40, spark-character #4, spark-personality-chip-labs #3. |
Reviewer preference: include test file in commit?This PR currently keeps the smoke / reproducer outside the commit (see the Reproducer comment above, or the smoke commands in the packet's If you'd prefer the test pinned into the PR diff as a permanent regression guard (e.g. No action needed if comment-only is fine. |
|
Thanks, this was useful. We maintainer-adopted this exception-boundary improvement in #603 and merged it into What shipped:
Verification on the adopted PR:
Source credit is recorded for this PR, and #603 itself should not receive participant credit. Points are still gated because this PR body had Closing this PR as adopted into #603. No code action is needed unless you believe #603 missed part of the issue. |
…json to OSError
In delete_revoke_all_secrets the active-mission pause path (cli.py L8337)
wraps a sequence of dict assignments on the in-memory `active` dict
followed by save_json(active_path, active):
try:
active["status"] = "paused"
active["lastUpdated"] = created_at
active["note"] = "Paused by spark security revoke-all"
active["securityRevokeAll"] = {"pausedAt": created_at, "source": "spark-cli"}
save_json(active_path, active)
except Exception as error:
failures.append({"path": str(active_path), "error": ...})
The dict-assignment lines on an existing dict (already checked
isinstance(active, dict) two layers up at L8331) can't raise. The only
operation that can fail is the save_json file write -- which calls
atomic_write_json -> Path.mkdir/write_text/os.replace and only raises
OSError (the SystemExit from the symlink-guard is BaseException and
already passes through the bare-Exception unchanged).
Narrow `except Exception` to `except OSError`. Programming bugs and
interrupts now propagate. Except body byte-identical. Caller contract
(failures list shape) unchanged.
Pattern-match for the exception-narrow family: same shape as the
already-merged narrow bare except work in spark-researcher vibeforge1111#39, vibeforge1111#40,
spark-character vibeforge1111#4, spark-personality-chip-labs vibeforge1111#3, and our own
spark-cli vibeforge1111#526 (system_map sqlite introspection narrow).
|
R22/R23 final scoring update: this PR did receive final R22/R23 public leaderboard credit. Earlier gate, credit-review, or points-lock wording described the pre-final review state, not a final rejection or permanent zero. Final R22/R23 credit for this PR: 48 points. Thanks for the contribution. |
{
"schema": "spark-compete-hotfix-v1",
"event": "spark-compete-first-event",
"submission_mode": "public_repo_pr",
"submission_target_url": "#526",
"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-cli",
"source": "https://github.com/vibeforge1111/spark-cli",
"owner_surface": "spark-cli"
},
"issue": {
"type": "bug",
"severity": "low",
"title": "Six builder-state-db introspection helpers swallow KeyboardInterrupt and programming bugs as generic Exception",
"actual_behavior": "src/spark_cli/system_map.py has six builder-state-db introspection helpers (inspect_builder_state_db L651, inspect_builder_request_id_overlap L944, inspect_builder_trace_ref_overlap L986, inspect_builder_memory_tables L2579, inspect_builder_event_trace L2687, inspect_builder_event_samples L2745) that share an identical wrapper: open a read-only sqlite3 connection, run metadata queries, then
except Exception as exc: out[\"error\"] = f\"{type(exc).__name__}: {exc}\". The bare Exception catches everything -- including KeyboardInterrupt (under BaseException pre-3.8 and harmless to catch post-3.8, but still risky), SystemExit, and silent programming bugs (AttributeError from a typo'd column name, NameError, TypeError). Those bugs get stringified into out["error"] and the helper returns partial state, hiding the real problem from the operator runningspark os compile.","expected_behavior": "The same
out[\"error\"]reporting happens for SQL errors and filesystem errors (the conditions the wrapper was designed to absorb), while programming bugs and interrupts propagate naturally so the operator sees them.","repro_steps": [
"gh pr checkout 526",
"PYTHONPATH=src python -c "from pathlib import Path; from spark_cli.system_map import inspect_builder_event_samples; import tempfile, os; d = tempfile.mkdtemp(); p = Path(d) / 'spark-intelligence'; p.mkdir(); (p / 'state.db').write_text('not a sqlite db'); print(inspect_builder_event_samples(p)['error'])" prints a DatabaseError/OperationalError type name, NOT 'Exception:'.",
"Inverse: hand-edit an AttributeError into the helper body (e.g. typo a column name) and the helper now raises AttributeError visibly rather than burying it as 'AttributeError: ...' in out['error'].",
"PYTHONPATH=src python -m unittest tests.test_system_map.SparkSystemMapTests.test_inspect_builder_event_samples_records_sqlite_error_when_db_corrupt -> ok. Full test_system_map sweep: 30 passed."
],
"affected_workflow": "spark os compile / builder-state-db introspection used by spark live status, spark doctor builder details, and the system_map relay"
},
"evidence": {
"safe_links_only": true,
"before_after_proof": "Six identical try/except patterns across system_map.py. Before:
except Exception as exc: out[\"error\"] = .... After:except (sqlite3.Error, OSError) as exc: out[\"error\"] = .... The except body is byte-identical -- only the catch tuple changes. Caller contract (out dict shape, return value) is unchanged. A corrupt-db smoke test pins the safe behavior: the new test seeds 'this is not a sqlite database' into the state.db file and confirms inspect_builder_event_samples still populates out['error'] with the sqlite3 error class name and NOT a generic 'Exception:'. Diff: system_map.py +6/-6, tests/test_system_map.py +14/-0. Full test_system_map regression: 30 passed.","links": [
"https://github.com//pull/526"
],
"forbidden": ["pdf","zip","exe","unknown downloads","shortened links","archives","binaries","tokens","browser cookies","wallet material","raw logs","raw conversations","raw memory","raw patches","private repo maps","private scoring details"]
},
"proposed_fix": {
"approach": "Replace
except Exception as excwithexcept (sqlite3.Error, OSError) as excin six identical sqlite3-connect wrapper sites in system_map.py. sqlite3.Error is the parent of OperationalError, DatabaseError, IntegrityError, ProgrammingError, NotSupportedError, InterfaceError, and Warning -- which covers every error path the helpers' bodies can raise. OSError covers any filesystem-layer issue surfacing through sqlite3.connect's URI parameter. The catch tuple is the only thing that changes; the except body is byte-identical. Add a focused test that pins the contract (corrupt db -> out['error'] is sqlite3-class-named).","files_expected": [
"src/spark_cli/system_map.py",
"tests/test_system_map.py"
],
"tests_or_smoke": "PYTHONPATH=src python -m unittest tests.test_system_map -> 30 passed. The new test test_inspect_builder_event_samples_records_sqlite_error_when_db_corrupt explicitly confirms the corrupt-db path still produces out['error'] without a generic 'Exception:' prefix."
},
"pr": {
"branch": "sentinel/exception-narrow/system-map-sqlite-introspection",
"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"],
"url": "#526"
},
"review_claim": {
"impact_claim": "low",
"evidence_types": ["passing_test","redacted_terminal_excerpt"],
"duplicate_notes": "Two prior PRs touch system_map.py with a single-site narrow at L420 in git_summary (driasim #348 and #523 -- competing attempts on the same line). Neither overlaps the six builder-state-db introspection sites this PR narrows (L651, L944, L986, L2579, L2687, L2745). johncrossu's bare-except narrowing work is in spark-intelligence-builder, not spark-cli system_map.",
"risk_notes": "Local scope: one source file, six identical edits in already-existing except clauses, plus one new unit test. Each except body is byte-identical pre/post. The success path through every helper is unchanged. SQL errors and filesystem-layer errors continue to be caught and reported via out['error']. Programming bugs and interrupts no longer get silently swallowed -- which is the only observable behavior change, and the goal of the fix.",
"review_state_requested": "pr_review"
}
}