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.
Files changed (80) hide show
  1. gitgrip-1.5.0.dist-info/METADATA +13 -0
  2. gitgrip-1.5.0.dist-info/RECORD +80 -0
  3. gitgrip-1.5.0.dist-info/WHEEL +5 -0
  4. gitgrip-1.5.0.dist-info/entry_points.txt +2 -0
  5. gitgrip-1.5.0.dist-info/top_level.txt +2 -0
  6. gr2/__init__.py +0 -0
  7. gr2/overlay/__init__.py +6 -0
  8. gr2/overlay/activate.py +196 -0
  9. gr2/overlay/agent_manifest.py +138 -0
  10. gr2/overlay/cli.py +181 -0
  11. gr2/overlay/cross_repo.py +124 -0
  12. gr2/overlay/drivers.py +113 -0
  13. gr2/overlay/introspection.py +155 -0
  14. gr2/overlay/language_drivers.py +115 -0
  15. gr2/overlay/objects.py +412 -0
  16. gr2/overlay/perf.py +251 -0
  17. gr2/overlay/refs.py +36 -0
  18. gr2/overlay/trust.py +150 -0
  19. gr2/overlay/types.py +69 -0
  20. gr2/overlay/units.py +313 -0
  21. gr2/overlay/workspace_spec.py +59 -0
  22. gr2/prototypes/__init__.py +0 -0
  23. gr2/prototypes/cache_materialization_probe.py +190 -0
  24. gr2/prototypes/concurrent_event_stress.py +199 -0
  25. gr2/prototypes/concurrent_lease_stress.py +240 -0
  26. gr2/prototypes/concurrent_workspace_cap_stress.py +231 -0
  27. gr2/prototypes/contribution_protocol.py +665 -0
  28. gr2/prototypes/cross_mode_lane_stress.py +986 -0
  29. gr2/prototypes/jsonl_store.py +158 -0
  30. gr2/prototypes/lane_workspace_prototype.py +2088 -0
  31. gr2/prototypes/layout_model_probe.py +139 -0
  32. gr2/prototypes/propagation_daemon.py +546 -0
  33. gr2/prototypes/propagation_state_machine.py +1478 -0
  34. gr2/prototypes/python_exec_playground.py +194 -0
  35. gr2/prototypes/python_hook_runtime_playground.py +240 -0
  36. gr2/prototypes/python_migration_playground.py +144 -0
  37. gr2/prototypes/python_review_checkout_playground.py +242 -0
  38. gr2/prototypes/python_spec_apply_playground.py +282 -0
  39. gr2/prototypes/real_git_lane_materialization.py +248 -0
  40. gr2/prototypes/real_git_playground.py +334 -0
  41. gr2/prototypes/recall_lane_history.py +274 -0
  42. gr2/prototypes/repo_maintenance_prototype.py +659 -0
  43. gr2/prototypes/repo_transport_probe.py +147 -0
  44. gr2/python_cli/__init__.py +2 -0
  45. gr2/python_cli/__main__.py +6 -0
  46. gr2/python_cli/add.py +51 -0
  47. gr2/python_cli/app.py +2516 -0
  48. gr2/python_cli/branch.py +67 -0
  49. gr2/python_cli/channel_bridge.py +131 -0
  50. gr2/python_cli/clone_exec.py +1019 -0
  51. gr2/python_cli/commit.py +199 -0
  52. gr2/python_cli/config.py +291 -0
  53. gr2/python_cli/env_exec.py +419 -0
  54. gr2/python_cli/events.py +529 -0
  55. gr2/python_cli/execops.py +372 -0
  56. gr2/python_cli/failures.py +98 -0
  57. gr2/python_cli/file_exec.py +256 -0
  58. gr2/python_cli/gitops.py +226 -0
  59. gr2/python_cli/grip.py +1337 -0
  60. gr2/python_cli/grip_cli.py +493 -0
  61. gr2/python_cli/hooks.py +450 -0
  62. gr2/python_cli/launch_exec.py +786 -0
  63. gr2/python_cli/merge_verification.py +274 -0
  64. gr2/python_cli/migration.py +985 -0
  65. gr2/python_cli/open_gr_review.py +699 -0
  66. gr2/python_cli/platform.py +441 -0
  67. gr2/python_cli/pr.py +487 -0
  68. gr2/python_cli/project_review.py +314 -0
  69. gr2/python_cli/prune.py +365 -0
  70. gr2/python_cli/push.py +172 -0
  71. gr2/python_cli/review.py +462 -0
  72. gr2/python_cli/review_ephemeral.py +143 -0
  73. gr2/python_cli/review_run.py +621 -0
  74. gr2/python_cli/spec_apply.py +1285 -0
  75. gr2/python_cli/staging_cleanup.py +205 -0
  76. gr2/python_cli/syncops.py +920 -0
  77. gr2/python_cli/target.py +100 -0
  78. gr2/python_cli/workspace_snapshot.py +105 -0
  79. gr2/schemas/gr2-materialization-plan-v1.schema.json +191 -0
  80. 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())