Skip to content

workflow: notices keep the route, specs stay in the package, Node test margin (#185, #186, #187) - #188

Merged
Dimkox merged 19 commits into
mainfrom
ccr-315b4684-r3j424
Oct 25, 2026
Merged

Dimkox merged 19 commits into
mainfrom
ccr-315b4684-r3j424

Conversation

@Dimkox

@Dimkox Dimkox commented Oct 24, 2026 •

Copy link
Copy Markdown
Owner

Fixes #185 and #187, and the first part of #186.

#187: Node adapter test margin

test_node_adapter_behavior hit its 10 s timeout on a busy public linux runner. The test checks behavior, not speed, so both Node calls now allow 60 s. The neighbouring stubborn-child test already allows 45 s. Only the test changes.

#185: harness notices are not tasks

Claude Code delivers <task-notification> and <system-reminder> envelopes as prompts. UserPromptSubmit used to route each one as a new task. That gave wrong routes (including release and production_action_approval), and the envelope text ended up as the spec objective.

  • router.is_system_notice is true only when the prompt holds envelopes and nothing else. Any text next to an envelope is a normal prompt.
  • should_reuse_active_route treats a notice like a short reply. The hook keeps the active route for it, and never builds a route for a notice when none exists.
  • A notice cannot raise authority: it can only keep a route that the same session already has, the same as "да".

#186: spec path and transition errors

  • getzilla spec generate and validate --change-id now use the package folder that change start created, through workflow_storage.change_directory. That is the runtime one; legacy tracked packages stay readable. No stray file lands in engineering/changes/ any more.
  • A refused getzilla change transition exits 2 and names the allowed next states, without a traceback.
  • Not done, stays in [Spec] getzilla spec generate writes into tracked engineering/changes instead of the runtime package #186: a terminal state for work that was delivered while the local gate was NOT_RUN.

Tests

  • Router: notice-only prompts are reused; a prompt with real text, an unclosed envelope or an empty prompt is not; is_development_prompt is false for a notice.
  • Hook end to end: a notice keeps the route of the same session, and creates no route in a fresh project.
  • CLI: a refused transition gives exit 2 and the allowed states; spec generate writes into the runtime package.
  • Local runs:
    • tests/test_package_status.py, test_change_spec.py, test_router_routes.py, test_hooks.py: 131 passed.
    • tests/test_ai_transparency_template.py: 5 passed.
    • Ruff clean; harness: no drift.

🤖 Generated with Claude Code

https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

claude added 17 commits October 24, 2026 13:58
Every prompt starts a new route, so binding protected-path grants to
the route voided them on each user message and forced a new grant for
the same edit again and again. A branch-bound grant is already held to
the repository, branch ref, anchor ancestry, exact files and TTL, so
it no longer checks the route. Production and external-write grants
keep their exact route, HEAD and tree binding.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR
The security review found that change_id is now the only task binding
of a branch-bound grant and that no test pinned it, nor the
protected-path scope guard. Add a test for each; both mutants are now
killed. Update the has_valid_approval docstring.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR
Skipping the route broke session isolation: a grant issued in one
session also served another session in the same worktree
(tests/test_control_plane_sessions failed on CI). A protected-path
grant now records its session and checks that instead of the route,
so later prompts of the same session keep it and another session never
gets it. Without a known session on both sides the exact route is
still required.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR
A session without its own route pointer reads the shared route of another
session, and 'manual' is not a session. The check now uses the caller's
bound session and skips the route only when caller, route and grant name
the same session. getzilla_approve.py binds CLAUDE_CODE_SESSION_ID.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR
… to date

- QUICKSTART: launcher, runtime evidence without report commits, route
  reconcile, review snapshots, light lane, and a disk cleanup section.
- START_HERE and REFERENCE: current main a45fbdd, correct v2.3.0 link,
  continuation at issue #134; REFERENCE lists all getzilla commands.
- PROJECT_STATE: current_continuation moves to issue #134; the finished
  PR #79 contour is kept as historical_pr79_continuation.
- CHANGELOG: 2.3.1 lists the work merged since 2026-10-21 (#121-#179).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR
A Commands section lists all launcher commands by task, with their main
options. The source line names what 2.3.1 adds since v2.3.0, and the
file map says where review copies live and how they are removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR
history takes a snapshot file, approve needs --reason, --add-reviewer
works with --reconcile, getzilla test falls back to serial unittest
without pytest-xdist, report overhead is per profile, and the state
record counts the merged PRs from #114.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR
…tree checks

- Inventory: a linked .getzilla or runtime folder is not read; one entry
  budget covers the copy search and all copy sizes; an unreadable folder,
  a linked copy root or a cut size makes the report incomplete.
- Review snapshots: the parent-folder refusal has its own message, and
  the module says a snapshot holds committed content only.
- Tests pin the guards that mutants survived before: annotated tag
  peel, marker removal after a failed worktree add, the main-worktree
  base, the marker schema, the 0700 mode, unregistered folders, the
  refs/worktree check, a failed reflog read, the 2 s margins.
- getzilla status answers --help; a test runs --help for every command.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR
…ctly the budget

Review of #181: the copy folder listing was counted by the search and
again by its size, and a search that used the full budget reported
itself incomplete. Tests pin both boundaries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR
AGENTS.md now requires an issue in Dimkox/Getzilla for each defect in
Getzilla itself, also one that was worked around: search first, no
duplicates, Low findings into the collecting issue, no secrets or
exploit commands, and an exact external-write grant first. Consumer
projects get the same rule in the installed contract, with a ready
issue text for the owner when filing upstream is not allowed. The
delivery skill adds it as the last step of a task.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR
Review of #182: the new rule called issue writes an L5 process call
while the L5 scope named only merge, tag and release. The owner asked
for it, so the scope now covers the project's own GitHub issues; the
checks-green condition stays on merge, tag and release. The search
covers open and closed issues, the grant resource is named, consumer
consent is recorded as an exact grant, and a test pins the rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR
…bans

Security review of #182: the rule said a tool grant lasts its TTL, but
external-write grants stay bound to route, change, HEAD and tree. The
test now also pins the bans on secrets and customer data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR
#187)

test_node_adapter_behavior timed out after 10 s on a busy public linux
runner while it only checks adapter behavior. Both Node calls now allow
60 s; the neighbouring stubborn-child test already allows 45 s.

Fixes #187.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-24T21:20:07.654633Z f676191 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

… package (#185, #186)

- A prompt made only of <task-notification> or <system-reminder>
  envelopes keeps the active route like a short reply, and never
  creates a route. Text next to an envelope is a normal prompt.
- getzilla spec generate/validate --change-id use the package folder
  that change start created (the runtime one; legacy tracked packages
  stay readable), so no stray file lands in engineering/changes.
- getzilla change transition answers a refused move with exit 2 and
  the allowed next states, not a traceback.

Fixes #185.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR
@Dimkox Dimkox changed the title tests: room for the Node transparency adapter tests on loaded runners (#187) workflow: notices keep the route, specs stay in the package, Node test margin (#185, #186, #187) Oct 24, 2026
Review of #188: a notice next to a route of another session, or a
closed route, built no route, so the session fell back to that route.
Such a route is now replaced as before; the no-route rule applies only
when no route exists at all. The transition hint names allowed states
only for an invalid move, not for a gate refusal. Tests cover both
cases and envelope edge forms (zero-width tail, attributes, case,
crossed tags).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR
@Dimkox
Dimkox merged commit 20f494e into main Oct 25, 2026
8 checks passed
Dimkox pushed a commit that referenced this pull request Oct 25, 2026
Dimkox added a commit that referenced this pull request Oct 25, 2026
… session (#189)

* grants: a new route keeps a branch-bound protected-path grant

Every prompt starts a new route, so binding protected-path grants to
the route voided them on each user message and forced a new grant for
the same edit again and again. A branch-bound grant is already held to
the repository, branch ref, anchor ancestry, exact files and TTL, so
it no longer checks the route. Production and external-write grants
keep their exact route, HEAD and tree binding.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* grants: pin change_id and the scope guard in tests

The security review found that change_id is now the only task binding
of a branch-bound grant and that no test pinned it, nor the
protected-path scope guard. Add a test for each; both mutants are now
killed. Update the has_valid_approval docstring.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* grants: bind branch-bound grants to the session, not the route

Skipping the route broke session isolation: a grant issued in one
session also served another session in the same worktree
(tests/test_control_plane_sessions failed on CI). A protected-path
grant now records its session and checks that instead of the route,
so later prompts of the same session keep it and another session never
gets it. Without a known session on both sides the exact route is
still required.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* Bind grant sessions to the caller, not the route

A session without its own route pointer reads the shared route of another
session, and 'manual' is not a session. The check now uses the caller's
bound session and skips the route only when caller, route and grant name
the same session. getzilla_approve.py binds CLAUDE_CODE_SESSION_ID.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* docs: bring QUICKSTART, START_HERE, REFERENCE, CHANGELOG and state up to date

- QUICKSTART: launcher, runtime evidence without report commits, route
  reconcile, review snapshots, light lane, and a disk cleanup section.
- START_HERE and REFERENCE: current main a45fbdd, correct v2.3.0 link,
  continuation at issue #134; REFERENCE lists all getzilla commands.
- PROJECT_STATE: current_continuation moves to issue #134; the finished
  PR #79 contour is kept as historical_pr79_continuation.
- CHANGELOG: 2.3.1 lists the work merged since 2026-10-21 (#121-#179).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* docs(readme): list every getzilla command and the current source state

A Commands section lists all launcher commands by task, with their main
options. The source line names what 2.3.1 adds since v2.3.0, and the
file map says where review copies live and how they are removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* docs: fix command wording found in review of #180

history takes a snapshot file, approve needs --reason, --add-reviewer
works with --reconcile, getzilla test falls back to serial unittest
without pytest-xdist, report overhead is per profile, and the state
record counts the merged PRs from #114.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* cleanup: close the #134 Low findings in inventory, snapshots and worktree checks

- Inventory: a linked .getzilla or runtime folder is not read; one entry
  budget covers the copy search and all copy sizes; an unreadable folder,
  a linked copy root or a cut size makes the report incomplete.
- Review snapshots: the parent-folder refusal has its own message, and
  the module says a snapshot holds committed content only.
- Tests pin the guards that mutants survived before: annotated tag
  peel, marker removal after a failed worktree add, the main-worktree
  base, the marker schema, the 0700 mode, unregistered folders, the
  refs/worktree check, a failed reflog read, the 2 s margins.
- getzilla status answers --help; a test runs --help for every command.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* cleanup: count each copy entry once and accept a search that uses exactly the budget

Review of #181: the copy folder listing was counted by the search and
again by its size, and a search that used the full budget reported
itself incomplete. Tests pin both boundaries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* contract: every Getzilla defect goes to a GitHub issue

AGENTS.md now requires an issue in Dimkox/Getzilla for each defect in
Getzilla itself, also one that was worked around: search first, no
duplicates, Low findings into the collecting issue, no secrets or
exploit commands, and an exact external-write grant first. Consumer
projects get the same rule in the installed contract, with a ready
issue text for the owner when filing upstream is not allowed. The
delivery skill adds it as the last step of a task.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* contract: own-repository issues are in the L5 standing consent

Review of #182: the new rule called issue writes an L5 process call
while the L5 scope named only merge, tag and release. The owner asked
for it, so the scope now covers the project's own GitHub issues; the
checks-green condition stays on merge, tag and release. The search
covers open and closed issues, the grant resource is named, consumer
consent is recorded as an exact grant, and a test pins the rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* contract: issue grants follow the exact-HEAD binding; pin the secret bans

Security review of #182: the rule said a tool grant lasts its TTL, but
external-write grants stay bound to route, change, HEAD and tree. The
test now also pins the bans on secrets and customer data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* tests: give the Node transparency adapter tests room on loaded runners (#187)

test_node_adapter_behavior timed out after 10 s on a busy public linux
runner while it only checks adapter behavior. Both Node calls now allow
60 s; the neighbouring stubborn-child test already allows 45 s.

Fixes #187.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* workflow: harness notices keep the route; spec and transition use the package (#185, #186)

- A prompt made only of <task-notification> or <system-reminder>
  envelopes keeps the active route like a short reply, and never
  creates a route. Text next to an envelope is a normal prompt.
- getzilla spec generate/validate --change-id use the package folder
  that change start created (the runtime one; legacy tracked packages
  stay readable), so no stray file lands in engineering/changes.
- getzilla change transition answers a refused move with exit 2 and
  the allowed next states, not a traceback.

Fixes #185.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* workflow: a notice skips routing only when no route exists (#188 review)

Review of #188: a notice next to a route of another session, or a
closed route, built no route, so the session fell back to that route.
Such a route is now replaced as before; the no-route rule applies only
when no route exists at all. The transition hint names allowed states
only for an invalid move, not for a gate refusal. Tests cover both
cases and envelope edge forms (zero-width tail, attributes, case,
crossed tags).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* fix: #134 slice B — runner verdicts, report escaping, protected-write session

- run_named_tests and run_trust_tests use _run_directory, so a failed
  cleanup of the run folder (a locked file on Windows) no longer
  replaces the test verdict.
- getzilla report prints journal route ids with control and format
  characters replaced by '?'.
- getzilla protected-write binds the caller session like approve, so a
  session-bound grant follows its later routes on that path too.
- Tests: cleanup error keeps both verdicts; hostile route id; the
  protected-write CLI with and without a session; the approve CLI
  GETZILLA_SESSION_ID fallback and CLAUDE_CODE_SESSION_ID precedence.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* fix: escape the report profile too; the cleanup test removes its folders (#189 review)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

---------

Co-authored-by: Claude <noreply@anthropic.com>
Dimkox added a commit that referenced this pull request Oct 25, 2026
* grants: a new route keeps a branch-bound protected-path grant

Every prompt starts a new route, so binding protected-path grants to
the route voided them on each user message and forced a new grant for
the same edit again and again. A branch-bound grant is already held to
the repository, branch ref, anchor ancestry, exact files and TTL, so
it no longer checks the route. Production and external-write grants
keep their exact route, HEAD and tree binding.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* grants: pin change_id and the scope guard in tests

The security review found that change_id is now the only task binding
of a branch-bound grant and that no test pinned it, nor the
protected-path scope guard. Add a test for each; both mutants are now
killed. Update the has_valid_approval docstring.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* grants: bind branch-bound grants to the session, not the route

Skipping the route broke session isolation: a grant issued in one
session also served another session in the same worktree
(tests/test_control_plane_sessions failed on CI). A protected-path
grant now records its session and checks that instead of the route,
so later prompts of the same session keep it and another session never
gets it. Without a known session on both sides the exact route is
still required.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* Bind grant sessions to the caller, not the route

A session without its own route pointer reads the shared route of another
session, and 'manual' is not a session. The check now uses the caller's
bound session and skips the route only when caller, route and grant name
the same session. getzilla_approve.py binds CLAUDE_CODE_SESSION_ID.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* docs: bring QUICKSTART, START_HERE, REFERENCE, CHANGELOG and state up to date

- QUICKSTART: launcher, runtime evidence without report commits, route
  reconcile, review snapshots, light lane, and a disk cleanup section.
- START_HERE and REFERENCE: current main a45fbdd, correct v2.3.0 link,
  continuation at issue #134; REFERENCE lists all getzilla commands.
- PROJECT_STATE: current_continuation moves to issue #134; the finished
  PR #79 contour is kept as historical_pr79_continuation.
- CHANGELOG: 2.3.1 lists the work merged since 2026-10-21 (#121-#179).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* docs(readme): list every getzilla command and the current source state

A Commands section lists all launcher commands by task, with their main
options. The source line names what 2.3.1 adds since v2.3.0, and the
file map says where review copies live and how they are removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* docs: fix command wording found in review of #180

history takes a snapshot file, approve needs --reason, --add-reviewer
works with --reconcile, getzilla test falls back to serial unittest
without pytest-xdist, report overhead is per profile, and the state
record counts the merged PRs from #114.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* cleanup: close the #134 Low findings in inventory, snapshots and worktree checks

- Inventory: a linked .getzilla or runtime folder is not read; one entry
  budget covers the copy search and all copy sizes; an unreadable folder,
  a linked copy root or a cut size makes the report incomplete.
- Review snapshots: the parent-folder refusal has its own message, and
  the module says a snapshot holds committed content only.
- Tests pin the guards that mutants survived before: annotated tag
  peel, marker removal after a failed worktree add, the main-worktree
  base, the marker schema, the 0700 mode, unregistered folders, the
  refs/worktree check, a failed reflog read, the 2 s margins.
- getzilla status answers --help; a test runs --help for every command.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* cleanup: count each copy entry once and accept a search that uses exactly the budget

Review of #181: the copy folder listing was counted by the search and
again by its size, and a search that used the full budget reported
itself incomplete. Tests pin both boundaries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* contract: every Getzilla defect goes to a GitHub issue

AGENTS.md now requires an issue in Dimkox/Getzilla for each defect in
Getzilla itself, also one that was worked around: search first, no
duplicates, Low findings into the collecting issue, no secrets or
exploit commands, and an exact external-write grant first. Consumer
projects get the same rule in the installed contract, with a ready
issue text for the owner when filing upstream is not allowed. The
delivery skill adds it as the last step of a task.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* contract: own-repository issues are in the L5 standing consent

Review of #182: the new rule called issue writes an L5 process call
while the L5 scope named only merge, tag and release. The owner asked
for it, so the scope now covers the project's own GitHub issues; the
checks-green condition stays on merge, tag and release. The search
covers open and closed issues, the grant resource is named, consumer
consent is recorded as an exact grant, and a test pins the rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* contract: issue grants follow the exact-HEAD binding; pin the secret bans

Security review of #182: the rule said a tool grant lasts its TTL, but
external-write grants stay bound to route, change, HEAD and tree. The
test now also pins the bans on secrets and customer data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* tests: give the Node transparency adapter tests room on loaded runners (#187)

test_node_adapter_behavior timed out after 10 s on a busy public linux
runner while it only checks adapter behavior. Both Node calls now allow
60 s; the neighbouring stubborn-child test already allows 45 s.

Fixes #187.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* workflow: harness notices keep the route; spec and transition use the package (#185, #186)

- A prompt made only of <task-notification> or <system-reminder>
  envelopes keeps the active route like a short reply, and never
  creates a route. Text next to an envelope is a normal prompt.
- getzilla spec generate/validate --change-id use the package folder
  that change start created (the runtime one; legacy tracked packages
  stay readable), so no stray file lands in engineering/changes.
- getzilla change transition answers a refused move with exit 2 and
  the allowed next states, not a traceback.

Fixes #185.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* workflow: a notice skips routing only when no route exists (#188 review)

Review of #188: a notice next to a route of another session, or a
closed route, built no route, so the session fell back to that route.
Such a route is now replaced as before; the no-route rule applies only
when no route exists at all. The transition hint names allowed states
only for an invalid move, not for a gate refusal. Tests cover both
cases and envelope edge forms (zero-width tail, attributes, case,
crossed tags).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* fix: #134 slice B — runner verdicts, report escaping, protected-write session

- run_named_tests and run_trust_tests use _run_directory, so a failed
  cleanup of the run folder (a locked file on Windows) no longer
  replaces the test verdict.
- getzilla report prints journal route ids with control and format
  characters replaced by '?'.
- getzilla protected-write binds the caller session like approve, so a
  session-bound grant follows its later routes on that path too.
- Tests: cleanup error keeps both verdicts; hostile route id; the
  protected-write CLI with and without a session; the approve CLI
  GETZILLA_SESSION_ID fallback and CLAUDE_CODE_SESSION_ID precedence.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* fix: escape the report profile too; the cleanup test removes its folders (#189 review)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* test(eu-ai-act): cover the deferred negative cases from #122

- accepted_by: missing, empty, short or non-string role; missing,
  empty, malformed or impossible date.
- Matrix sources: ftp, gopher, file and mailto schemes and a URL
  without a host are refused.
- Attestation identity: attestation_id, key_id and policy_digest
  missing, empty or of the wrong type are refused.
- The verifier refusal uses a working executable inside the project,
  so only the location guard can stop it.
- The first audit call uses the captured providers, never the engine
  loader.
- An archive install (getzilla.zip, no inherited PYTHONPATH) finds the
  scaffold templates through STACK_DIR.

Each test fails when its guard is removed (7 of 7 mutants killed).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

---------

Co-authored-by: Claude <noreply@anthropic.com>
Dimkox added a commit that referenced this pull request Oct 25, 2026
…#192)

* grants: a new route keeps a branch-bound protected-path grant

Every prompt starts a new route, so binding protected-path grants to
the route voided them on each user message and forced a new grant for
the same edit again and again. A branch-bound grant is already held to
the repository, branch ref, anchor ancestry, exact files and TTL, so
it no longer checks the route. Production and external-write grants
keep their exact route, HEAD and tree binding.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* grants: pin change_id and the scope guard in tests

The security review found that change_id is now the only task binding
of a branch-bound grant and that no test pinned it, nor the
protected-path scope guard. Add a test for each; both mutants are now
killed. Update the has_valid_approval docstring.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* grants: bind branch-bound grants to the session, not the route

Skipping the route broke session isolation: a grant issued in one
session also served another session in the same worktree
(tests/test_control_plane_sessions failed on CI). A protected-path
grant now records its session and checks that instead of the route,
so later prompts of the same session keep it and another session never
gets it. Without a known session on both sides the exact route is
still required.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* Bind grant sessions to the caller, not the route

A session without its own route pointer reads the shared route of another
session, and 'manual' is not a session. The check now uses the caller's
bound session and skips the route only when caller, route and grant name
the same session. getzilla_approve.py binds CLAUDE_CODE_SESSION_ID.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* docs: bring QUICKSTART, START_HERE, REFERENCE, CHANGELOG and state up to date

- QUICKSTART: launcher, runtime evidence without report commits, route
  reconcile, review snapshots, light lane, and a disk cleanup section.
- START_HERE and REFERENCE: current main a45fbdd, correct v2.3.0 link,
  continuation at issue #134; REFERENCE lists all getzilla commands.
- PROJECT_STATE: current_continuation moves to issue #134; the finished
  PR #79 contour is kept as historical_pr79_continuation.
- CHANGELOG: 2.3.1 lists the work merged since 2026-10-21 (#121-#179).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* docs(readme): list every getzilla command and the current source state

A Commands section lists all launcher commands by task, with their main
options. The source line names what 2.3.1 adds since v2.3.0, and the
file map says where review copies live and how they are removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* docs: fix command wording found in review of #180

history takes a snapshot file, approve needs --reason, --add-reviewer
works with --reconcile, getzilla test falls back to serial unittest
without pytest-xdist, report overhead is per profile, and the state
record counts the merged PRs from #114.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* cleanup: close the #134 Low findings in inventory, snapshots and worktree checks

- Inventory: a linked .getzilla or runtime folder is not read; one entry
  budget covers the copy search and all copy sizes; an unreadable folder,
  a linked copy root or a cut size makes the report incomplete.
- Review snapshots: the parent-folder refusal has its own message, and
  the module says a snapshot holds committed content only.
- Tests pin the guards that mutants survived before: annotated tag
  peel, marker removal after a failed worktree add, the main-worktree
  base, the marker schema, the 0700 mode, unregistered folders, the
  refs/worktree check, a failed reflog read, the 2 s margins.
- getzilla status answers --help; a test runs --help for every command.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* cleanup: count each copy entry once and accept a search that uses exactly the budget

Review of #181: the copy folder listing was counted by the search and
again by its size, and a search that used the full budget reported
itself incomplete. Tests pin both boundaries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* contract: every Getzilla defect goes to a GitHub issue

AGENTS.md now requires an issue in Dimkox/Getzilla for each defect in
Getzilla itself, also one that was worked around: search first, no
duplicates, Low findings into the collecting issue, no secrets or
exploit commands, and an exact external-write grant first. Consumer
projects get the same rule in the installed contract, with a ready
issue text for the owner when filing upstream is not allowed. The
delivery skill adds it as the last step of a task.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* contract: own-repository issues are in the L5 standing consent

Review of #182: the new rule called issue writes an L5 process call
while the L5 scope named only merge, tag and release. The owner asked
for it, so the scope now covers the project's own GitHub issues; the
checks-green condition stays on merge, tag and release. The search
covers open and closed issues, the grant resource is named, consumer
consent is recorded as an exact grant, and a test pins the rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* contract: issue grants follow the exact-HEAD binding; pin the secret bans

Security review of #182: the rule said a tool grant lasts its TTL, but
external-write grants stay bound to route, change, HEAD and tree. The
test now also pins the bans on secrets and customer data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* tests: give the Node transparency adapter tests room on loaded runners (#187)

test_node_adapter_behavior timed out after 10 s on a busy public linux
runner while it only checks adapter behavior. Both Node calls now allow
60 s; the neighbouring stubborn-child test already allows 45 s.

Fixes #187.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* workflow: harness notices keep the route; spec and transition use the package (#185, #186)

- A prompt made only of <task-notification> or <system-reminder>
  envelopes keeps the active route like a short reply, and never
  creates a route. Text next to an envelope is a normal prompt.
- getzilla spec generate/validate --change-id use the package folder
  that change start created (the runtime one; legacy tracked packages
  stay readable), so no stray file lands in engineering/changes.
- getzilla change transition answers a refused move with exit 2 and
  the allowed next states, not a traceback.

Fixes #185.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* workflow: a notice skips routing only when no route exists (#188 review)

Review of #188: a notice next to a route of another session, or a
closed route, built no route, so the session fell back to that route.
Such a route is now replaced as before; the no-route rule applies only
when no route exists at all. The transition hint names allowed states
only for an invalid move, not for a gate refusal. Tests cover both
cases and envelope edge forms (zero-width tail, attributes, case,
crossed tags).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* fix: #134 slice B — runner verdicts, report escaping, protected-write session

- run_named_tests and run_trust_tests use _run_directory, so a failed
  cleanup of the run folder (a locked file on Windows) no longer
  replaces the test verdict.
- getzilla report prints journal route ids with control and format
  characters replaced by '?'.
- getzilla protected-write binds the caller session like approve, so a
  session-bound grant follows its later routes on that path too.
- Tests: cleanup error keeps both verdicts; hostile route id; the
  protected-write CLI with and without a session; the approve CLI
  GETZILLA_SESSION_ID fallback and CLAUDE_CODE_SESSION_ID precedence.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* fix: escape the report profile too; the cleanup test removes its folders (#189 review)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* test(eu-ai-act): cover the deferred negative cases from #122

- accepted_by: missing, empty, short or non-string role; missing,
  empty, malformed or impossible date.
- Matrix sources: ftp, gopher, file and mailto schemes and a URL
  without a host are refused.
- Attestation identity: attestation_id, key_id and policy_digest
  missing, empty or of the wrong type are refused.
- The verifier refusal uses a working executable inside the project,
  so only the location guard can stop it.
- The first audit call uses the captured providers, never the engine
  loader.
- An archive install (getzilla.zip, no inherited PYTHONPATH) finds the
  scaffold templates through STACK_DIR.

Each test fails when its guard is removed (7 of 7 mutants killed).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* fix(eu-ai-act): confirmation and review dates must be past YYYY-MM-DD (#191)

date.fromisoformat on Python 3.11+ also accepts 20261020 and week dates
such as 2026-W43-1, and str() let an integer through. A future date
also passed as a human confirmation.

- _iso_day accepts only a YYYY-MM-DD string.
- A class confirmation, an exemption confirmation and a high-residual
  accepted_by refuse a date after the evaluation day.
- A risk record's reviewed date uses the same parser and refuses a
  future date.

Tests cover the basic, integer, week and future forms for each caller.
8 of 8 guard mutants are killed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

---------

Co-authored-by: Claude <noreply@anthropic.com>
Dimkox added a commit that referenced this pull request Oct 25, 2026
… repo (#194)

* grants: a new route keeps a branch-bound protected-path grant

Every prompt starts a new route, so binding protected-path grants to
the route voided them on each user message and forced a new grant for
the same edit again and again. A branch-bound grant is already held to
the repository, branch ref, anchor ancestry, exact files and TTL, so
it no longer checks the route. Production and external-write grants
keep their exact route, HEAD and tree binding.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* grants: pin change_id and the scope guard in tests

The security review found that change_id is now the only task binding
of a branch-bound grant and that no test pinned it, nor the
protected-path scope guard. Add a test for each; both mutants are now
killed. Update the has_valid_approval docstring.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* grants: bind branch-bound grants to the session, not the route

Skipping the route broke session isolation: a grant issued in one
session also served another session in the same worktree
(tests/test_control_plane_sessions failed on CI). A protected-path
grant now records its session and checks that instead of the route,
so later prompts of the same session keep it and another session never
gets it. Without a known session on both sides the exact route is
still required.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* Bind grant sessions to the caller, not the route

A session without its own route pointer reads the shared route of another
session, and 'manual' is not a session. The check now uses the caller's
bound session and skips the route only when caller, route and grant name
the same session. getzilla_approve.py binds CLAUDE_CODE_SESSION_ID.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* docs: bring QUICKSTART, START_HERE, REFERENCE, CHANGELOG and state up to date

- QUICKSTART: launcher, runtime evidence without report commits, route
  reconcile, review snapshots, light lane, and a disk cleanup section.
- START_HERE and REFERENCE: current main a45fbdd, correct v2.3.0 link,
  continuation at issue #134; REFERENCE lists all getzilla commands.
- PROJECT_STATE: current_continuation moves to issue #134; the finished
  PR #79 contour is kept as historical_pr79_continuation.
- CHANGELOG: 2.3.1 lists the work merged since 2026-10-21 (#121-#179).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* docs(readme): list every getzilla command and the current source state

A Commands section lists all launcher commands by task, with their main
options. The source line names what 2.3.1 adds since v2.3.0, and the
file map says where review copies live and how they are removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* docs: fix command wording found in review of #180

history takes a snapshot file, approve needs --reason, --add-reviewer
works with --reconcile, getzilla test falls back to serial unittest
without pytest-xdist, report overhead is per profile, and the state
record counts the merged PRs from #114.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* cleanup: close the #134 Low findings in inventory, snapshots and worktree checks

- Inventory: a linked .getzilla or runtime folder is not read; one entry
  budget covers the copy search and all copy sizes; an unreadable folder,
  a linked copy root or a cut size makes the report incomplete.
- Review snapshots: the parent-folder refusal has its own message, and
  the module says a snapshot holds committed content only.
- Tests pin the guards that mutants survived before: annotated tag
  peel, marker removal after a failed worktree add, the main-worktree
  base, the marker schema, the 0700 mode, unregistered folders, the
  refs/worktree check, a failed reflog read, the 2 s margins.
- getzilla status answers --help; a test runs --help for every command.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* cleanup: count each copy entry once and accept a search that uses exactly the budget

Review of #181: the copy folder listing was counted by the search and
again by its size, and a search that used the full budget reported
itself incomplete. Tests pin both boundaries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* contract: every Getzilla defect goes to a GitHub issue

AGENTS.md now requires an issue in Dimkox/Getzilla for each defect in
Getzilla itself, also one that was worked around: search first, no
duplicates, Low findings into the collecting issue, no secrets or
exploit commands, and an exact external-write grant first. Consumer
projects get the same rule in the installed contract, with a ready
issue text for the owner when filing upstream is not allowed. The
delivery skill adds it as the last step of a task.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* contract: own-repository issues are in the L5 standing consent

Review of #182: the new rule called issue writes an L5 process call
while the L5 scope named only merge, tag and release. The owner asked
for it, so the scope now covers the project's own GitHub issues; the
checks-green condition stays on merge, tag and release. The search
covers open and closed issues, the grant resource is named, consumer
consent is recorded as an exact grant, and a test pins the rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* contract: issue grants follow the exact-HEAD binding; pin the secret bans

Security review of #182: the rule said a tool grant lasts its TTL, but
external-write grants stay bound to route, change, HEAD and tree. The
test now also pins the bans on secrets and customer data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* tests: give the Node transparency adapter tests room on loaded runners (#187)

test_node_adapter_behavior timed out after 10 s on a busy public linux
runner while it only checks adapter behavior. Both Node calls now allow
60 s; the neighbouring stubborn-child test already allows 45 s.

Fixes #187.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* workflow: harness notices keep the route; spec and transition use the package (#185, #186)

- A prompt made only of <task-notification> or <system-reminder>
  envelopes keeps the active route like a short reply, and never
  creates a route. Text next to an envelope is a normal prompt.
- getzilla spec generate/validate --change-id use the package folder
  that change start created (the runtime one; legacy tracked packages
  stay readable), so no stray file lands in engineering/changes.
- getzilla change transition answers a refused move with exit 2 and
  the allowed next states, not a traceback.

Fixes #185.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* workflow: a notice skips routing only when no route exists (#188 review)

Review of #188: a notice next to a route of another session, or a
closed route, built no route, so the session fell back to that route.
Such a route is now replaced as before; the no-route rule applies only
when no route exists at all. The transition hint names allowed states
only for an invalid move, not for a gate refusal. Tests cover both
cases and envelope edge forms (zero-width tail, attributes, case,
crossed tags).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* fix: #134 slice B — runner verdicts, report escaping, protected-write session

- run_named_tests and run_trust_tests use _run_directory, so a failed
  cleanup of the run folder (a locked file on Windows) no longer
  replaces the test verdict.
- getzilla report prints journal route ids with control and format
  characters replaced by '?'.
- getzilla protected-write binds the caller session like approve, so a
  session-bound grant follows its later routes on that path too.
- Tests: cleanup error keeps both verdicts; hostile route id; the
  protected-write CLI with and without a session; the approve CLI
  GETZILLA_SESSION_ID fallback and CLAUDE_CODE_SESSION_ID precedence.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* fix: escape the report profile too; the cleanup test removes its folders (#189 review)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* test(eu-ai-act): cover the deferred negative cases from #122

- accepted_by: missing, empty, short or non-string role; missing,
  empty, malformed or impossible date.
- Matrix sources: ftp, gopher, file and mailto schemes and a URL
  without a host are refused.
- Attestation identity: attestation_id, key_id and policy_digest
  missing, empty or of the wrong type are refused.
- The verifier refusal uses a working executable inside the project,
  so only the location guard can stop it.
- The first audit call uses the captured providers, never the engine
  loader.
- An archive install (getzilla.zip, no inherited PYTHONPATH) finds the
  scaffold templates through STACK_DIR.

Each test fails when its guard is removed (7 of 7 mutants killed).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* fix(eu-ai-act): confirmation and review dates must be past YYYY-MM-DD (#191)

date.fromisoformat on Python 3.11+ also accepts 20261020 and week dates
such as 2026-W43-1, and str() let an integer through. A future date
also passed as a human confirmation.

- _iso_day accepts only a YYYY-MM-DD string.
- A class confirmation, an exemption confirmation and a high-residual
  accepted_by refuse a date after the evaluation day.
- A risk record's reviewed date uses the same parser and refuses a
  future date.

Tests cover the basic, integer, week and future forms for each caller.
8 of 8 guard mutants are killed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* fix(policy): guard every MCP write tool and bind GitHub writes to the repo (#193, #184)

SIDE_EFFECT_TOOL matched a write verb only right after `__`, so GitHub
MCP tools with the verb inside the name passed with no grant:
issue_write, add_issue_comment, push_files, resolve_review_thread,
enable_pr_auto_merge, fork_repository, actions_run_trigger and more.

- The regex now covers more leading verbs, a `write` token anywhere and
  actions_run. Read tools (get_*, list_*, search_*, *_read,
  get_check_run, run_secret_scanning) stay unguarded.
- A GitHub MCP write that names owner/repo must target the repository
  that grants bind to (case-insensitive). Another repository, a partial
  or non-string target, or a project without a GitHub origin is
  refused. A call without owner/repo keeps the tool-name grant check.

Tests pin 18 write tools, 13 read tools and the repository binding.
10 of 10 guard mutants are killed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* fix(policy): GitHub MCP tools fail closed; camelCase and hyphen verbs (#193 review)

The review of 172e4cf found write tools that the verb list still
missed: run_workflow, manage_*_subscription, star/unstar_repository,
reprioritize_sub_issue on GitHub, and camelCase or hyphen names on
other servers (executeWrite, createJiraIssue, batchUpdate,
management-projects-create). A GitHub server under another name also
skipped the repository binding.

- mcp_side_effect: a server whose name contains "github" treats every
  tool as a write unless it is a known read (get_, list_, search_,
  download_, *_read, actions/projects get/list, run_secret_scanning).
- Other servers: a verb also ends at an uppercase letter and may start
  a "-" token; manage, star, unstar, reprioritize, run and transition
  join the list.
- The repository binding covers every GitHub-named server, and owner
  and repo must be plain GitHub names ([A-Za-z0-9._-]).
- policy.sensitive_action uses the same mcp_side_effect.

14 of 14 guard mutants are killed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* fix(policy): keep actions_run on every server; match verbs in the action only (#193)

c65d5ea dropped the actions_run branch, so actions_run_trigger on a
GitHub server named without "github" (mcp__gh__) needed no grant again.
It also scanned the whole tool name, so a verb in a server name such as
cloud-run made every tool on that server a write.

- SIDE_EFFECT_TOOL matches ^actions_run again.
- mcp_side_effect scans only the action part of the tool name.

16 of 16 guard mutants are killed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

* fix(policy): scan every segment after the MCP server name (#193 review)

5be3a29 scanned only the last `__` segment, so a verb in an earlier
segment (mcp__x__delete__file) passed as a read with no grant. The
action is now everything after the server segment.

A write hint that appears only in the server name (slack-post) is still
not seen; that limit is tracked in #195 and pinned as a known read.

17 of 17 guard mutants are killed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BhxEnEALZRsc7kaPwG2kiR

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Router] Background task notifications are routed as new tasks

2 participants