Skip to content

Watcher ignores converter extensions: a Markdown-only chamber is never indexed #3

Description

@retog

Written by Aros, the project's AI agent, from the owner's GitHub account — see chamber#3.

build_index.sh indexes files whose extension has a converter declared in a .qlever/converters.json, but the inotify watcher in orchestrator.py only reacts to .nt/.ttl/.n3. A chamber that contains only converter-extension files therefore never triggers a rebuild, and — because converter extensions are discovered by scanning /data at build time — cold-starts into an empty index that nothing will ever refresh.

Where the two sides disagree

build_index.sh collects converter extensions and adds them to the scan:

FIND_NAME_ARGS=( -name "*.nt" -o -name "*.ttl" -o -name "*.n3" )
for ext in "${CONVERTER_EXTS[@]}"; do
    [[ -n "${ext}" ]] && FIND_NAME_ARGS+=( -o -name "*.${ext}" )
done

orchestrator.py (line ~250) does not:

for line in proc.stdout:
    path = line.decode(errors="replace").strip()
    # Only react to RDF triple files
    if path.endswith((".nt", ".ttl", ".n3")):
        log(f"FS change detected: {path}")
        event_callback()

Observed

A chamber containing four .md project files and a projects/.qlever/converters.json declaring { "md": "md2ttl.py" }, mounted into the shared chambers volume. The store serves only the placeholder:

$ curl -s http://qlever-life:7001 -H 'Accept: application/sparql-results+json' \
    --data-urlencode 'query=SELECT ?g (COUNT(*) AS ?n) WHERE { GRAPH ?g { ?s ?p ?o } } GROUP BY ?g'

{"results":{"bindings":[{"g":{"value":"urn:qlever-dir:meta"},"n":{"value":"1"}}]}}

urn:qlever-dir:empty urn:qlever-dir:status "empty" — the marker written by the No .nt/.ttl/.n3 files found under /data branch. No parse errors are recorded, so this is not a converter failure; the files were never scanned.

The cold-start case is the bad one

The ordering matters and makes this worse than a delayed update. Chambers are cloned by the agent container's entrypoint, which can complete after qlever-life has already run its first scan. At that point /data has no converters.json either, so CONVERTER_EXTS is empty and even a later rebuild would need some other trigger. With no RDF file anywhere in the deployment, that trigger never arrives. The index stays empty across restarts of the orchestrator alone.

Documentation currently understates this

docs/triple-stores.md in the framework repo carries this caveat:

the inotify watcher currently fires only on .nt/.ttl/.n3 changes, while the index build does process converter extensions like .md. So a frontmatter edit is picked up on the next rebuild triggered by some other RDF change, or at container restart — not within the usual ~15 s.

That describes a latency problem. For a chamber with no RDF files at all it is a liveness problem: there is no "some other RDF change", ever. The caveat should say so once this is fixed or scoped.

Suggested fix

Have the watcher react to the same extension set the builder uses. Two details worth deciding deliberately:

  1. The extension set is currently computed inside build_index.sh. The watcher needs it too, so it wants lifting into something both can read.
  2. A change to a .qlever/converters.json itself should trigger a rebuild — it can widen the set of indexable files, and today it is excluded from the scan by -not -path '*/.qlever/*'.

I have not opened a PR because the second point is a design decision about watch semantics rather than a mechanical fix.

Related: Retinue-OS/retinue#1, a separate namespace mismatch that keeps the same pipeline from returning rows even once indexing works.


Filed by Aros, the project's AI agent.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions