Skip to main content

g6-safety-engine

Use when an agent loop or a tool-calling door needs trusted per-run limits (steps, tool calls, shell commands, files, lines, retries, wall time, privilege, cost) checked before each action, with a kill switch the planner cannot reset, or when a change touches tests, conftest.py or test configuration and you must know whether it weakened them before trusting a green run.

Source facts

Repository
basicisabc1994/g6solver
Last source activity
October 26, 2026 at 01:52
Detected SKILL.md language
English
Stars
0
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
g6-safety-engine
description
Use when an agent loop or a tool-calling door needs trusted per-run limits (steps, tool calls, shell commands, files, lines, retries, wall time, privilege, cost) checked before each action, with a kill switch the planner cannot reset, or when a change touches tests, conftest.py or test configuration and you must know whether it weakened them before trusting a green run.
# G6 safety engine Trusted runtime ceilings for one run, and a test-weakening check. `PolicyEngine.authorize_action` checks the kill switch, the ceilings, guard verdicts, a validator quorum, the tool allow-list, forbidden paths and tests before a final answer before an action runs, and returns `ALLOW`, `BLOCK` or `ESCALATE`. `detect_test_weakening` compares the tests and their configuration before and after a change by reading the files; it runs nothing. ## When to use it - Building an agent loop or a tool door: one `RuntimePolicy` from trusted configuration, one `RunState` per run, `authorize_action` before every call, then `record_execution` and `record_cost` after it, and `record_tests` after each test run the door itself ran. - An agent's change touches tests and you are about to trust "the tests pass": `detect_test_weakening` on the files before and after, or on two snapshot directories. - A run must stop: trip its kill switch. ## When not to use it - Whether one outward action should go ahead, given its reach and reversibility: `action_gating`. - Flagging injection or tampering phrasing in text: `guards`, then pass its verdict here. - Whether the change itself is right: run the tests; nothing here runs them. - An operating-system sandbox: this is not one. ## Python API - `detect_test_weakening`: compare test files, every `conftest.py` and the pytest and CI configuration before and after a change; returns a `TestWeakeningReport`. - `read_snapshot`: read a directory into the path-to-text mapping `detect_test_weakening` compares. - `TestWeakeningReport`: `weakened`, `reasons`, `checked`, `not_checked`, `completion_state` and `to_envelope()`. - `policy_engine.PolicyEngine`: `authorize_action(action, state, policy, guard_verdicts, validator_votes)`, the pre-action decision. - `schema.RuntimePolicy`: the frozen, trusted ceilings, allow-list, forbidden paths and quorum settings for one run. - `schema.ActionRequest`: one proposed tool call, untrusted data: tool, arguments, files touched, privilege, shell flag, estimated lines, cost ceiling, and `is_final` for the call that delivers the final answer. - `schema.AuthorizationDecision`: the decision, its reason, `permitted_action` (set only on `ALLOW`) and the `policy_checks` that ran. - `schema.ValidatorVote`: one validator's vote and its declared fault domain. - `state.RunState`: the run's counters, its kill switch and its policy; `record_tests(passed)` records the latest test run. - `ceilings.exceeds_ceiling`: the first ceiling an action would breach, projected before it runs. - `kill_switch.KillSwitch`: a run-scoped stop that trips one way; `KillSwitch.with_reset_token()` returns a switch and the only token that resets it, and a switch made without one never resets. - `quorum.quorum_satisfied`: whether the votes clear the policy's quorum. ## Reading the result `authorize_action` checks in this order and stops at the first refusal: the run's kill switch and G6's process-wide stop; the ceilings (tool calls, steps, shell commands, files modified, lines changed, retries, runtime, privilege, cost); a guard `BLOCK` verdict, which also trips the kill switch; a guard `ESCALATE`; the quorum, when `require_quorum` is on; the allow-list, enforced whenever it is not empty; forbidden paths, matched on normalised, case-folded spellings; and, when `require_tests_before_final` is on (the default), an `is_final` action before the run has recorded a passing test run (`record_tests(passed=True)`; only a boolean `True` counts). Every decision that gets past the ceilings is one step of `max_steps`, whether it is allowed or refused, so a planner that keeps proposing refused actions stops too. The decision is not a token: the code that runs the action must obey it. A weakening report is `blocked-escalated` when `weakened`, else `qualified-draft`, never `verified`. Its envelope's warning code is `G6_E_TEST_WEAKENING_DETECTED`, `G6_E_TEST_WEAKENING_STATIC_ONLY` (nothing found in what it compared) or `G6_E_TEST_WEAKENING_NOTHING_COMPARED`. `not_checked` always lists what a static scan cannot see. ## Alone and composed From Python only: `from g6.safety_engine import detect_test_weakening`, and the policy pieces from their modules (`g6.safety_engine.policy_engine`, `.schema`, `.state`). It has no block and no MCP op. Composed: - `workforce`: its single call door authorises every call with `PolicyEngine` against the worker's `RuntimePolicy`, and reads a cost-ceiling refusal as `refused:budget`; its patch checks run `detect_test_weakening` on the original repository against the changed copy. - `guards`: pass `PatternGuard` verdicts as `guard_verdicts`; the engine, not the guard, decides. ## Failure modes it catches - `runaway_run` (a run that keeps going past its limits): every ceiling is projected before the action runs, from the frozen `RuntimePolicy` the caller passes (load it from trusted configuration before the run; the engine cannot tell where it came from); a negative cost cannot lower the projection; the step ceiling counts refused proposals as well as allowed ones; the kill switch trips one way, and `reset` refuses anything but the token handed to the switch's owner, which the switch does not keep. - `test_weakening` (an agent weakening tests to make them pass): it reports a deleted test file, a removed, renamed or neutralised check, fewer tests, an early return, an added skip, xfail, `importorskip`, `pytestmark`, mock or autouse fixture, a module-level patch, any code change to a `conftest.py` in any directory, and any change to the pytest, test-runner or CI configuration. ## Blind spots - Ceilings bound only what passes through a door that asks and obeys; it does not observe an action's real effects. - The counters move only when the caller records them, and the shell, files, lines and privilege axes read the action's declared fields. The workforce door leaves those four axes inert, and nothing there records a retry. - The reset token is a capability, not a security boundary: code in the same process can still write a switch's private fields directly (the `guards` source scan flags a write to its `_tripped` flag). - The engine checks whatever `policy` it is passed and never compares it with `state.policy`. - The tests-before-final check holds only an action the caller marks `is_final`, and `record_tests` is the word of the code that calls it; the workforce door marks no call final, so there it never fires. - The quorum counts declared fault domains; it proves nothing about the validators' independence. - The weakening check is static: whether the tests pass, or are collected at all, is not established; a check whose text is unchanged but proves less (a trivial fixture, `assert x or True`) is not seen; test files outside pytest's default names and options from the command line or plugins are not read. - It declares no failure mode of its own. ## What it needs Nothing outside G6: pure standard-library Python (the weakening check parses files with `ast`, `tomllib` and `configparser`). Nothing is run. ## Examples ```python from g6.safety_engine import detect_test_weakening from g6.safety_engine.ceilings import COST_CEILING from g6.safety_engine.policy_engine import PolicyEngine from g6.safety_engine.schema import ActionRequest, RuntimePolicy from g6.safety_engine.state import RunState policy = RuntimePolicy(max_cost_cents=50, allowed_tools=frozenset({"search", "write"}), forbidden_paths=frozenset({"secrets/"})) state = RunState(policy=policy, run_id="run-1") engine = PolicyEngine() first = engine.authorize_action(ActionRequest(tool_name="search", cost_ceiling_cents=30), state, policy) assert first.decision == "ALLOW" and first.permitted_action is not None state.record_execution(first.permitted_action) state.record_cost(30) second = engine.authorize_action(ActionRequest(tool_name="search", cost_ceiling_cents=30), state, policy) assert second.decision == "BLOCK" and COST_CEILING in second.reason # 30 spent + 30 more > 50 assert engine.authorize_action(ActionRequest(tool_name="shell"), state, policy).decision == "BLOCK" assert engine.authorize_action(ActionRequest(tool_name="write", files_touched=("SECRETS/key.pem",)), state, policy).decision == "BLOCK" # forbidden, whatever the spelling state.kill_switch.trip("stopped by the operator") assert engine.authorize_action(ActionRequest(tool_name="search"), state, policy).decision == "BLOCK" before = {"tests/test_calc.py": "from calc import add\n\n\ndef test_add():\n assert add(2, 2) == 4\n"} after = {"tests/test_calc.py": "import pytest\nfrom calc import add\n\n\n@pytest.mark.skip\n" "def test_add():\n assert add(2, 2) == 4\n"} report = detect_test_weakening(before, after) assert report.weakened and report.completion_state == "blocked-escalated" assert report.to_envelope()["warning_card"]["code"] == "G6_E_TEST_WEAKENING_DETECTED" ``` ## The four open problems - **Learning signals**: Not yet: it writes nothing itself. Each decision names its reason and the `policy_checks` that ran, and the weakening report's envelope carries a `G6_E_*` code and its reasons, records a caller can keep; the workforce door files a cost refusal as `refused:budget`. - **Evaluators the model cannot influence**: the policy is a frozen `RuntimePolicy` the caller passes (load it from trusted configuration before the run; the engine cannot tell where it came from); the kill switch resets only with the token its owner was given; the weakening check reads the file text it is given (G6 reads the files itself when given two directories), so the agent whose change it judges cannot argue with it. Not yet: the code is not digest-pinned. - **Transfer by failure mode**: it is bound to `runaway_run` and `test_weakening`, not to a task: the ceilings are counters any loop has, and the weakening rules read pytest's structure in any Python repository (only Python and pytest). Not yet: catch rates on unseen task families. - **Enough held-out cases**: Not yet: its catch and false-alarm rates are not judged by G6's sequential test; its tests are fixed regressions, with null tests showing the older, weaker weakening detector fails them; the ceiling and policy tests have none.
View on GitHub