Skip to content

fix(research): survive the #137 config layout, and anchor the flag rewrite - #1398

Open
TimeToBuildBob wants to merge 1 commit into
ActivityWatch:masterfrom
TimeToBuildBob:fix/re-patch-config-shape
Open

fix(research): survive the #137 config layout, and anchor the flag rewrite#1398
TimeToBuildBob wants to merge 1 commit into
ActivityWatch:masterfrom
TimeToBuildBob:fix/re-patch-config-shape

Conversation

@TimeToBuildBob

Copy link
Copy Markdown
Contributor

Two defects in scripts/patch_research_edition_config.py, both introduced by the interaction with ActivityWatch/aw-watcher-window#137. Neither is visible today, and both fire on the next submodule bump.

#137 itself is right — moving research knobs out of default_config stops them being persisted into the config of every user who is not in a study. It just removes the two TOML table headers this script anchors on.

1. Injection breaks on the next submodule bump

patch_config() requires exactly one [aw-watcher-window.research_category_map] and one [aw-watcher-window.research_app_category_map] header. Past #137 neither exists, so the script aborts and the Research Edition build fails.

Verified against both revisions of aw_watcher_window/config.py:

submodule sha category header app header
a297914 (#136 merge — the current pin) 1 1
a7690ac (aw-watcher-window master, #137) 0 0

So the build works today purely because the pin has not moved. Anything that advances it — including a routine dependabot submodule bump — breaks it. The fail-closed message would then misdiagnose the cause as "submodule predates #136", which is the opposite of what happened.

2. The flag rewrite could silently disable the Research Edition

#137 documents the release-time rewrite in a comment containing the literal text:

#   sed -i 's/^research_enabled = false$/research_enabled = true/'

That comment sits above the real flag. The existing unanchored text.replace(enabled_line, ..., 1) therefore rewrites the comment and leaves research_enabled = false.

That failure has no error and no failed step. It ships a signed Research Edition installer with the privacy filter off — to study participants. This is the one I'd want a second pair of eyes on.

Fix

  • Both layouts handled. Post-Wakatime supports browsers #137 the maps are injected into research_defaults with unprefixed headers — that template is parsed standalone and merged into the [aw-watcher-window] section key by key, so a prefixed header would create a nested aw-watcher-window key that nothing reads. Pre-Wakatime supports browsers #137 the existing prefixed headers are used, unchanged.
  • Flag rewrite is line-anchored via re.MULTILINE, matching the contract Wakatime supports browsers #137's own comment documents. It refuses to proceed on anything other than exactly one match rather than guessing.
  • The pre-Add API endpoint for removing events #136 guard now keys on the runtime lookup config.get("research_app_category_map" instead of a table header. That tests the capability that actually matters — whether the watcher can consume an app map — and survives further reshuffling of the config templates.

Verification

Against the two real config.py revisions, not just synthetic fixtures — both yield research_enabled = true, 570 category patterns, 72 app entries, and output that parses as valid Python and valid TOML.

Test suite rewritten to cover both layouts (7 tests, passing), including a regression test asserting the sed-example comment survives while the real flag flips. The previous fixtures omitted the runtime lookup that real config.py always has, which is why they did not catch this.

Context

This is on the critical path for a Lund University study build promised this week. Related: aw-watcher-window#136, #137, and #1397.

…r the flag rewrite

aw-watcher-window#137 moved the research knobs out of `default_config` into a
separate `research_defaults` template, so they stop being persisted into every
fresh install's config file. That is the right fix, but it removes both TOML
table headers the Research Edition patch script anchors on. Two defects follow.

1. Injection breaks on the next submodule bump.

   `patch_config()` requires exactly one
   `[aw-watcher-window.research_category_map]` and one
   `[aw-watcher-window.research_app_category_map]` header. Neither exists past
   ActivityWatch#137, so the script aborts and the Research Edition build fails. The pin is
   currently a297914 (the ActivityWatch#136 merge), where both headers still exist -- so the
   build works today and breaks the moment anything, including a dependabot
   submodule bump, moves it forward.

   The fail-closed message would also misdiagnose it as 'submodule predates
   ActivityWatch#136' when the real cause is the opposite.

2. The flag rewrite could silently disable the Research Edition.

   ActivityWatch#137 documents the release-time rewrite in a comment containing the literal
   text `sed -i 's/^research_enabled = false$/research_enabled = true/'`, and
   that comment sits *above* the real flag. The unanchored
   `text.replace(..., 1)` therefore patches the comment and leaves
   `research_enabled = false`, producing a green build with research disabled
   and no error anywhere.

Both layouts are now handled: post-ActivityWatch#137 the maps are injected into
`research_defaults` with unprefixed headers (that template is parsed standalone
and merged into the section key by key, so a prefixed header would create a
nested key nothing reads); pre-ActivityWatch#137 the existing prefixed headers are used. The
flag rewrite is line-anchored via regex, matching the contract ActivityWatch#137's own
comment documents, and refuses to guess if it finds anything other than exactly
one match.

The pre-ActivityWatch#136 guard now keys on the runtime lookup
`config.get("research_app_category_map"` rather than a table header, so it
tests the capability that actually matters and survives further reshuffling of
the config templates.

Verified against both real config.py revisions: 570 category patterns and 72 app
entries inject correctly, and the output parses as Python and as TOML in each.
@greptile-apps

greptile-apps Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR updates the Research Edition configuration patcher to support both watcher configuration layouts while safely targeting the effective feature flag.

  • Anchors the research_enabled rewrite and fails closed on missing or ambiguous matches.
  • Injects category maps into either the legacy prefixed tables or the post-Wakatime supports browsers #137 standalone defaults template.
  • Replaces layout-dependent app-map validation with a runtime-lookup capability marker.
  • Expands tests across both layouts, TOML/Python parsing, comment preservation, and failure paths.

Confidence Score: 5/5

The PR appears safe to merge, with no concrete blocking or non-blocking defects identified in the changed paths.

The patcher validates the unique effective flag and required app-map capability before handling each known configuration layout, while the expanded tests cover successful output and relevant failure modes.

Important Files Changed

Filename Overview
scripts/patch_research_edition_config.py Adds anchored flag replacement, runtime capability validation, and layout-aware map injection without an established actionable defect.
scripts/tests/test_patch_research_edition_config.py Reworks fixtures and assertions to validate both layouts, parsed output, comment preservation, and fail-closed behavior.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Research Edition build] --> B[Load watcher config.py]
  B --> C{Exactly one anchored disabled flag?}
  C -->|No| X[Fail build]
  C -->|Yes| D{App-map runtime lookup present?}
  D -->|No| X
  D -->|Yes| E{research_defaults template present?}
  E -->|Yes| F[Enable flag and inject unprefixed maps]
  E -->|No| G[Validate legacy prefixed tables]
  G -->|Invalid| X
  G -->|Valid| H[Enable flag and populate prefixed maps]
  F --> I[Write patched watcher config]
  H --> I
Loading

Reviews (1): Last reviewed commit: "fix(research): survive the #137 config l..." | Re-trigger Greptile

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant