gitgrip 1.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gitgrip-1.5.0.dist-info/METADATA +13 -0
- gitgrip-1.5.0.dist-info/RECORD +80 -0
- gitgrip-1.5.0.dist-info/WHEEL +5 -0
- gitgrip-1.5.0.dist-info/entry_points.txt +2 -0
- gitgrip-1.5.0.dist-info/top_level.txt +2 -0
- gr2/__init__.py +0 -0
- gr2/overlay/__init__.py +6 -0
- gr2/overlay/activate.py +196 -0
- gr2/overlay/agent_manifest.py +138 -0
- gr2/overlay/cli.py +181 -0
- gr2/overlay/cross_repo.py +124 -0
- gr2/overlay/drivers.py +113 -0
- gr2/overlay/introspection.py +155 -0
- gr2/overlay/language_drivers.py +115 -0
- gr2/overlay/objects.py +412 -0
- gr2/overlay/perf.py +251 -0
- gr2/overlay/refs.py +36 -0
- gr2/overlay/trust.py +150 -0
- gr2/overlay/types.py +69 -0
- gr2/overlay/units.py +313 -0
- gr2/overlay/workspace_spec.py +59 -0
- gr2/prototypes/__init__.py +0 -0
- gr2/prototypes/cache_materialization_probe.py +190 -0
- gr2/prototypes/concurrent_event_stress.py +199 -0
- gr2/prototypes/concurrent_lease_stress.py +240 -0
- gr2/prototypes/concurrent_workspace_cap_stress.py +231 -0
- gr2/prototypes/contribution_protocol.py +665 -0
- gr2/prototypes/cross_mode_lane_stress.py +986 -0
- gr2/prototypes/jsonl_store.py +158 -0
- gr2/prototypes/lane_workspace_prototype.py +2088 -0
- gr2/prototypes/layout_model_probe.py +139 -0
- gr2/prototypes/propagation_daemon.py +546 -0
- gr2/prototypes/propagation_state_machine.py +1478 -0
- gr2/prototypes/python_exec_playground.py +194 -0
- gr2/prototypes/python_hook_runtime_playground.py +240 -0
- gr2/prototypes/python_migration_playground.py +144 -0
- gr2/prototypes/python_review_checkout_playground.py +242 -0
- gr2/prototypes/python_spec_apply_playground.py +282 -0
- gr2/prototypes/real_git_lane_materialization.py +248 -0
- gr2/prototypes/real_git_playground.py +334 -0
- gr2/prototypes/recall_lane_history.py +274 -0
- gr2/prototypes/repo_maintenance_prototype.py +659 -0
- gr2/prototypes/repo_transport_probe.py +147 -0
- gr2/python_cli/__init__.py +2 -0
- gr2/python_cli/__main__.py +6 -0
- gr2/python_cli/add.py +51 -0
- gr2/python_cli/app.py +2516 -0
- gr2/python_cli/branch.py +67 -0
- gr2/python_cli/channel_bridge.py +131 -0
- gr2/python_cli/clone_exec.py +1019 -0
- gr2/python_cli/commit.py +199 -0
- gr2/python_cli/config.py +291 -0
- gr2/python_cli/env_exec.py +419 -0
- gr2/python_cli/events.py +529 -0
- gr2/python_cli/execops.py +372 -0
- gr2/python_cli/failures.py +98 -0
- gr2/python_cli/file_exec.py +256 -0
- gr2/python_cli/gitops.py +226 -0
- gr2/python_cli/grip.py +1337 -0
- gr2/python_cli/grip_cli.py +493 -0
- gr2/python_cli/hooks.py +450 -0
- gr2/python_cli/launch_exec.py +786 -0
- gr2/python_cli/merge_verification.py +274 -0
- gr2/python_cli/migration.py +985 -0
- gr2/python_cli/open_gr_review.py +699 -0
- gr2/python_cli/platform.py +441 -0
- gr2/python_cli/pr.py +487 -0
- gr2/python_cli/project_review.py +314 -0
- gr2/python_cli/prune.py +365 -0
- gr2/python_cli/push.py +172 -0
- gr2/python_cli/review.py +462 -0
- gr2/python_cli/review_ephemeral.py +143 -0
- gr2/python_cli/review_run.py +621 -0
- gr2/python_cli/spec_apply.py +1285 -0
- gr2/python_cli/staging_cleanup.py +205 -0
- gr2/python_cli/syncops.py +920 -0
- gr2/python_cli/target.py +100 -0
- gr2/python_cli/workspace_snapshot.py +105 -0
- gr2/schemas/gr2-materialization-plan-v1.schema.json +191 -0
- gr2_overlay/__init__.py +37 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Repeated stress harness for the workspace-wide edit-lease cap."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import json
|
|
8
|
+
import multiprocessing
|
|
9
|
+
import os
|
|
10
|
+
import subprocess
|
|
11
|
+
import tempfile
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def parse_args() -> argparse.Namespace:
|
|
16
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
17
|
+
parser.add_argument("--rounds", type=int, default=20)
|
|
18
|
+
parser.add_argument("--json", action="store_true")
|
|
19
|
+
return parser.parse_args()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def repo_root() -> Path:
|
|
23
|
+
return Path(__file__).resolve().parents[2]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def lane_proto(root: Path) -> Path:
|
|
27
|
+
return root / "gr2" / "prototypes" / "lane_workspace_prototype.py"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _run(argv: list[str], *, env: dict[str, str] | None = None) -> subprocess.CompletedProcess[str]:
|
|
31
|
+
return subprocess.run(argv, text=True, capture_output=True, env=env, check=False)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _init_workspace(workspace_root: Path) -> None:
|
|
35
|
+
(workspace_root / ".grip").mkdir(parents=True)
|
|
36
|
+
(workspace_root / "agents").mkdir()
|
|
37
|
+
(workspace_root / ".grip" / "workspace_spec.toml").write_text(
|
|
38
|
+
"""schema_version = 1
|
|
39
|
+
workspace_name = "workspace-cap-stress"
|
|
40
|
+
|
|
41
|
+
[cache]
|
|
42
|
+
root = ".grip/cache"
|
|
43
|
+
|
|
44
|
+
[workspace_constraints]
|
|
45
|
+
max_concurrent_edit_leases_global = 1
|
|
46
|
+
|
|
47
|
+
[[repos]]
|
|
48
|
+
name = "app"
|
|
49
|
+
path = "repos/app"
|
|
50
|
+
url = "https://example.invalid/app.git"
|
|
51
|
+
|
|
52
|
+
[[units]]
|
|
53
|
+
name = "atlas"
|
|
54
|
+
path = "agents/atlas"
|
|
55
|
+
repos = ["app"]
|
|
56
|
+
|
|
57
|
+
[[units]]
|
|
58
|
+
name = "apollo"
|
|
59
|
+
path = "agents/apollo"
|
|
60
|
+
repos = ["app"]
|
|
61
|
+
""",
|
|
62
|
+
encoding="utf-8",
|
|
63
|
+
)
|
|
64
|
+
root = repo_root()
|
|
65
|
+
for unit, lane in (("atlas", "lane-a"), ("apollo", "lane-b")):
|
|
66
|
+
result = _run(
|
|
67
|
+
[
|
|
68
|
+
"python3",
|
|
69
|
+
str(lane_proto(root)),
|
|
70
|
+
"create-lane",
|
|
71
|
+
str(workspace_root),
|
|
72
|
+
unit,
|
|
73
|
+
lane,
|
|
74
|
+
"--repos",
|
|
75
|
+
"app",
|
|
76
|
+
"--branch",
|
|
77
|
+
f"feat/{lane}",
|
|
78
|
+
]
|
|
79
|
+
)
|
|
80
|
+
if result.returncode != 0:
|
|
81
|
+
raise RuntimeError(result.stderr or result.stdout)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _acquire_worker(
|
|
85
|
+
workspace_root: str,
|
|
86
|
+
unit: str,
|
|
87
|
+
lane: str,
|
|
88
|
+
actor: str,
|
|
89
|
+
start: object,
|
|
90
|
+
queue: object,
|
|
91
|
+
disable_locking: bool,
|
|
92
|
+
) -> None:
|
|
93
|
+
if not start.wait(timeout=10):
|
|
94
|
+
queue.put({"returncode": 99, "error": "start gate timed out"})
|
|
95
|
+
return
|
|
96
|
+
env = os.environ.copy()
|
|
97
|
+
env["GR2_WORKSPACE_CAP_TEST_DELAY"] = "0.04"
|
|
98
|
+
if disable_locking:
|
|
99
|
+
env["GR2_DISABLE_LEASE_LOCKING"] = "1"
|
|
100
|
+
env["GR2_LEASE_TEST_DELAY"] = "0.04"
|
|
101
|
+
result = _run(
|
|
102
|
+
[
|
|
103
|
+
"python3",
|
|
104
|
+
str(lane_proto(repo_root())),
|
|
105
|
+
"acquire-lane-lease",
|
|
106
|
+
workspace_root,
|
|
107
|
+
unit,
|
|
108
|
+
lane,
|
|
109
|
+
"--actor",
|
|
110
|
+
actor,
|
|
111
|
+
"--mode",
|
|
112
|
+
"edit",
|
|
113
|
+
"--ttl-seconds",
|
|
114
|
+
"900",
|
|
115
|
+
],
|
|
116
|
+
env=env,
|
|
117
|
+
)
|
|
118
|
+
queue.put(
|
|
119
|
+
{
|
|
120
|
+
"returncode": result.returncode,
|
|
121
|
+
"stdout": result.stdout,
|
|
122
|
+
"stderr": result.stderr,
|
|
123
|
+
}
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _active_edit_count(workspace_root: Path) -> int:
|
|
128
|
+
count = 0
|
|
129
|
+
for path in workspace_root.glob(".grip/state/lanes/*/*/leases.json"):
|
|
130
|
+
for lease in json.loads(path.read_text()):
|
|
131
|
+
count += lease.get("mode") == "edit"
|
|
132
|
+
return count
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _run_round(*, disable_locking: bool) -> dict[str, object]:
|
|
136
|
+
with tempfile.TemporaryDirectory(prefix="gr2-workspace-cap-") as tmp:
|
|
137
|
+
workspace_root = Path(tmp)
|
|
138
|
+
_init_workspace(workspace_root)
|
|
139
|
+
ctx = multiprocessing.get_context("spawn")
|
|
140
|
+
start = ctx.Event()
|
|
141
|
+
queue = ctx.Queue()
|
|
142
|
+
processes = [
|
|
143
|
+
ctx.Process(
|
|
144
|
+
target=_acquire_worker,
|
|
145
|
+
args=(
|
|
146
|
+
str(workspace_root),
|
|
147
|
+
unit,
|
|
148
|
+
lane,
|
|
149
|
+
f"agent:{unit}",
|
|
150
|
+
start,
|
|
151
|
+
queue,
|
|
152
|
+
disable_locking,
|
|
153
|
+
),
|
|
154
|
+
)
|
|
155
|
+
for unit, lane in (("atlas", "lane-a"), ("apollo", "lane-b"))
|
|
156
|
+
]
|
|
157
|
+
for process in processes:
|
|
158
|
+
process.start()
|
|
159
|
+
start.set()
|
|
160
|
+
for process in processes:
|
|
161
|
+
process.join(timeout=15)
|
|
162
|
+
if process.is_alive():
|
|
163
|
+
process.terminate()
|
|
164
|
+
raise RuntimeError("workspace-cap worker hung")
|
|
165
|
+
outcomes = [queue.get(timeout=2) for _ in processes]
|
|
166
|
+
active_count = _active_edit_count(workspace_root)
|
|
167
|
+
return {
|
|
168
|
+
"worker_failures": sum(row["returncode"] not in (0, 1) for row in outcomes),
|
|
169
|
+
"active_edit_count": active_count,
|
|
170
|
+
"cap_violation": active_count > 1,
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def run_phase(*, rounds: int, disable_locking: bool) -> dict[str, object]:
|
|
175
|
+
results = [_run_round(disable_locking=disable_locking) for _ in range(rounds)]
|
|
176
|
+
return {
|
|
177
|
+
"locking": "disabled" if disable_locking else "enabled",
|
|
178
|
+
"rounds": rounds,
|
|
179
|
+
"cap_violation_rounds": sum(bool(row["cap_violation"]) for row in results),
|
|
180
|
+
"worker_failure_rounds": sum(bool(row["worker_failures"]) for row in results),
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def sequential_control() -> dict[str, object]:
|
|
185
|
+
with tempfile.TemporaryDirectory(prefix="gr2-workspace-cap-sequential-") as tmp:
|
|
186
|
+
workspace_root = Path(tmp)
|
|
187
|
+
_init_workspace(workspace_root)
|
|
188
|
+
outcomes = []
|
|
189
|
+
for unit, lane in (("atlas", "lane-a"), ("apollo", "lane-b")):
|
|
190
|
+
outcomes.append(
|
|
191
|
+
_run(
|
|
192
|
+
[
|
|
193
|
+
"python3",
|
|
194
|
+
str(lane_proto(repo_root())),
|
|
195
|
+
"acquire-lane-lease",
|
|
196
|
+
str(workspace_root),
|
|
197
|
+
unit,
|
|
198
|
+
lane,
|
|
199
|
+
"--actor",
|
|
200
|
+
f"agent:{unit}",
|
|
201
|
+
"--mode",
|
|
202
|
+
"edit",
|
|
203
|
+
]
|
|
204
|
+
).returncode
|
|
205
|
+
)
|
|
206
|
+
active_count = _active_edit_count(workspace_root)
|
|
207
|
+
return {
|
|
208
|
+
"returncodes": outcomes,
|
|
209
|
+
"active_edit_count": active_count,
|
|
210
|
+
"cap_violation": active_count > 1,
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def main() -> int:
|
|
215
|
+
args = parse_args()
|
|
216
|
+
payload = {
|
|
217
|
+
"sequential_control": sequential_control(),
|
|
218
|
+
"before_workspace_lock": run_phase(rounds=args.rounds, disable_locking=True),
|
|
219
|
+
"after_workspace_lock": run_phase(rounds=args.rounds, disable_locking=False),
|
|
220
|
+
}
|
|
221
|
+
print(json.dumps(payload, indent=2))
|
|
222
|
+
after = payload["after_workspace_lock"]
|
|
223
|
+
return int(
|
|
224
|
+
payload["sequential_control"]["cap_violation"]
|
|
225
|
+
or after["cap_violation_rounds"] != 0
|
|
226
|
+
or after["worker_failure_rounds"] != 0
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
if __name__ == "__main__":
|
|
231
|
+
raise SystemExit(main())
|