Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3fc0b4b

Browse files
feat: implement proactive roaming radar and network-throttled drift detection (#48)
Shifts remote divergence detection from reactive CLI polling to a proactive background daemon interrupt. The daemon now actively monitors the remote topology and fires OS-level notifications to prevent local entropy generation during distributed handoffs. - Refactor `get_remote_drift_state` out of the CLI presentation layer and into `ops.py` for shared internal use. - Implement atomic file I/O (`get_drift_state`, `set_drift_state`) using `os.replace` and `os.fsync` for cross-process state caching. - Integrate a 15-minute throttled network fetch into the `daemon.py` core loop, gated by battery limits and TCP reachability. - Add notification fatigue prevention by tracking the latest warned remote timestamp. - Migrate and expand test coverage in `test_ops.py` and `test_daemon.py`. - Update architecture documentation and Phase 2 roadmap.
1 parent e21626e commit 3fc0b4b

9 files changed

Lines changed: 462 additions & 241 deletions

File tree

README.md

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
>
1313
> **Git Pulsar decouples them. It is a background daemon that provides high-frequency, out-of-band state capture, ensuring your work is immutable and recoverable without polluting your project history.**
1414
15-
### 📡 The Mission: Decoupling Signal from Noise
15+
## 📡 The Mission: Decoupling Signal from Noise
16+
1617
In a typical workflow, developers are forced to make "WIP" commits just to switch machines or save their progress. This introduces **entropy** into the commit log, requiring complex interactive rebases to clean up later.
1718

1819
**Git Pulsar** treats the working directory state as a continuous stream of data. It captures this "noise" in a dedicated namespace (`refs/heads/wip/...`), keeping your primary branch purely focused on "signal" (logical units of work).
@@ -28,21 +29,24 @@ In a typical workflow, developers are forced to make "WIP" commits just to switc
2829

2930
---
3031

31-
### ⚙️ Engineering Philosophy: Non-Blocking Determinism
32+
## ⚙️ Engineering Philosophy: Non-Blocking Determinism
3233

3334
This system is designed to operate safely alongside standard Git commands without race conditions or index locking.
3435

35-
#### 1. Out-of-Band Indexing (The "Shadow" Index)
36+
### 1. Out-of-Band Indexing (The "Shadow" Index)
37+
3638
Most autosave tools aggressively run `git add .`, which destroys the user's carefully staged partial commits.
3739
* **The Invariant:** The user's `.git/index` must never be touched by the daemon.
3840
* **The Implementation:** Pulsar sets the `GIT_INDEX_FILE` environment variable to a temporary location (`.git/pulsar_index`). It constructs the tree object using low-level plumbing commands (`git write-tree`), bypassing the porcelain entirely. This ensures **Zero-Interference** with your active workflow.
3941

40-
#### 2. Distributed State Reconciliation (The "Zipper" Graph)
42+
### 2. Distributed State Reconciliation (The "Zipper" Graph)
43+
4144
In a distributed environment (Laptop ↔ Desktop), state drift is inevitable.
4245
* **The Mechanism:** Pulsar maintains a separate refspec for each machine ID.
4346
* **The Topology:** When you run `git pulsar finalize`, the engine performs an **Octopus Merge**, traversing the DAG (Directed Acyclic Graph) of all machine streams and squashing them into a single, clean commit on `main`.
4447

45-
#### 3. Fault Tolerance
48+
### 3. Fault Tolerance
49+
4650
* **The Problem:** Laptops die. SSH connections drop.
4751
* **The Solution:** By decoupling commits from pushes, Pulsar can capture local state every few minutes while conserving battery by pushing to the remote at a lower frequency (e.g., hourly). This guarantees that the **Mean Time To Recovery (MTTR)** is minimized regardless of network availability or hardware failure.
4852

@@ -52,20 +56,22 @@ In a distributed environment (Laptop ↔ Desktop), state drift is inevitable.
5256

5357
* **Decoupled Cycles:** Independent intervals for local commits and remote pushes. Save your battery while staying protected.
5458
* **Smart Identity:** Automatically detects naming collisions with other devices on the remote, ensuring unique backup streams for every machine.
59+
* **Roaming Radar:** The background daemon actively polls for topological drift, firing a cross-platform OS notification if another machine leapfrogs your local session so you can `sync` before conflicts arise.
5560
* **Out-of-Band Indexing:** Backups are stored in a configured namespace (default: `refs/heads/wip/pulsar/...`). Your `git status`, `git branch`, and `git log` remain completely clean.
5661
* **Distributed Sessions:** Hop between machines. Pulsar tracks sessions per device and lets you `sync` to pick up exactly where you left off.
5762
* **State-Aware Diagnostics:** The `doctor` command correlates transient log events with active system health to prevent alert fatigue, and proactively scans for pipeline blockers like strict git hooks or broken `systemd` configurations.
5863
* **Zero-Interference:**
59-
* Uses a temporary index so it never messes up your partial `git add`.
60-
* Detects if you are rebasing or merging and waits for you to finish.
61-
* Prevents accidental upload of large binaries (configurable threshold).
64+
* Uses a temporary index so it never messes up your partial `git add`.
65+
* Detects if you are rebasing or merging and waits for you to finish.
66+
* Prevents accidental upload of large binaries (configurable threshold).
6267
* **Cascading Config:** Settings are merged from global defaults, `~/.config/git-pulsar/config.toml`, and local `pulsar.toml` or `pyproject.toml` files.
6368

6469
---
6570

6671
## 📦 Installation
6772

6873
### macOS
74+
6975
Install via Homebrew. This automatically manages the background service.
7076

7177
```bash
@@ -75,6 +81,7 @@ brew services start git-pulsar
7581
```
7682

7783
### Linux / Generic
84+
7885
Install via `uv` (or `pipx`) and use the built-in service manager to register the systemd timer.
7986

8087
```bash
@@ -90,6 +97,7 @@ git pulsar install-service --interval 300
9097
Pulsar is designed to feel like a native git command.
9198

9299
### 1. Initialize & Identify
100+
93101
Navigate to your project. The first time you run Pulsar, it will register the repo, **check for naming collisions**, and start the background protection loop.
94102

95103
```bash
@@ -99,15 +107,18 @@ git pulsar
99107
*The daemon will now silently snapshot your work based on your configured intervals.*
100108

101109
### 2. Configure Your Intensity
110+
102111
Need high-frequency protection for a critical project? Set a preset or fine-tune the intervals in your project root.
103112

104-
**pulsar.toml**
113+
#### pulsar.toml
114+
105115
```toml
106116
[daemon]
107117
preset = "paranoid" # 5min commits, 5min pushes
108118
```
109119

110120
### 3. The "Session Handoff" (Sync)
121+
111122
You worked on your **Desktop** all night but forgot to push manually. You open your **Laptop** at class.
112123

113124
```bash
@@ -116,6 +127,7 @@ git pulsar sync
116127
*Pulsar checks the remote, finds the newer session from `desktop`, and fast-forwards your working directory to match it.*
117128

118129
### 4. Restore a File
130+
119131
Mess up a script? Grab the version from your last shadow commit.
120132

121133
```bash
@@ -124,6 +136,7 @@ git pulsar restore src/main.py
124136
```
125137

126138
### 5. Finalize Your Work
139+
127140
When you are ready to submit or merge to `main`:
128141

129142
```bash
@@ -143,17 +156,18 @@ git pulsar --env
143156

144157
This bootstraps the current directory with:
145158

146-
- **uv:** Initializes a project with fast package management and Python 3.12+ pinning.
159+
* **uv:** Initializes a project with fast package management and Python 3.12+ pinning.
147160

148-
- **direnv:** Creates an .envrc for auto-activating virtual environments and hooking into the shell.
161+
* **direnv:** Creates an .envrc for auto-activating virtual environments and hooking into the shell.
149162

150-
- **VS Code:** Generates a .vscode/settings.json pre-configured to exclude build artifacts and use the local venv.
163+
* **VS Code:** Generates a .vscode/settings.json pre-configured to exclude build artifacts and use the local venv.
151164

152165
---
153166

154167
## 🛠 Command Reference
155168

156169
### Backup Management
170+
157171
| Command | Description |
158172
| :--- | :--- |
159173
| `git pulsar` | **Default.** Registers the current repo and ensures the daemon is watching it. |
@@ -164,6 +178,7 @@ This bootstraps the current directory with:
164178
| `git pulsar finalize` | Squash-merge all backup streams into `main`. |
165179

166180
### Repository Control
181+
167182
| Command | Description |
168183
| :--- | :--- |
169184
| `git pulsar status` | Show detailed daemon state and repository-specific commit/push history. |
@@ -175,13 +190,15 @@ This bootstraps the current directory with:
175190
| `git pulsar ignore <glob>` | Add a pattern to `.gitignore` (and untrack it if needed). |
176191

177192
### Maintenance
193+
178194
| Command | Description |
179195
| :--- | :--- |
180196
| `git pulsar doctor` | Run state-aware diagnostics (logs, repo health, drift detection, hook interference) and clean up the registry. |
181197
| `git pulsar prune` | Delete old backup history (>30 days). Runs automatically weekly. |
182198
| `git pulsar log` | View recent log history (last 1000 lines) and tail new entries. |
183199

184200
### Service
201+
185202
| Command | Description |
186203
| :--- | :--- |
187204
| `git pulsar install-service` | Register the background daemon (LaunchAgent/Systemd). |
@@ -194,14 +211,16 @@ This bootstraps the current directory with:
194211
Settings cascade from Global → Local. Local list options (like `ignore`) append to global ones.
195212

196213
### Options
214+
197215
| Section | Key | Default | Description |
198216
| :--- | :--- | :--- | :--- |
199217
| `daemon` | `preset` | `None` | Use `paranoid`, `aggressive`, `balanced`, or `lazy`. |
200218
| `daemon` | `commit_interval` | `600` | Seconds between local state captures. |
201219
| `daemon` | `push_interval` | `3600` | Seconds between remote pushes. |
202-
| `limits` | `large_file_threshold`| `100MB` | Max file size before aborting a backup. |
220+
| `limits` | `large_file_threshold` | `100MB` | Max file size before aborting a backup. |
203221

204222
### Example `~/.config/git-pulsar/config.toml`
223+
205224
```toml
206225
[daemon]
207226
preset = "balanced"
@@ -219,26 +238,28 @@ ignore = ["*.tmp", "node_modules/"]
219238

220239
*Focus: Turning the tool from a blind script into a helpful partner that negotiates with you.*
221240

222-
- [ ] **Smart Restore:** Replace hard failures on "dirty" files with a negotiation menu (Overwrite / View Diff / Cancel).
223-
- [ ] **Pre-Flight Checklists:** Display a summary table of incoming changes (machines, timestamps, file counts) before running destructive commands like `finalize`.
224-
- [ ] **Active Doctor:** Upgrade `git pulsar doctor` to not just diagnose issues (like stopped daemons), but offer to auto-fix them interactively.
241+
* [ ] **Smart Restore:** Replace hard failures on "dirty" files with a negotiation menu (Overwrite / View Diff / Cancel).
242+
* [ ] **Pre-Flight Checklists:** Display a summary table of incoming changes (machines, timestamps, file counts) before running destructive commands like `finalize`.
243+
* [ ] **Active Doctor:** Upgrade `git pulsar doctor` to not just diagnose issues (like stopped daemons), but offer to auto-fix them interactively.
225244

226245
### Phase 2: "Deep Thought" (Context & Intelligence)
227246

228247
*Focus: Leveraging data to make the tool feel alive and aware of your workflow.*
229248

230-
- [ ] **Semantic Shadow Logs:** Replace generic "Shadow backup" messages with auto-generated summaries (e.g., `backup: modified daemon.py (+15 lines)`).
231-
- [x] **Roaming Radar:** Proactively detect if a different machine has pushed newer work to the same branch and notify the user to `sync`.
232-
- [ ] **Decaying Retention:** Implement "Grandfather-Father-Son" pruning (keep all hourly backups for 24h, then daily summaries) to balance safety with disk space.
249+
* [ ] **Semantic Shadow Logs:** Replace generic "Shadow backup" messages with auto-generated summaries (e.g., `backup: modified daemon.py (+15 lines)`).
250+
* [x] **Roaming Radar:** Proactively detect if a different machine has pushed newer work to the same branch and notify the user to `sync`.
251+
* [ ] **Decaying Retention:** Implement "Grandfather-Father-Son" pruning (keep all hourly backups for 24h, then daily summaries) to balance safety with disk space.
233252

234253
### Phase 3: The "TUI" Experience (Visuals)
254+
235255
*Focus: Making the invisible backup history tangible and explorable.*
236-
- [ ] **Time Machine UI:** A terminal-based visual browser for `git pulsar restore` that lets you scroll through file history and view side-by-side diffs.
237-
- [ ] **Universal Bootstrap:** Expand `git pulsar --env` to support Linux (apt/dnf) environments alongside macOS.
256+
* [ ] **Time Machine UI:** A terminal-based visual browser for `git pulsar restore` that lets you scroll through file history and view side-by-side diffs.
257+
* [ ] **Universal Bootstrap:** Expand `git pulsar --env` to support Linux (apt/dnf) environments alongside macOS.
238258

239259
### Future Horizons
240-
- [ ] **End-to-End Encryption:** Optional GPG encryption for shadow commits.
241-
- [ ] **Windows Support:** Native support for PowerShell and Task Scheduler.
260+
261+
* [ ] **End-to-End Encryption:** Optional GPG encryption for shadow commits.
262+
* [ ] **Windows Support:** Native support for PowerShell and Task Scheduler.
242263

243264
---
244265

src/README.md

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,41 +5,45 @@ The `src/` directory contains the package source code. The architecture strictly
55
## Module Map
66

77
### 1. The Core Loop (State Management)
8+
89
* **`git_pulsar/daemon.py`**: The background process.
9-
* **Role:** The "Heartbeat." It wakes up, checks system constraints (Battery, CPU Load), and triggers the backup logic.
10-
* **Logic:** Decouples "Saving" (Commit) from "Publishing" (Push) using independent intervals to optimize for battery life.
11-
* **Safety:** Implements `GIT_INDEX_FILE` isolation to ensure it never locks or corrupts the user's active git index.
10+
* **Role:** The "Heartbeat." It wakes up, checks system constraints (Battery, CPU Load), and triggers the backup logic.
11+
* **Logic:** Decouples "Saving" (Commit) from "Publishing" (Push) using independent intervals to optimize for battery life. Incorporates the "Roaming Radar" to poll for remote drift asynchronously.
12+
* **Safety:** Implements `GIT_INDEX_FILE` isolation to ensure it never locks or corrupts the user's active git index.
1213
* **`git_pulsar/ops.py`**: High-level Business Logic.
13-
* **Role:** The "Controller." It orchestrates complex multi-step operations like `finalize` (Octopus Merges) and `restore`.
14-
* **Logic:** Calculates the "Zipper Graph" topology to merge shadow commits back into the main branch.
14+
* **Role:** The "Controller." It orchestrates complex multi-step operations like `finalize` (Octopus Merges), `restore`, and drift detection.
15+
* **Logic:** Calculates the "Zipper Graph" topology to merge shadow commits back into the main branch, and manages atomic file I/O for cross-process state tracking.
1516
* **`git_pulsar/config.py`**: Configuration Engine.
16-
* **Role:** The "Source of Truth."
17-
* **Logic:** Implements a cascading hierarchy (Defaults → Global → Local) to merge settings from `~/.config/git-pulsar/config.toml` and project-level `pulsar.toml` or `pyproject.toml`.
17+
* **Role:** The "Source of Truth."
18+
* **Logic:** Implements a cascading hierarchy (Defaults → Global → Local) to merge settings from `~/.config/git-pulsar/config.toml` and project-level `pulsar.toml` or `pyproject.toml`.
1819

1920
### 2. The Abstraction Layer (Plumbing)
21+
2022
* **`git_pulsar/git_wrapper.py`**: The Git Interface.
21-
* **Role:** A strict wrapper around `subprocess`.
22-
* **Philosophy:** **No Porcelain.** This module primarily uses git *plumbing* commands (`write-tree`, `commit-tree`, `update-ref`) rather than user-facing commands (`commit`, `add`) to ensure deterministic behavior.
23+
* **Role:** A strict wrapper around `subprocess`.
24+
* **Philosophy:** **No Porcelain.** This module primarily uses git *plumbing* commands (`write-tree`, `commit-tree`, `update-ref`) rather than user-facing commands (`commit`, `add`) to ensure deterministic behavior.
2325
* **`git_pulsar/system.py`**: OS Abstraction.
24-
* **Role:** Identity & Environment.
25-
* **Logic:** Handles the chaos of cross-platform identity (mapping `IOPlatformUUID` on macOS vs `/etc/machine-id` on Linux) to ensure stable "Roaming Profiles."
26+
* **Role:** Identity & Environment.
27+
* **Logic:** Handles the chaos of cross-platform identity (mapping `IOPlatformUUID` on macOS vs `/etc/machine-id` on Linux) to ensure stable "Roaming Profiles."
2628

2729
### 3. Service Management (Lifecycle)
30+
2831
* **`git_pulsar/service.py`**: The Installation Engine.
29-
* **Role:** Interface with the host init system.
30-
* **Logic:** Generates and registers `systemd` user timers (Linux) or instructions for `launchd` (macOS/Homebrew).
32+
* **Role:** Interface with the host init system.
33+
* **Logic:** Generates and registers `systemd` user timers (Linux) or instructions for `launchd` (macOS/Homebrew).
3134

3235
### 4. The Interface
36+
3337
* **`git_pulsar/cli.py`**: The User Entry Point & Diagnostic Engine.
34-
* **Role:** Argument parsing, UI rendering, and system health evaluation.
35-
* **Logic:** Uses `rich` for terminal visualization. Beyond routing subcommands to `ops.py` and `daemon.py`, it houses the `doctor` logic. It correlates repository state against transient event logs, detects topological drift across distributed sessions, and scans for host-environment pipeline blockers (e.g., strict git hooks, missing `systemd` linger).
38+
* **Role:** Argument parsing, UI rendering, and system health evaluation.
39+
* **Logic:** Uses `rich` for terminal visualization. Beyond routing subcommands to `ops.py` and `daemon.py`, it presents the `doctor` diagnostics. It correlates repository state against transient event logs, and relies on `ops.py` to evaluate topological drift across distributed sessions and scan for host-environment pipeline blockers (e.g., strict git hooks, missing `systemd` linger).
3640

3741
---
3842

3943
## Key Invariants
4044

41-
1. **Index Isolation:** The `daemon` module MUST ALWAYS set `os.environ["GIT_INDEX_FILE"]` to a temporary path before performing write operations.
42-
2. **Zero-Destruction:** The `prune` logic in `ops.py` relies on strictly namespaced refspecs (`refs/heads/wip/pulsar/...`) and never touches standard heads.
43-
3. **Identity Stability:** The `system` module guarantees that a Machine ID persists across reboots, preventing "Split Brain" backup histories.
44-
4. **Configuration Precedence:** Local project configuration MUST always override global user settings to ensure repo-specific constraints (e.g., large file limits) are respected.
45-
5. **State Over Events:** The diagnostic engine (`cli.py`) MUST prioritize current repository and environmental state over historical log events to prevent alert fatigue from self-healing anomalies.
45+
1. **Index Isolation:** The `daemon` module MUST ALWAYS set `os.environ["GIT_INDEX_FILE"]` to a temporary path before performing write operations.
46+
2. **Zero-Destruction:** The `prune` logic in `ops.py` relies on strictly namespaced refspecs (`refs/heads/wip/pulsar/...`) and never touches standard heads.
47+
3. **Identity Stability:** The `system` module guarantees that a Machine ID persists across reboots, preventing "Split Brain" backup histories.
48+
4. **Configuration Precedence:** Local project configuration MUST always override global user settings to ensure repo-specific constraints (e.g., large file limits) are respected.
49+
5. **State Over Events:** The diagnostic engine (`cli.py`) MUST prioritize current repository and environmental state over historical log events to prevent alert fatigue from self-healing anomalies.

0 commit comments

Comments
 (0)