Visitar URL original
Re-Raise the Interrupt Signal and Exempt a Script That Execs Its Process by ptr727 · Pull Request #4134 · ptr727/ProjectTemplate · GitHub
Skip to content

Re-Raise the Interrupt Signal and Exempt a Script That Execs Its Process - #4134

Merged
ptr727 merged 6 commits into
developfrom
burndown/interrupts-reraise
Nov 13, 2026
Merged

ptr727 merged 6 commits into
developfrom
burndown/interrupts-reraise

Conversation

@ptr727

@ptr727 ptr727 commented Nov 13, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • CODESTYLE.md "Interrupts": after its cleanup, an interrupted script re-raises the signal rather than calling exit 130 or exit 143. A shell still reports 130 or 143. At Ctrl-C, a calling shell's loop now stops instead of starting its next iteration. A launcher such as uv run exits with the status rather than dying by the signal, and the rule says so. The mid-run test asserts the script died by the signal, and starts the script with its interpreter directly.
  • "Interrupts in Python": the entry point flushes its output under contextlib.suppress(OSError), restores the default handler with signal.signal(signum, signal.SIG_DFL), and re-sends the signal with os.kill(os.getpid(), signum). The re-raise runs outside every with block and finally clause, and no cleanup on its path relies on an atexit handler or a finalizer. A process the signal does not end, such as PID 1 in a container, then exits 128 plus the signal number. On Windows, where os.kill would end the process with the signal number as its status, it keeps exiting 130.
  • "Interrupts in Shell": each trap clears itself with trap - INT or trap - TERM, re-sends the signal with kill -s INT "$$" or kill -s TERM "$$", then ends with exit 130 or exit 143, which runs only where the signal does not end the script, such as PID 1. The EXIT trap is set before the INT and TERM traps, since bash skips it when a TERM trap set ahead of it re-sends SIGTERM.
  • "Interrupts" exempts a script that ends by exec-ing its long-running process, such as a container entrypoint or an s6 or runit run script. A background child may be handed across the exec, neither stopped nor waited for, where something else stops it, such as a container's teardown. Anything else the script holds is released before the exec. A script holding nothing else at any point before the exec owes no trap and no signal test. As PID 1, such a script ignores a SIGTERM that arrives before its exec, and the rule says so. "Interrupts in Shell" points at that exemption from its trap and wait bullets.
  • python-codestyle and shell-codestyle regenerated through scripts/build_dist.py. python-codestyle's description is unchanged.

Verification

A constructed probe, run under setsid --wait timeout: a non-interactive bash loop runs a child three times, and SIGINT goes to the loop's whole process group, as Ctrl-C does. With bash 5.2, Python 3.13, and uv 0.13:

Child Loop after SIGINT
bash, trap ends with exit 130 runs iterations 2 and 3, exits 0
bash, trap re-raises stops, exits 130, EXIT trap ran
Python, sys.exit(130) runs iterations 2 and 3, exits 0
Python, re-raise stops, exits 130, finally ran
Python, re-raise, through uv run --script runs on, uv exits 130

With SIGTERM sent to the child alone, the loop reads status 143 from both forms. Further probes: a bash TERM trap set before the EXIT trap skips the EXIT trap on its re-sent SIGTERM, and runs it when set after. A Python PID 1 in a PID namespace survives its own re-sent SIGTERM and reaches the 143 fallback. Bash as PID 1 with no EXIT trap survives its own re-sent SIGTERM and runs on, and the trailing exit 143 ends it. Bash as PID 1 with no traps ignores a SIGTERM sent from outside its namespace. build_dist.py --check, the prose gate, and markdownlint pass.

Local review

Each push carries a recorded local pass. The findings those passes raised were fixed on this branch, so none stays open.

Closes on promotion: #4084, #4097

🤖 Generated with Claude Code

ptr727 and others added 3 commits November 12, 2026 21:27
A script that calls exit 130 has not died by the signal, so a calling
bash loop reads Ctrl-C as an ordinary failure and runs its next
iteration. Re-raising after cleanup keeps the 130 or 143 a shell reports
and makes the signal death visible to the caller.

A script whose last step is an exec into its long-running process hands
the signal straight to that process, so it owes no trap, no wait, and no
signal test for it, including a background child handed across the exec.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ocess

