Skip to content

the daemon reads projects.yml without asking its kind — a FIFO wedges the event loop at startup, on every project touch, and on list_projects/remove_project #2105

Closed

Description

@argszero

Four readers of ~/.emrg/projects.yml open it without asking its kind, and every one of
them runs on the daemon's event loop:

site reached by
EmrgServer._rebuild_sessions_index (emrg/server/daemon.py:1098) daemon startup
EmrgServer._touch_project (emrg/server/daemon.py:1897) every message carrying a cwd, and init_auto_evolve
EmrgServer._handle_list_projects (emrg/server/daemon.py:6012) every client's first frame (list_projects)
EmrgServer._handle_remove_project (emrg/server/daemon.py:6064) remove_project

read_text on a FIFO waits at the open for a writer and raises nothing, so no handler
can fire and the call never returns. These are synchronous calls inside coroutines the
daemon awaits, so the block is the whole daemon: every client stops being answered, no
turn runs, and the only recovery is a restart — which belongs to the host. The registry is
also the first thing a GUI or TUI asks for on connect, so the wedge arrives with the first
frame a client sends.

Measured 2026-10-11 (cyc20261011-173122) on master 60541e39, one arm per site bounded
by tests/bounded_read.within (5 s), each with a pipe-free control in the same shape:

site FIFO (master) control: a directory (master)
_handle_list_projects did not return in 5 s answered projects_list, log says IsADirectoryError: [Errno 21]
_touch_project did not return in 5 s warned failed to parse …, rebuilding, then tried to rename a temp file over the directory
_rebuild_sessions_index did not return in 5 s answered silently — no trace that the registry was unreadable
_handle_remove_project did not return in 5 s answered removed: false, error: "failed to read projects.yml"

The two directions need different answers, and the difference is not cosmetic:

  • The three readers refuse through the except OSError each already has for a registry
    it cannot read, so no new branch is added and the reading the caller gets is the one its
    contract already promised for an unreadable file.
  • _touch_project reads the registry and then rewrites it. Letting it fall into its
    existing "rebuilding" branch would answer a host file it could not read with an empty
    registry and delete every project the host had registered, in one write, to report a
    problem it never mentioned. It skips the registration instead — the file keeps what it
    had — and the warning names the kind.

This is the same condition #2062 named for the three file tools and #2073 for the
daemon's own readers; #2081 is the shared predicate (_non_regular_kind), and the
refusal here is that predicate plus one line, so this member is the last spelling of it in
this module rather than a second one.

Activity

  1. argszero commented on Oct 11, 2026

    @argszero
    OwnerAuthor

    Handled by #2106

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions