Skip to content

Releases: Synaptic-Labs-AI/PACT-Plugin

v4.5.2 — tests/ import hygiene + repo-wide F401 enforcement

Choose a tag to compare

@michael-wojcik michael-wojcik released this 07 Jul 05:12
5eac5bc

Summary

Completes the tests/ unused-import cleanup deferred from the import-hygiene lint arc and widens both enforcement layers (CI ruff leg + L1 suite gate) to cover pact-plugin/tests/.

What landed

  • CI import-hygiene leg 1 widened to pact-plugin/ (F401+F821); tests/-exclusion comment retired; F821 floor leg kept as deliberate structure.
  • 138 F401 findings resolved across 75 test files: 137 deletions (each cleared by a five-point AST-anchored whole-tree consumer scan) + 1 reasoned ensure-loaded keep with first-line noqa.
  • L1 suite gate widened to sweep tests/, pinned by 4 counter-tests (self-inclusion reachability, subdirectory planted probe pinning glob recursion, strict-flip simulation, kept-seam noqa recognition).
  • Review remediation: gate scope comment precision, sweep-recursion pin hardening, re-export probe noqa made first-line-visible.

Why

tests/ was excluded from F401 coverage only while it carried a known backlog. With the backlog at zero, both layers now enforce the same surface with the same first-line-noqa escape hatch — a future dead import in tests/ fails CI and the suite gate identically.

v4.5.1 — Layered import-hygiene enforcement

Choose a tag to compare

@michael-wojcik michael-wojcik released this 06 Jul 23:55
0930b53

Summary

Layered import-hygiene enforcement: unused-import defects — invisible to behavioral testing — are now caught mechanically at three levels instead of by reviewers reading diffs.

What landed

  • L1 (primary enforcement)tests/test_import_hygiene.py: strict stdlib-AST sweep over all consumer-shipped Python on every suite/CI run; non-vacuity fixtures driven through the gate's own entry point, a no-default signature pin on the predicate's try-scope parameter, and a prose pin on the canonical coder command. Zero new dependencies.
  • L2 (consumer machinery)lint-check.sh --files mode: execution-probed linter ladder (ruff → pyflakes → flake8 → stdlib fallback), per-rung F401/F821 scope pinning, mandatory IMPORT-HYGIENE: PASS | FINDINGS (n) | SKIPPED (<reason>) verdict line, fail-open by construction. New check_unused_imports.py stdlib predicate (read-context-only usage analysis, literal typing.TYPE_CHECKING carve-out, try/except* scoping, first-line noqa honoring incl. PEP-263 non-UTF-8 sources) is the single substrate shared by L1 and L2, plus subprocess contract tests for the script itself.
  • L3 (trigger) — one canonical sentence in both coder dispatch templates (orchestrate.md, comPACT.md) and the skill, with filename single-quoting guidance.
  • CI — two-leg ruff step: F401+F821 over consumer-shipped surfaces + F821 repo-wide (--target-version py39).
  • Cleanup — 51 dead imports removed across hooks/, telegram/, skills/; the merge-guard re-import facade reduced to its consumed surface with reasoned per-disposition # noqa: F401 markers; 17 inert monkeypatches and their vestigial seam import removed.

Why

Two dead import os statements survived a fully-green 10k-test suite and were caught only in peer review — the suite is structurally blind to hygiene defects (gate blindness, not process failure). A shipped hooks.json enactment was rejected by the consumers-first boundary; the layered design gives maintainers a mechanical CI gate, consumers a portable advisory tool, and coders a one-command workflow trigger.

Deferred (tracked in #1117): the ~140-finding unused-import cleanup across tests/, after which the F401 CI leg can widen repo-wide.

v4.5.0 — Unified config framework + PACT_PR_GREEDY_FIX

Choose a tag to compare

@michael-wojcik michael-wojcik released this 06 Jul 15:06
92dcbcd

Summary

A unified configuration framework for the PACT plugin over PACT_* environment variables, with PACT_PR_GREEDY_FIX as the flagship first consumer. Config resolves once per session; LLM-consumed options are injected into the orchestrator's context at SessionStart so markdown flows can honor them.

What landed

  • Resolver (hooks/shared/pact_config.py) — os.environ-blind, call-time, typed registry (get_bool / get_enum / llm_options); exact-membership bool parsing (fail-safe, not truthiness); any failure → registry default, never raises.
  • Gate unification — the two copy-pasted *_MODE reads (dispatch_gate, handoff_ordering_gate) now resolve through the registry; behavior byte-equivalent, each gate's fail-direction preserved.
  • SessionStart injection bridge (session_init.py) — composes a PACT Runtime Config block into additionalContext via fixed-label canonical-value composition (a poisoned resolver value cannot inject text); lead-only, fail-open (absence == all OFF). Multi-tier settings.json malformed-file self-check (user + project + local).
  • PACT_PR_GREEDY_FIX (commands/peer-review.md) — greedy remediation of minor + future PR findings, scoped to strictly reversible auto-delegation of fixes; merge / close / push stay user-gated; hard SACROSANCT carve-out; fix routing is by fix-domain, orchestrator-mediated.
  • autonomous-scope-detection hard-cut — the CLAUDE.md prose marker is replaced by PACT_AUTONOMOUS_SCOPE_DETECTION, byte-mirrored into the pact-protocols.md SSOT.
  • Docs — new pact-plugin/reference/config.md; completed README Configuration tables.

Why (MINOR)

The autonomous-scope-detection marker hard-cut is a user-visible behavioral migration.

Migration

If you set autonomous-scope-detection: enabled in CLAUDE.md, set PACT_AUTONOMOUS_SCOPE_DETECTION=1 instead (via settings.json's env block or a shell export). Existing markers become no-ops. See pact-plugin/reference/config.md.

Verification

Full suite 10752 passed / 0 failed / 0 errors; extract byte-gate 19/0. Reviewed by 4 lenses (design-coherence + adversarial security + implementation + coverage), 0 Blocking, security-clear (transitive-laundering unreachable — outward-facing actions gated by merge_guard_pre for all agents).

v4.4.55 — merge-guard: op+target+flags Layer-1 retirement granularity (#1100)

Choose a tag to compare

@michael-wojcik michael-wojcik released this 05 Jul 08:56
fa3e876

Summary

Raises merge-guard Layer-1 token retirement granularity from op+target to op+target+bound_flags (#1100), curing a bounded re-approval friction where a successful bare same-op/same-target command retired an operator's approved flag-escalated token — without weakening retirement's security role.

What landed

  • Finer retirement identity. _retire_token_for_command (a PostToolUse observer) now discriminates on bound_flags in addition to op+target+session, derived from one leg-isolated extract_command_context mirroring the read arm — so mint, read, and retirement agree on (op, target, bound_flags) identity by construction. Reuse-only: no mint/read/shared-extractor edits.
  • Fail-safe hardening (from GitHub Copilot's PR review): the token-side bound_flags read is guarded (isinstance-list + all-string-element) so a malformed/legacy token is skipped gracefully instead of crashing the observer and skipping retirement for the rest of the run.
  • Tests. TestFlagAwareRetirement (bidirectional friction-cure, flag-normalization equivalence, two-mechanism non-vacuity, both-modes session matrix), a post→pre seam test, TestMalformedTokenRetirementRobustness (9 malformed-shape + loop-resilience tests), and an intent-preserving fix to the pre-existing #1097 target-axis non-vacuity probe. Full suite 10629 passed / 0 failed / 0 errors.

Why

Follow-on to #1097 (target-aware retirement). Retirement is a security-relevant observer: this reduces over-block friction while preserving its security job (a genuine self-consume still retires; the residual is a tolerated under-retire backstopped by TTL + MAX_USES; over-block is structurally impossible for a PostToolUse observer). Certified SAFE-TO-MERGE by an independent pact-security-engineer 8-item review + a 3-lens adversarial break-sweep (no laundering, extraction-symmetric), plus GitHub Copilot's robustness catch fixed and regression-tested.

v4.4.54 — merge-guard: branch-delete cross-leg over-block cured

Choose a tag to compare

@michael-wojcik michael-wojcik released this 04 Jul 12:00
7619ba1

Summary

Cures the merge-guard branch-delete cross-leg over-block (#1094) — the 4th and final cross-leg twin, completing the per-leg conversion class begun with the force-push, API-merge, and PR-close legs.

What landed

  • Per-leg read floor: the 3 branch-delete arms moved verbatim from DANGEROUS_PATTERNS into the _BRANCH_DELETE_LITERAL_ARMS SSOT; 4th per-leg loop reusing the hoisted legs substrate
  • Detect conversion: detect_command_operation_type consumes the same tuple per-leg — read==mint classification parity by construction; closes the mint-scan multiplicity over-block vector and structurally closes the ambiguous-compound laundering substrate
  • Certification: TestBranchDeleteLiteralArmCrossLegSweep (cured rows incl. 4 probe-discovered separator families, 14-row same-leg preservation matrix, parity rows p1–p6, per-row two-stage counter-mutations with runtime-verified flip-set) + a two-direction laundering-closure canary
  • Review remediation: comment/docstring accuracy fixes + a behavior-neutral detect legs-hoist (also flagged independently by Copilot)
  • PATCH bump 4.4.53 → 4.4.54

Why

Pre-fix, a stray -D/--delete token in a benign continuation leg gated faithful clicks (git branch new-feature && echo -D — the cardinal-sin direction under the honest-mistake charter). Dual-independent review (blind security verdict-lock): zero blocking findings; full suite 10598 passed / 0 failed / 0 errors.

Completes the acceptance criteria of #1094; issue closure pending the post-install live-probe of the installed hooks. Follow-ups: #1103 (push-to-main declaration tuple-ization), #1104 (substitution-carrier accepted-residual disposition record).

v4.4.53 — merge-guard cross-leg completion + gh-api-only API-merge mint

Choose a tag to compare

@michael-wojcik michael-wojcik released this 03 Jul 09:24
2c8cdd2

Summary

Completes the merge-guard cross-leg leg-isolation arc and lands the API-based PR-merge mint cure in its provably-sound, gh-api-only form. Over-block remains the cardinal sin (a faithful single-command click always mints and merges); the API-merge laundering surface is closed by construction.

What landed

  • #1087 — close-arm approval-laundering channel closed via per-leg matching.
  • #1086 — API cross-leg over-blocks removed via per-leg matching.
  • #1097 — target-aware token retirement: retirement matches op-type + target, so an unrelated same-op command no longer retires an operator's approved token.
  • #1096 (gh-api-only) — a faithful gh api PUT/PATCH/POST to a pull-request merge endpoint now mints an approval token (previously gated-but-unmintable). Recognition and endpoint extraction share one per-leg helper that binds the URL-positional PR, not a decoy in a flag body or another leg.
  • #1037 — the unquoted-body read-floor over-block is cured.
  • A latent contents-API case-insensitivity under-block is fixed (the strip exception now matches its case-insensitive read arm).

Why gh-api-only

Multi-lens review (GitHub Copilot + adversarial security review) found the original curl/wget API-merge extraction relied on a value-taking-flag denylist over an unbounded, per-release flag vocabulary — a target-confusion laundering class (approve merge-of-X, authorize merge-of-Y) with dozens of leaking flags including the most common. gh api has a finite, documented flag set and a first-positional-endpoint convention, making its extraction provably sound. So the mint is restricted to gh-api; curl/wget merge reverts to its pre-existing gated-but-unmintable state (still read-gated — not a new hole), and the laundering class dies by construction (cannot classify a merge → cannot mint → cannot launder). Extending the cure to curl/wget with a real argv parser is a tracked follow-up.

Verification

Full suite 10548 passed / 0 failed / 0 errors. Independent re-certification of each remediation with source-revert-proven non-vacuity; adversarial security re-review confirmed the laundering class dead by construction with no new under-block; design-coherence re-review confirmed a clean cut; both-sides hermetic live-probe through the real hook mains.

Gated closure

Closure of #1087, #1086, #1096, #1097 (and #1037) rides a post-install live-probe re-run against the installed version, per the established gated-closure discipline.

v4.4.52 — Agent Teams wake/idle message-ordering hardening

Choose a tag to compare

@michael-wojcik michael-wojcik released this 02 Jul 17:06
60f1479

Summary

Hardens the Agent Teams instruction surfaces against wake/idle message-ordering races — crossed-wake idles, stale counter-confirms, and mid-turn directive misses. Instruction-only: the platform's async-inbox contract makes synchronous wake/send detection dead-by-construction, so these rules make agents behave correctly under the race.

What landed

  • Teammate-side (pact-agent-teams SKILL): seam-agnostic On-Wake Disk-First Re-Read (any intentional_wait reason + any crossed inbound directive), Counter-Confirm Suppression, Boundary-Drain Rule (literal inbox-file read before every protocol-boundary message, fail-open, idempotent) with drain lines in both the HANDOFF and teachback notify templates.
  • Lead-side (pact-completion-authority + SSOT mirror + orchestrator persona): Crossed-Wake Idles — one redundant confirm then stop (with a behavioral no-synchronous-hook non-goal note), Directive-Reflection Check with a mechanically checkable boundary-drain: marker.
  • Stall-protocol harmonization: post-wake / live-wait idles are delivery-ordering artifacts, not stalls.
  • Drift fixes: stale 4-point-rule summary corrected to the protocol's 3-point rule; stale no-hook-consumer claims corrected; inbox message field list grounded in an empirical 132-message survey.
  • 61 presence pins (whitespace-normalized phrases, line-anchored headings, terminator-guarded slug cross-refs, fence-aware matching) with run-verified non-vacuity.
  • Charter pointer to the suppression exception; placeholder spelling unified to {team_name}.

Why

Two orchestration sessions produced 6+ crossed-wake incidents across three seam types, 5 stale counter-confirms, and 1 mid-turn directive miss. The rules were dogfooded during their own implementation and review — including a live two-sided crossed-directive recovery caught by the directive-reflection check this release ships.

v4.4.51 — merge-guard cross-leg leg-isolation: 5 over-blocks fixed + approval-laundering closed

Choose a tag to compare

@michael-wojcik michael-wojcik released this 02 Jul 08:16
6a83b7b

Summary

Completes the merge-guard's cross-leg leg-isolation: five over-blocks fixed and a live approval-laundering vulnerability closed, unified by one move — convert cross-leg danger/bind matching to per-leg. The merge-guard is a SACROSANCT honest-mistake control; a faithful single-command click always mints and merges, and a benign-looking approval must never authorize a more-dangerous execution.

What landed

Over-blocks fixed (a faithful click that was blocked or gated-but-unmintable):

  • #1064 — lease-protected push to default now gates AND mints (boolean privileged-flag bind; plain/lease/force never cross-authorize).
  • #1077 — httpie dropped from the read floor (was gated-but-unmintable → permanent block).
  • #1078 — flag-condition union arm anchored to the first executable leg (cross-leg flag leak).
  • #1082 — force-push literal danger arms match per-leg (cures the cross-leg over-block including the permanent git push && rm -f x.txt).
  • #1083 — two-tier leg-bounded bind window on both the mint and read surfaces.

Security — approval-laundering channel closed (#1083): before this release, approving a benign-looking compound (e.g. gh pr close 42 && echo --delete-branch) minted a token whose bound flags were scanned from the whole command, so it could authorize a real irreversible branch-deleting close (and the lease-push / force-push / admin-merge analogues). The two-tier window binds only from the executed op's own leg on both surfaces, so the laundered token can no longer form — verified end-to-end across all four channels.

Why

All five were faithful-single-command over-blocks or the permissive-direction laundering hole — the cardinal failures the control exists to avoid. Architecturally, the union arm (#1078), the force-push literal arms (#1082), and the mint/read bind surfaces (#1083) all now route through one shared leg-boundary primitive (_slice_stripped_legs), with mint and read sharing leg-selection under an anti-rot symmetry pin.

Verification

  • Full suite: 10366 passed / 11 skipped / 0 failed / 0 errors.
  • Two independent blind adversarial security reviews (original batch + leg-isolation delta), both SAFE-TO-MERGE.
  • Two hermetic live-probes through the real shipped hook mains (subprocess-isolated, both pre/post sides): 17/17 + 14/14, zero runtime-vs-unit divergence.
  • Concurrent auditor GREEN; GitHub Copilot review addressed (two docstring completions).

Tracked follow-ups (pre-existing, not introduced by this release)

  • #1084 — lease-to-default under-blocks on non-idiomatic spellings.
  • #1086 — API danger arms match cross-leg (pure over-block; structurally not laundering-reachable).
  • #1087 — multi-close ambiguity still launders --delete-branch (the close-arm analogue of #1082).

#1086 and #1087 are the remaining cross-leg surfaces and share this release's per-leg fix pattern.

Issue closure

Completes the acceptance criteria of #1064, #1077, #1078, #1082, #1083; closure gated on the post-install live-probe against installed v4.4.51.

v4.4.50 — merge-guard op-recognition completeness

Choose a tag to compare

@michael-wojcik michael-wojcik released this 30 Jun 23:30
d79a6ba

Summary

Extends the merge-guard's honest-mistake recognition to three destructive op-classes that previously bypassed the operator's approval click — remote-ref deletion, mass deletion, and branch-protection API mutation — host-agnostically, while holding the guard's governing principle: a faithful single-command click always mints+executes, and anything that can block a faithful single-command click is wrong by definition.

What landed

  • remote-ref-deletegit push origin :ref / --delete / -d (incl. tag/refs colon-refspecs, implicit remote), as a distinct op-class so a local branch-delete token can't cross-authorize a remote ref-delete.
  • remote-mass-delete--mirror / --prune / multi-ref --delete, with a tight per-invocation binding (no cross-authorization between distinct invocations).
  • branch-protectiongh api/curl/wget -X DELETE|PUT|PATCH .../branches/*/protection, host-agnostic, POST excluded.
  • Host-agnostic curl git/refs gate (dropped the literal api key) + an HTTP-body strip so the new arms don't over-block a faithful command mentioning these paths in a quoted body.

Recognition is deliberately conservative: it gates the single destructive command (plus benign viewers/filters) and does not chase destructive ops in non-first compound legs — that would require match-anywhere recognition that over-blocks a faithful click. The accepted limitation is named in the SSOT threat-model so a future sweep can't harden it back into an over-block.

Why

Closes honest-mistake under-block coverage for these destructive forms while never over-blocking a faithful single-command click. Reviewed by a 4-reviewer panel plus an independent blind security review (which caught and resolved a compound-leg bypass) and GitHub Copilot; over-blocks were removed by widening the mint to match the read floor, never narrowing read. Full suite 10205 passed / 0 failed / 0 errors. Closes #1062 and #1061; completes the scoped ACs of #1063 (closure pending a post-install live-probe). Follow-ups tracked in #1074, #1075, #1077, #1078.

v4.4.49 — IO_NUMBER edge-case + discriminator regression pins

Choose a tag to compare

@michael-wojcik michael-wojcik released this 30 Jun 15:27
03f17f5

Summary

Test-only follow-up to v4.4.48 (#1070). Preserves five additional Fix A IO_NUMBER regression cases authored during the #1070 peer review after the security-cleared snapshot that merged.

What landed

Additions to TestFixADigitGluedRedirectUnderBlock (no source change):

  • A glued fd-duplication target case.
  • A dotted-version ref (v1.2-style) — the . breaks the fd-prefix, so the version digits stay part of the ref.
  • Two more spaced-fd-redirect assertions.
  • A discriminator pin: a clean ref + redirect (no glued digit) still authorizes the short token — proving it is the glued digit that shifts the target, not the bare redirect.

These converge with the architect's independent bash-ground-truth tables (zero divergence) and re-confirm the fine-grained non-vacuity.

Verification

Authoritative full suite (py3.14.5): 9988 passed / 0 failed / 0 errors.