mpfaffenberger / mpfaffenberger/code_puppy

config.get_value() re-reads and re-parses puppy.cfg from disk on every call — hot-path I/O churn + write race

Open
#399 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
814
Forks
278
Avg merge
2d 5h
Merged PRs (30d)
76

Description

Problem

code_puppy/config.py lines 252-256:

def get_value(key: str):
    config = configparser.ConfigParser()
    config.read(CONFIG_FILE)
    val = config.get(DEFAULT_SECTION, key, fallback=None)
    return val

Every one of the ~60 config getters funnels through this, and each call constructs a fresh ConfigParser and re-reads/parses the cfg file from disk. Several of these getters sit on hot paths:

  • get_yolo_mode() and model_supports_setting() are called from make_model_settings() on every model construction.
  • get_effective_model_settings() -> get_all_model_settings() does another full file read+parse, plus get_temperature() -> get_value() again -- 3+ file parses per model-settings resolution.
  • The file's own comment at line ~200 admits get_global_model_name() "happens a LOT" -- which is why a _SESSION_MODEL cache was bolted on for that one key, but the underlying problem remains for everything else.

Why it matters

Dozens of redundant open()+parse syscalls per agent turn. The same pattern also creates a read-modify-write race in set_config_value()/set_model_name() (read file -> mutate -> rewrite whole file): two concurrent writers on different keys can silently drop one write.

Suggested fix

Cache the parsed config with mtime invalidation:

_cfg_cache: tuple[int, configparser.ConfigParser] | None = None

def _load_config() -> configparser.ConfigParser:
    global _cfg_cache
    try:
        mtime = os.stat(CONFIG_FILE).st_mtime_ns
    except OSError:
        mtime = -1
    if _cfg_cache is None or _cfg_cache[0] != mtime:
        cfg = configparser.ConfigParser()
        cfg.read(CONFIG_FILE)
        _cfg_cache = (mtime, cfg)
    return _cfg_cache[1]

def get_value(key: str) -> Optional[str]:
    return _load_config().get(DEFAULT_SECTION, key, fallback=None)

Writers (set_config_value, reset_value, clear_model_settings, set_model_name) should invalidate the cache after writing, ideally behind a single threading.Lock to also fix the read-modify-write race.

Filed by Zen Reviewer A (code-puppy-60635a)

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Read code_puppy/config.py around get_value, set_config_value, reset_value, clear_model_settings, and set_model_name. Trace how reads and read-modify-write updates interact, then implement cache invalidation and synchronization so repeated getters avoid redundant parsing and concurrent writers do not lose updates.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
performance, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.