empty-pipeline-root-cause
Root-cause empty results in memory and graph pipelines.
- License 许可
- MIT
- 所属仓库
- zapabob/Skills
- 最近更新
- 2026-10-26
- Stars
- ★ 2
- Forks
- 0
01 前言 Front Matter
- name
- empty-pipeline-root-cause
- author
- Hermes
- license
- MIT
- version
- 0.1.0
- metadata
- { "hermes": { "tags": [ "Debugging", "Memory", "Semantic-Graph", "SQLite", "Root-Cause", "Verification" ], "related_skills": [ "systematic-debugging", "hakua-memory-dev", "memory-consolidation-sleep-obsidian-sync", "python-sqlite-script-safety" ] } }
- description
- Root-cause empty results in memory and graph pipelines.
03 SKILL.md 正文
Empty-Pipeline Root Cause
Root-causes a pipeline that returns a structurally empty result — [], count: 0,
association_id not found — and proves the repair on a database copy before touching the
live store. It does not run the periodic consolidation cycle itself (that is
memory-consolidation-sleep-obsidian-sync) and it does not teach general debugging method
(that is systematic-debugging). Stdlib Python plus sqlite3; no test framework needed.
When to Use
- A memory/graph tool answers successfully but with an empty payload, for cycles in a row.
- You have a suspected cause ("the provider is wrong", "the embedding is broken") and need it confirmed or killed before acting on it.
- A repair means flipping a config flag or seeding rows, and you must prove the blast radius on a copy before the live store.
- A second call to the same tool returns empty while the first returned data.
Prerequisites
- A readable SQLite DB path and a writable temp dir (
tempfile.gettempdir()). - For Hermes memory subsystems: the runtime interpreter is the repo venv, and the code that actually executes may be an installed package rather than the repo copy (see Pitfalls).
How to Run
Invoke the probe through the terminal tool, always against a copy:
python scripts/probe_seed_sources.py --db "<live.db>" \
--sql "SELECT COUNT(*) FROM <focus_table>" \
--sql "SELECT COUNT(*) FROM <fallback_table> WHERE <status_col>='<value>'"
Open the DB read-only when you only need counts; the script copies first by default so the
live file is never written. Use read_file on the implementation module to enumerate the
focus sources by hand, then encode them as --sql.
Quick Reference
| Need | Action |
|---|---|
| Empty result, live tool | Call the tool once; capture the response verbatim |
| Candidate seed sources | Read the function; count each source table directly |
| Live counts | probe_seed_sources.py --db <db> --sql "SELECT COUNT(*) …" |
| Kill a suspect theory | search_files the function for its network / LLM call sites |
| Prove a repair | Same probe against a copy, with the flag flipped |
| Blast radius | Run the side-effecting cycle on two copies, compare metrics |
| Commit + verify remote | git push, then git ls-remote + gh api …/commits/<branch> |
| Record the finding | Wiki concept page + ebbinghaus_memory(action="remember") |
Procedure
-
Capture the empty result verbatim. One call to the real tool. Record whether the response distinguishes disabled from enabled-but-empty — several tools return both, and an
enabled: trueflag with an empty list is a different bug fromenabled: false. -
Enumerate every source the function can draw from. Read the implementation and list each query feeding its focus set. Do not accept the first source you find; a focus set with two independent inputs needs both counted.
-
Count each source in the live DB. Use the probe with one
--sqlper source. Zero rows in every source means the empty result is structural, not transient — there was never anything to assemble. That single measurement usually ends the investigation. -
Falsify the leading suspect explicitly. For a "the provider/LLM is broken" theory, read the function under repair and search it for network or model call sites. If there are none, the theory cannot explain the symptom: record that it is a separate failure and stop chasing it. Name the correct failure you did find, so the earlier note stops misleading.
-
Prove the repair on a copy, never on the live store. Copy the DB into temp, construct the store object against the copy, flip the flag or seed the rows, and drive the full chain end to end (trigger → assemble → propose → validate → promote). Record the promoted id and the before/after counts. This also proves the repair is sufficient rather than merely correlated.
-
Measure blast radius before recommending the flip. Run the side-effecting cycle on two copies — one with the flag off, one with it on — and diff the metrics. Equal results are the evidence that the change is safe; equal-by-luck is not the same as equal-by-measurement.
-
Re-run the original tool once. One call. Never twice (see Pitfalls). Confirm the count moved and report the residual manual step (a restart) as unverified until the runtime actually reports the new state.
-
Record, then commit, then verify the remote. Write the root cause into the durable concept page, note the unverified step explicitly, commit with a scoped message, push, and confirm with three independent checks: local
rev-parse,git ls-remote, and the forge API. Write the run result back into the memory system after the commit, and say so in the record so the exported snapshot is not mistaken for post-write-back state.
Pitfalls
- A repeat call can fake a regression. A
UNIQUEfingerprint column plus a swallowedIntegrityErrormakes the second identical call return empty while the first row is stored. Verified pattern: preview → 1 result, immediate re-preview → 0, row count still 1. Delete the row before re-testing or the check lies. - Never seed or repair the production DB to make a check pass.
shutil.copy2into temp, run the whole chain there, then apply the real change only after the copy passes. - The runtime code may not be the repo code. Compare file hashes between the repo module and the installed package the interpreter actually imports, and compare version strings. Edit and diagnose the one that runs.
- Config flags load at startup. A flipped flag changes nothing until the process restarts, and the live status call keeps reporting the old value until then. Report that step as pending, never as done.
- "Empty" is often "no qualifying input", by design. When a threshold must be both rare enough to miss and common enough to be shared, a low hit rate is the mechanism working. Probe many samples, report the rate, and do not treat frequent failure as a bug.
- Count parity is not loss-freedom. Two snapshots with equal item counts can differ by removed-and-added rows. Diff exact keys and classify revisions, additions, and churn.
- Byte-size differences across a push are usually line endings.
core.autocrlf=truewith no.gitattributesinflates the checked-out copy. Compare blob hashes, not sizes, before calling a file corrupt. - Windows shell blocks long commands.
command length exceeds safe limitalso breaksread_fileandsearch_files; switch to Python insideexecute_codeand read files withopen(..., encoding="utf-8"). - Python 3.11 inspection scripts reject backslashes in f-string expressions. Precompute the value into a variable, then format it.
- A private-repo snapshot can still carry session excerpts in label fields even with secret patterns clean. Zero secret-pattern hits is not the same as zero disclosure risk.
Verification
python scripts/probe_seed_sources.py --db "<live.db>" --sql "SELECT COUNT(*) FROM <focus_table>"
Passing means the probe read the DB and reported a count; the investigation is only complete when every enumerated source is non-empty in the live store or the empty ones are named as the root cause, the suspect theory is recorded as falsified, and the repair is demonstrated on a copy.
04 同仓库更多 Skills
xurl
X/Twitter via xurl CLI: post, search, DM, media, v2 API.
writing-plans
Write implementation plans: bite-sized tasks, paths, code.
whisper
OpenAI's general-purpose speech recognition model. Supports 99 languages, transcription, translation to English, and language identification. Six model sizes from tiny (39M params) to large (1550M params). Use for speech-to-text, podcast transcription, or multilingual audio processing. Best for robust, multilingual ASR.
weights-and-biases
W&B: log ML experiments, sweeps, model registry, dashboards.
watchers
Poll RSS, JSON APIs, and GitHub with watermark dedup.
serving-llms-vllm
vLLM: high-throughput LLM serving, OpenAI API, quantization.