claude-dev-env 8.82.1 → 8.83.1
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.
- package/.agents/skills/deepen/SKILL.md +42 -0
- package/bin/codex-skill-load-block.mjs +32 -0
- package/bin/codex-skill-load-block.test.mjs +27 -0
- package/bin/codex-trimmed-sol.test.mjs +1 -0
- package/bin/ever-shipped-skills.mjs +1 -0
- package/bin/install-pstack-plugin.mjs +12 -0
- package/bin/install-pstack-plugin.test.mjs +23 -0
- package/bin/install.agents-home.test.mjs +1 -0
- package/bin/install.codex-rules.test.mjs +2 -0
- package/bin/install.cursor-rules.test.mjs +38 -1
- package/bin/install.mjs +34 -2
- package/bin/install.prompt-context.test.mjs +3 -1
- package/bin/install.prune.test.mjs +1 -0
- package/bin/install.question-presentation.test.mjs +4 -0
- package/bin/install.settings-defaults.test.mjs +1 -0
- package/bin/install.shared-settings.test.mjs +1 -0
- package/bin/install.test.mjs +34 -1
- package/bin/install.transaction.test.mjs +8 -0
- package/bin/install.uninstall-transaction.test.mjs +2 -0
- package/bin/install.update-keeps-hooks.test.mjs +1 -0
- package/commands/deepen.md +19 -0
- package/docs/account-broker.md +1 -1
- package/docs/rule-guides/agent-board.md +27 -0
- package/docs/rule-guides/features-start-with-an-eval.md +4 -2
- package/docs/rule-guides/proof-before-pull-request.md +1 -1
- package/hooks/blocking/build_eval_before_eval_write_gate.py +102 -0
- package/hooks/blocking/pr_lifecycle_skill_gate.py +42 -16
- package/hooks/blocking/pull_request_proof.py +111 -2
- package/hooks/blocking/reply_length_gate.py +69 -13
- package/hooks/blocking/test_build_eval_before_eval_write_gate.py +162 -0
- package/hooks/blocking/test_pr_lifecycle_skill_gate.py +25 -0
- package/hooks/blocking/test_pull_request_proof.py +115 -0
- package/hooks/blocking/test_reply_length_gate.py +98 -10
- package/hooks/context_budget/tests/test_model.py +65 -0
- package/hooks/features/conduct-gates.md +4 -0
- package/hooks/features/lifecycle-cleanup.md +1 -1
- package/hooks/features/session-context.md +3 -0
- package/hooks/hooks.json +20 -0
- package/hooks/hooks_constants/build_eval_before_eval_write_gate_constants.py +19 -0
- package/hooks/hooks_constants/deepen_first_prompt_constants.py +119 -0
- package/hooks/hooks_constants/mod_handoff_constants.py +2 -0
- package/hooks/hooks_constants/nested_project_hooks_constants.py +2 -0
- package/hooks/hooks_constants/pull_request_proof_constants.py +38 -0
- package/hooks/hooks_constants/reply_length_gate_constants.py +14 -0
- package/hooks/hooks_constants/test_reply_length_gate_constants.py +8 -0
- package/hooks/lifecycle/nested_project_hooks.py +17 -8
- package/hooks/lifecycle/test_nested_project_hooks.py +50 -0
- package/hooks/session/deepen_first_prompt.py +390 -0
- package/hooks/session/test_deepen_first_prompt.py +274 -0
- package/hooks/test_transcript_skill_scan.py +6 -2
- package/hooks/transcript_skill_scan.py +18 -7
- package/package.json +1 -1
- package/rules/agent-board.md +9 -0
- package/rules/index.md +1 -1
- package/scripts/account_broker.py +1 -0
- package/scripts/account_broker_support.py +71 -24
- package/scripts/ci/install-playtest.mjs +329 -2
- package/scripts/ci/install-playtest.test.mjs +6 -0
- package/scripts/dev_env_scripts_constants/account_broker_constants.py +11 -3
- package/scripts/dev_env_scripts_constants/test_account_broker_constants.py +15 -0
- package/scripts/policy_lint/adapter_configuration.py +5 -0
- package/scripts/policy_lint/config/constants.py +1 -0
- package/scripts/test_account_broker.py +19 -1
- package/scripts/test_account_broker_support.py +161 -3
- package/scripts/tests/test_adapter_configuration.py +8 -0
- package/scripts/tests/test_rule_load_scopes.py +1 -0
|
@@ -191,6 +191,21 @@ def test_should_treat_accounts_that_differ_only_in_profile_as_one_account() -> N
|
|
|
191
191
|
assert Account(Product.CLAUDE, "first", home, profile="first") == Account(Product.CLAUDE, "first", home)
|
|
192
192
|
|
|
193
193
|
|
|
194
|
+
def test_should_wait_until_a_rate_limited_meter_may_be_probed_again() -> None:
|
|
195
|
+
now = datetime(2026, 10, 11, 19, 31, tzinfo=timezone.utc)
|
|
196
|
+
probe_again_at = now + timedelta(minutes=5)
|
|
197
|
+
account = Account(Product.CLAUDE, "second", Path("second"))
|
|
198
|
+
reading = broker_constants.Reading(account, None, "usage probe failed: HTTP Error 429", None, probe_again_at)
|
|
199
|
+
|
|
200
|
+
decision = broker_constants._wait_decision([reading], now, frozenset(), {})
|
|
201
|
+
|
|
202
|
+
assert decision.resets_at == probe_again_at
|
|
203
|
+
assert decision.reason == (
|
|
204
|
+
"no account meter could be read (second (usage probe failed: HTTP Error 429)); "
|
|
205
|
+
"next check at 2026-10-11T19:36:00+00:00"
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
|
|
194
209
|
def _codex_reading(meters: broker_constants.Meters) -> broker_constants.Reading:
|
|
195
210
|
return broker_constants.Reading(Account(Product.CODEX, "codex-1", Path("/profiles/codex-1")), meters)
|
|
196
211
|
|
|
@@ -135,6 +135,7 @@ def _names_exempt_registration_path(registered_string: str) -> bool:
|
|
|
135
135
|
hooks/blocking/verify_before_acting.py -> exempt
|
|
136
136
|
hooks/blocking/session_title_format_gate.py -> exempt
|
|
137
137
|
hooks/blocking/artifact_dark_mode_gate.py -> exempt
|
|
138
|
+
hooks/blocking/build_eval_before_eval_write_gate.py -> exempt
|
|
138
139
|
hooks/blocking/merge_over_review_offer_gate.py -> exempt
|
|
139
140
|
hooks/blocking/final_reply_gate.py -> exempt
|
|
140
141
|
hooks/blocking/some_new_blocker.py -> flagged
|
|
@@ -168,6 +169,10 @@ def _names_exempt_registration_path(registered_string: str) -> bool:
|
|
|
168
169
|
The artifact page gate denies a page publish whose text is unreadable in
|
|
169
170
|
dark mode. It decides how a page renders and no code or safety policy.
|
|
170
171
|
|
|
172
|
+
The eval write gate denies a write to an eval file until the session
|
|
173
|
+
invokes ``/claude-api build-eval``. It holds eval writes until a skill
|
|
174
|
+
loads, and it judges no code or safety content.
|
|
175
|
+
|
|
171
176
|
The merge offer gate denies a decision card whose text offers a merge and
|
|
172
177
|
names open review findings. It reads only the wording of a chat card and
|
|
173
178
|
decides no code or safety policy; the merge review gate holds the merge.
|
|
@@ -74,6 +74,7 @@ ALL_ACTION_BOUNDARY_EXEMPT_REGISTRATION_PATHS = (
|
|
|
74
74
|
"blocking/image_read_size_gate.py",
|
|
75
75
|
"blocking/artifact_dark_mode_gate.py",
|
|
76
76
|
"blocking/haiku_spawn_slim_gate.py",
|
|
77
|
+
"blocking/build_eval_before_eval_write_gate.py",
|
|
77
78
|
"blocking/merge_over_review_offer_gate.py",
|
|
78
79
|
"blocking/final_reply_gate.py",
|
|
79
80
|
)
|
|
@@ -470,12 +470,30 @@ def test_should_count_failed_meter_read_as_spent() -> None:
|
|
|
470
470
|
|
|
471
471
|
|
|
472
472
|
def test_should_serialize_readings_with_named_fields() -> None:
|
|
473
|
-
reading = Reading(_account("one"), _meters(80, 70))
|
|
473
|
+
reading = Reading(_account("one"), _meters(80, 70), measured_at=NOW)
|
|
474
474
|
|
|
475
475
|
payload = account_broker.readings_payload((reading,))
|
|
476
476
|
|
|
477
477
|
assert payload[0]["name"] == "one"
|
|
478
478
|
assert payload[0]["meters"]["weekly_percent_left"] == 70
|
|
479
|
+
assert payload[0]["measured_at"] == NOW.isoformat()
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
def test_should_wait_until_the_rate_limit_probe_after_stale_meters_expire() -> None:
|
|
483
|
+
reading = Reading(
|
|
484
|
+
_account("one", Product.CLAUDE), None,
|
|
485
|
+
"usage probe failed: HTTP Error 429", NOW - timedelta(minutes=25),
|
|
486
|
+
NOW + timedelta(minutes=5),
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
decision = choose_from_readings(Product.CLAUDE, (reading,), now=NOW)
|
|
490
|
+
|
|
491
|
+
assert decision.action == "wait"
|
|
492
|
+
assert decision.resets_at == NOW + timedelta(minutes=5)
|
|
493
|
+
assert decision.reason == (
|
|
494
|
+
"no account meter could be read (one (usage probe failed: HTTP Error 429)); "
|
|
495
|
+
"next check at 2026-10-03T00:05:00+00:00"
|
|
496
|
+
)
|
|
479
497
|
|
|
480
498
|
|
|
481
499
|
def test_should_wait_when_all_meter_reads_fail() -> None:
|
|
@@ -7,7 +7,7 @@ import shutil
|
|
|
7
7
|
import subprocess
|
|
8
8
|
import sys
|
|
9
9
|
import time
|
|
10
|
-
from datetime import datetime, timezone
|
|
10
|
+
from datetime import datetime, timedelta, timezone
|
|
11
11
|
from collections.abc import Callable
|
|
12
12
|
from pathlib import Path
|
|
13
13
|
from types import SimpleNamespace
|
|
@@ -341,10 +341,11 @@ def test_should_cap_the_meter_read_delay(monkeypatch: pytest.MonkeyPatch, tmp_pa
|
|
|
341
341
|
all_failures = [support.WeeklyUtilizationProbeError("down") for _ in range(6)]
|
|
342
342
|
_claude_meter_reads(monkeypatch, all_failures)
|
|
343
343
|
|
|
344
|
-
meters, unread_reason = support.read_meters_with_backoff(support.read_claude_meters, Account(Product.CLAUDE, "one", tmp_path))
|
|
344
|
+
meters, unread_reason, is_rate_limited = support.read_meters_with_backoff(support.read_claude_meters, Account(Product.CLAUDE, "one", tmp_path))
|
|
345
345
|
|
|
346
346
|
assert meters is None
|
|
347
347
|
assert unread_reason == "down"
|
|
348
|
+
assert not is_rate_limited
|
|
348
349
|
assert all_delays == [1.0, 2.0, 4.0, 8.0, 8.0]
|
|
349
350
|
|
|
350
351
|
|
|
@@ -356,10 +357,11 @@ def test_should_read_a_signed_out_claude_account_once(monkeypatch: pytest.Monkey
|
|
|
356
357
|
all_reads.append(account)
|
|
357
358
|
raise support.ClaudeSignedOutError("no usable bearer token")
|
|
358
359
|
|
|
359
|
-
meters, unread_reason = support.read_meters_with_backoff(signed_out_reader, Account(Product.CLAUDE, "main", tmp_path))
|
|
360
|
+
meters, unread_reason, is_rate_limited = support.read_meters_with_backoff(signed_out_reader, Account(Product.CLAUDE, "main", tmp_path))
|
|
360
361
|
|
|
361
362
|
assert meters is None
|
|
362
363
|
assert unread_reason == "no usable bearer token"
|
|
364
|
+
assert not is_rate_limited
|
|
363
365
|
assert len(all_reads) == 1
|
|
364
366
|
assert all_delays == []
|
|
365
367
|
|
|
@@ -385,6 +387,162 @@ def test_should_cache_account_reading_under_injected_state_path(
|
|
|
385
387
|
assert support.broker_state_path().is_file()
|
|
386
388
|
|
|
387
389
|
|
|
390
|
+
def _read_twice(monkeypatch: pytest.MonkeyPatch, tmp_path: Path, all_results: list[object], gap: timedelta) -> object:
|
|
391
|
+
monkeypatch.setattr(support, "broker_state_path", lambda: tmp_path / "broker" / "state.json")
|
|
392
|
+
_recorded_sleeps(monkeypatch)
|
|
393
|
+
account = Account(Product.CLAUDE, "second", tmp_path)
|
|
394
|
+
pending = list(all_results)
|
|
395
|
+
|
|
396
|
+
def reader(_selected: Account) -> Meters:
|
|
397
|
+
next_outcome = pending.pop(0)
|
|
398
|
+
if isinstance(next_outcome, Exception):
|
|
399
|
+
raise next_outcome
|
|
400
|
+
return next_outcome
|
|
401
|
+
|
|
402
|
+
adapter = ProductAdapter(lambda: (account,), reader, "CLAUDE_CONFIG_DIR", ())
|
|
403
|
+
state = support._load_state(support.broker_state_path())
|
|
404
|
+
first_read_at = datetime(2026, 10, 11, 19, 20, tzinfo=timezone.utc)
|
|
405
|
+
support.read_accounts(Product.CLAUDE, adapter, all_state=state, now=first_read_at)
|
|
406
|
+
return support.read_accounts(Product.CLAUDE, adapter, all_state=state, now=first_read_at + gap)[0]
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
def test_should_keep_the_last_good_meters_when_the_usage_endpoint_rate_limits(
|
|
410
|
+
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
|
|
411
|
+
) -> None:
|
|
412
|
+
rate_limited = support.WeeklyUtilizationProbeError("usage probe failed: HTTP Error 429: Too Many Requests")
|
|
413
|
+
reading = _read_twice(monkeypatch, tmp_path, [Meters(74.0, None, 81.0, None), rate_limited], timedelta(minutes=5))
|
|
414
|
+
|
|
415
|
+
assert reading.meters == Meters(74.0, None, 81.0, None)
|
|
416
|
+
assert reading.unread_reason == str(rate_limited)
|
|
417
|
+
assert reading.measured_at == datetime(2026, 10, 11, 19, 20, tzinfo=timezone.utc)
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
def test_should_drop_last_good_meters_older_than_the_fallback_window(
|
|
421
|
+
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
|
|
422
|
+
) -> None:
|
|
423
|
+
rate_limited = support.WeeklyUtilizationProbeError("usage probe failed: HTTP Error 429: Too Many Requests")
|
|
424
|
+
reading = _read_twice(monkeypatch, tmp_path, [Meters(74.0, None, 81.0, None), rate_limited], timedelta(hours=2))
|
|
425
|
+
|
|
426
|
+
assert reading.meters is None
|
|
427
|
+
assert reading.unread_reason == "usage probe failed: HTTP Error 429: Too Many Requests"
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
def test_should_keep_last_good_meters_at_the_fallback_boundary(
|
|
431
|
+
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
|
|
432
|
+
) -> None:
|
|
433
|
+
rate_limited = support.WeeklyUtilizationProbeError("usage probe failed: HTTP Error 429")
|
|
434
|
+
reading = _read_twice(
|
|
435
|
+
monkeypatch, tmp_path,
|
|
436
|
+
[Meters(74.0, None, 81.0, None), rate_limited], timedelta(minutes=30),
|
|
437
|
+
)
|
|
438
|
+
|
|
439
|
+
assert reading.meters == Meters(74.0, None, 81.0, None)
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
def test_should_drop_last_good_meters_after_a_window_reset(
|
|
443
|
+
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
|
|
444
|
+
) -> None:
|
|
445
|
+
first_read = datetime(2026, 10, 11, 19, 20, tzinfo=timezone.utc)
|
|
446
|
+
rate_limited = support.WeeklyUtilizationProbeError("usage probe failed: HTTP Error 429")
|
|
447
|
+
reading = _read_twice(
|
|
448
|
+
monkeypatch, tmp_path,
|
|
449
|
+
[Meters(3.0, first_read + timedelta(minutes=10), 81.0, None), rate_limited],
|
|
450
|
+
timedelta(minutes=25),
|
|
451
|
+
)
|
|
452
|
+
|
|
453
|
+
assert reading.meters is None
|
|
454
|
+
assert reading.unread_reason == str(rate_limited)
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
def test_should_drop_held_meters_when_a_window_resets(
|
|
458
|
+
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
|
|
459
|
+
) -> None:
|
|
460
|
+
monkeypatch.setattr(support, "broker_state_path", lambda: tmp_path / "broker" / "state.json")
|
|
461
|
+
account = Account(Product.CLAUDE, "second", tmp_path)
|
|
462
|
+
start = datetime(2026, 10, 11, 19, 20, tzinfo=timezone.utc)
|
|
463
|
+
state = support._load_state(support.broker_state_path())
|
|
464
|
+
state["meters"][support._state_key(account)] = {
|
|
465
|
+
"read_at": start.timestamp(),
|
|
466
|
+
"measured_at": (start - timedelta(minutes=5)).timestamp(),
|
|
467
|
+
"meters": support._meter_payload(Meters(3.0, start + timedelta(minutes=1), 81.0, None)),
|
|
468
|
+
"unread_reason": "usage probe failed: HTTP Error 429",
|
|
469
|
+
"retry_at": (start + timedelta(minutes=5)).timestamp(),
|
|
470
|
+
}
|
|
471
|
+
adapter = ProductAdapter(lambda: (account,), lambda _: pytest.fail("probe during cooldown"), "CLAUDE_CONFIG_DIR", ())
|
|
472
|
+
|
|
473
|
+
reading = support.read_accounts(Product.CLAUDE, adapter, all_state=state, now=start + timedelta(minutes=2))[0]
|
|
474
|
+
|
|
475
|
+
assert reading.meters is None
|
|
476
|
+
assert reading.retry_at == start + timedelta(minutes=5)
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
def test_should_reject_a_last_good_entry_with_an_unrelated_failure() -> None:
|
|
480
|
+
now = datetime(2026, 10, 11, 19, 20, tzinfo=timezone.utc)
|
|
481
|
+
entry = {
|
|
482
|
+
"measured_at": now.timestamp(),
|
|
483
|
+
"meters": support._meter_payload(Meters(74.0, None, 81.0, None)),
|
|
484
|
+
"unread_reason": "credentials file missing",
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
assert support._last_good_meters(entry, now) is None
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
def test_should_not_use_last_good_meters_after_a_file_failure(
|
|
491
|
+
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
|
|
492
|
+
) -> None:
|
|
493
|
+
reading = _read_twice(
|
|
494
|
+
monkeypatch, tmp_path,
|
|
495
|
+
[Meters(74.0, None, 81.0, None), *[OSError("credentials file missing") for _ in range(3)]],
|
|
496
|
+
timedelta(minutes=5),
|
|
497
|
+
)
|
|
498
|
+
|
|
499
|
+
assert reading.meters is None
|
|
500
|
+
assert reading.unread_reason == "credentials file missing"
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
def test_should_keep_first_measurement_time_across_rate_limit_fallbacks(
|
|
504
|
+
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
|
|
505
|
+
) -> None:
|
|
506
|
+
monkeypatch.setattr(support, "broker_state_path", lambda: tmp_path / "broker" / "state.json")
|
|
507
|
+
_recorded_sleeps(monkeypatch)
|
|
508
|
+
account = Account(Product.CLAUDE, "second", tmp_path)
|
|
509
|
+
rate_limited = support.WeeklyUtilizationProbeError("usage probe failed: HTTP Error 429")
|
|
510
|
+
pending = [Meters(74.0, None, 81.0, None), rate_limited, rate_limited]
|
|
511
|
+
calls = []
|
|
512
|
+
|
|
513
|
+
def reader(_selected: Account) -> Meters:
|
|
514
|
+
calls.append(1)
|
|
515
|
+
outcome = pending.pop(0)
|
|
516
|
+
if isinstance(outcome, Exception):
|
|
517
|
+
raise outcome
|
|
518
|
+
return outcome
|
|
519
|
+
|
|
520
|
+
adapter = ProductAdapter(lambda: (account,), reader, "CLAUDE_CONFIG_DIR", ())
|
|
521
|
+
state = support._load_state(support.broker_state_path())
|
|
522
|
+
first = datetime(2026, 10, 11, 19, 20, tzinfo=timezone.utc)
|
|
523
|
+
support.read_accounts(Product.CLAUDE, adapter, all_state=state, now=first)
|
|
524
|
+
second = support.read_accounts(Product.CLAUDE, adapter, all_state=state, now=first + timedelta(minutes=5))[0]
|
|
525
|
+
held = support.read_accounts(Product.CLAUDE, adapter, all_state=state, now=first + timedelta(minutes=6))[0]
|
|
526
|
+
third = support.read_accounts(Product.CLAUDE, adapter, all_state=state, now=first + timedelta(minutes=10))[0]
|
|
527
|
+
|
|
528
|
+
assert second.measured_at == first
|
|
529
|
+
assert held.measured_at == first
|
|
530
|
+
assert third.measured_at == first
|
|
531
|
+
assert len(calls) == 3
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
def test_should_keep_newer_measurement_when_stale_fallback_saves_last(tmp_path: Path) -> None:
|
|
535
|
+
state_path = tmp_path / "broker" / "state.json"
|
|
536
|
+
account = Account(Product.CLAUDE, "second", tmp_path)
|
|
537
|
+
key = support._state_key(account)
|
|
538
|
+
old = {"meters": {key: {"read_at": 40.0, "measured_at": 10.0, "meters": support._meter_payload(Meters(74.0, None, 81.0, None)), "unread_reason": "HTTP Error 429"}}, "spent": {}, "affinity": {}}
|
|
539
|
+
newer = {"meters": {key: {"read_at": 30.0, "measured_at": 30.0, "meters": support._meter_payload(Meters(5.0, None, 81.0, None)), "unread_reason": None}}, "spent": {}, "affinity": {}}
|
|
540
|
+
support._save_state(state_path, newer)
|
|
541
|
+
support._save_state(state_path, old)
|
|
542
|
+
|
|
543
|
+
assert support._load_state(state_path)["meters"][key]["meters"]["session_percent_left"] == 5.0
|
|
544
|
+
|
|
545
|
+
|
|
388
546
|
def test_should_extract_session_id_and_restore_runner() -> None:
|
|
389
547
|
original = support.subprocess_runner
|
|
390
548
|
|
|
@@ -130,6 +130,14 @@ def test_new_artifact_page_gate_registration_is_clean(tmp_path: Path) -> None:
|
|
|
130
130
|
assert adapters.hook_configuration_diagnostics(current_document, tmp_path) == ()
|
|
131
131
|
|
|
132
132
|
|
|
133
|
+
def test_new_eval_write_gate_registration_is_clean(tmp_path: Path) -> None:
|
|
134
|
+
current_document = _hook_document(
|
|
135
|
+
["hooks/blocking/build_eval_before_eval_write_gate.py"],
|
|
136
|
+
'{"hooks": {}}',
|
|
137
|
+
)
|
|
138
|
+
assert adapters.hook_configuration_diagnostics(current_document, tmp_path) == ()
|
|
139
|
+
|
|
140
|
+
|
|
133
141
|
def test_new_blocker_in_staged_change_is_rejected(tmp_path: Path) -> None:
|
|
134
142
|
current_document = _hook_document(
|
|
135
143
|
["hooks/blocking/new.py"],
|