A TERM trap set before the EXIT trap leaves the re-sent SIGTERM skipping
the EXIT trap. A Python PID 1 survives its own re-sent signal, and a
flush into a pipe the same Ctrl-C closed raises. The loop-stop claim
holds only where Ctrl-C reaches the calling shell, and a child handed
across an exec needs something else to stop it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…kips

Bash as PID 1 with no EXIT trap survives its own re-sent SIGTERM and
carries on, so the trap ends with exit 130 or 143. Python's default
action skips atexit handlers and finalizers as well as the flush. The
shell exemption sentence now matches the general one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings November 13, 2026 05:43
@coderabbitai

coderabbitai Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 34 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration

Commits

Reviewing files that changed from the base of the PR and between fa06887 and 43b94cb.

Files ignored due to path filters: 6

  • .claude-plugin/fleet-skills/.source-digests/python-codestyle is excluded by !.claude-plugin/fleet-skills/**
  • .claude-plugin/fleet-skills/.source-digests/shell-codestyle is excluded by !.claude-plugin/fleet-skills/**
  • .claude-plugin/fleet-skills/skills/python-codestyle/SKILL.md is excluded by !.claude-plugin/fleet-skills/**
  • .claude-plugin/fleet-skills/skills/shell-codestyle/SKILL.md is excluded by !.claude-plugin/fleet-skills/**
  • .github/skills/python-codestyle/SKILL.md is excluded by !.github/skills/**
  • .github/skills/shell-codestyle/SKILL.md is excluded by !.github/skills/**
Files selected for processing: 3

  • .agents/skills/python-codestyle/SKILL.md
  • .agents/skills/shell-codestyle/SKILL.md
  • CODESTYLE.md
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@ptr727

ptr727 commented Nov 13, 2026

Copy link
Copy Markdown
Owner Author

A recorded local strict-review pass covers head 4fd4afb559994729ac1853cc692e8076515ebc99, the content this pull request carries at that commit against develop, and it recorded 3 findings.

A launcher such as uv run exits with the child's status rather than
dying by its signal, so a loop over it runs on and a test through it
reads 130 or 143. The exec exemption's "nothing else" holds before the
exec, not only at it. The loop-stop claim no longer names the terminal
as a case where Ctrl-C reaches the shell.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The documentation still contains three active correctness issues about signal handling and exemption wording, so the launcher behavior and required trap rules remain ambiguous.

3 open issues
What changed in this PR

This pull request updates the fleet's interrupt-handling guidance so Python and shell scripts re-raise signals after cleanup, while documenting a scoped exemption for scripts that exec their long-running process.

Changes:

  • Clarifies signal re-raising, cleanup behavior, PID 1 fallbacks, and signal-death test expectations.
  • Documents the exec exemption and corresponding shell trap and wait guidance.
  • Regenerates authored skills, GitHub Copilot skills, Claude plugin skills, and source digests.
File Description
CODESTYLE.md Defines the canonical interrupt-handling rules and the scoped exec exemption.
.github/​skills/​shell-codestyle/​SKILL.md Provides the regenerated shell-codestyle guidance for GitHub Copilot.
.github/​skills/​python-codestyle/​SKILL.md Provides the regenerated Python-codestyle guidance for GitHub Copilot.
.claude-plugin/​fleet-skills/​skills/​shell-codestyle/​SKILL.md Provides the regenerated shell-codestyle guidance for the Claude plugin.
.claude-plugin/​fleet-skills/​skills/​python-codestyle/​SKILL.md Provides the regenerated Python-codestyle guidance for the Claude plugin.
.claude-plugin/​fleet-skills/​.source-digests/​shell-codestyle Records the regenerated shell-codestyle source digest.
.claude-plugin/​fleet-skills/​.source-digests/​python-codestyle Records the regenerated Python-codestyle source digest.
.agents/​skills/​shell-codestyle/​SKILL.md Carries the regenerated shell-codestyle guidance in the authored skill.
.agents/​skills/​python-codestyle/​SKILL.md Carries the regenerated Python-codestyle guidance in the authored skill.

Review effort: Lite

Comment thread CODESTYLE.md Resolved
Comment thread CODESTYLE.md Resolved
Comment thread CODESTYLE.md Resolved
The default action ends the process where the re-raise runs, so a with
block or finally clause around it never runs. A launcher such as uv run
hides the signal death a mid-run test asserts, so the test starts the
script with its interpreter directly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov

codecov Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 76.69%. Comparing base (fa06887) to head (43b94cb).
⚠️ Report is 1 commits behind head on develop.

Additional details and impacted files
@@           Coverage Diff            @@
##           develop    #4134   +/-   ##
========================================
  Coverage    76.69%   76.69%           
========================================
  Files           40       40           
  Lines        14146    14146           
========================================
  Hits         10849    10849           
  Misses        3297     3297           
Flag Coverage Δ
python-3.13 76.69% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

A shell script's EXIT trap cleans up as the re-raised signal ends it, so
the rule no longer orders cleanup before the re-raise. An exec script
with no trap that runs as PID 1 ignores a SIGTERM before its exec.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ptr727

ptr727 commented Nov 13, 2026

Copy link
Copy Markdown
Owner Author

A recorded local strict-review pass covers head 43b94cb0d67c1ca1815372c3d2c9c95d5b670f75, the content this pull request carries at that commit against develop, and it recorded 0 findings.

@ptr727

ptr727 commented Nov 13, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@ptr727

ptr727 commented Nov 13, 2026

Copy link
Copy Markdown
Owner Author

/review

@coderabbitai

coderabbitai Bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@ptr727
ptr727 merged commit bbbb33b into develop Nov 13, 2026
13 checks passed
@ptr727
ptr727 deleted the burndown/interrupts-reraise branch November 13, 2026 06:37
ptr727 added a commit that referenced this pull request Nov 13, 2026
… Rules (#4189)

## Summary

Promotes the backlog-burndown rounds and changes from other hub sessions
from `develop` to `main`.

- Hooks and the prose gate: #4132, #4134, #4136, #4145, #4152, #4184.
The Husky hook reads its path list once and diffs a merge against
`MERGE_HEAD`. Interrupts re-raise their signal, a Markdown code span
reads as quoted data, and the gate picks a commit's diff base and
recognizes a conflicted promotion's branch cut from `main`.
- Procedures and carried rules: #4133, #4139, #4141, #4149, #4166,
#4177, #4179, #4183, #4185. Resync, audit and check-this-repo procedure
gaps, code style and shell interrupt rules, review-loop gaps across four
skills, the context and delegation section of `AGENTS.md`, question
rules in governance, the promotion line in pull request bodies,
closing-keyword behavior on promotion, and the history-rewrite premise.
- Review and cleanup tooling: #4138, #4148, #4154, #4156, #4157, #4163,
#4164, #4168, #4174, #4180. Cleanliness reads, parked handoffs, the
backlog report's JSON output, exact inline script pins, trusted inputs,
env-file includes, the bounded review wait, side-reviewer matching, and
a Copilot billing-failure notice read as a refusal.
- Workflow and runbook contract: #4153, #4155, #4169, #4171, #4178,
#4182. The runtime-secrets check, a registry entry and spec references,
the Copilot runbook pointers, credential-free checkout steps, and the
deploy-key and runner wording.
- From other hub sessions: #4159 (a repository's own .NET line under a
fleet default), #4161 (the 1Password CLI as an optional host tool),
#4162 (Codex's Windows installer and one managed opencode copy). These
carry no promotion line.

#4182 carries no promotion line by design, and #4175 holds the split-out
part of #4057's scope. Both #1448 and #4175 stay open.

Fixes #1071
Fixes #1154
Fixes #1391
Fixes #1471
Fixes #1594
Fixes #1620
Fixes #1627
Fixes #1650
Fixes #1801
Fixes #2853
Fixes #3620
Fixes #3668
Fixes #3697
Fixes #3766
Fixes #3787
Fixes #3837
Fixes #3840
Fixes #3842
Fixes #3844
Fixes #3865
Fixes #3882
Fixes #3890
Fixes #3894
Fixes #3912
Fixes #3916
Fixes #3954
Fixes #4014
Fixes #4015
Fixes #4016
Fixes #4043
Fixes #4050
Fixes #4057
Fixes #4058
Fixes #4062
Fixes #4084
Fixes #4097
Fixes #4098
Fixes #4099
Fixes #4104
Fixes #4108
Fixes #4114
Fixes #4115
Fixes #4117
Fixes #4118
Fixes #4119
Fixes #4121
Fixes #4122
Fixes #4123
Fixes #4131
Fixes #4135
Fixes #4140
Fixes #4142
Fixes #4143
Fixes #4144
Fixes #4151

🤖 Generated with [Claude Code](https://claude.com/claude-code)
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.

2 participants