housebroken-cli 0.6.8__tar.gz → 0.6.9__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. {housebroken_cli-0.6.8 → housebroken_cli-0.6.9}/PKG-INFO +3 -3
  2. {housebroken_cli-0.6.8 → housebroken_cli-0.6.9}/README.md +2 -2
  3. {housebroken_cli-0.6.8 → housebroken_cli-0.6.9}/pyproject.toml +1 -1
  4. {housebroken_cli-0.6.8 → housebroken_cli-0.6.9}/scripts/branch-check.sh +57 -3
  5. {housebroken_cli-0.6.8 → housebroken_cli-0.6.9}/scripts/review.sh +23 -2
  6. {housebroken_cli-0.6.8 → housebroken_cli-0.6.9}/skills/housebroken/SKILL.md +13 -3
  7. housebroken_cli-0.6.9/src/housebroken/__init__.py +1 -0
  8. housebroken_cli-0.6.8/src/housebroken/__init__.py +0 -1
  9. {housebroken_cli-0.6.8 → housebroken_cli-0.6.9}/.gitignore +0 -0
  10. {housebroken_cli-0.6.8 → housebroken_cli-0.6.9}/LICENSE +0 -0
  11. {housebroken_cli-0.6.8 → housebroken_cli-0.6.9}/bin/housebroken +0 -0
  12. {housebroken_cli-0.6.8 → housebroken_cli-0.6.9}/hatch_build.py +0 -0
  13. {housebroken_cli-0.6.8 → housebroken_cli-0.6.9}/scripts/check-ai-policy.sh +0 -0
  14. {housebroken_cli-0.6.8 → housebroken_cli-0.6.9}/scripts/claim-check.sh +0 -0
  15. {housebroken_cli-0.6.8 → housebroken_cli-0.6.9}/scripts/comment-census.sh +0 -0
  16. {housebroken_cli-0.6.8 → housebroken_cli-0.6.9}/scripts/comment-check.sh +0 -0
  17. {housebroken_cli-0.6.8 → housebroken_cli-0.6.9}/scripts/diff-defaults.sh +0 -0
  18. {housebroken_cli-0.6.8 → housebroken_cli-0.6.9}/scripts/distinct-outside.sh +0 -0
  19. {housebroken_cli-0.6.8 → housebroken_cli-0.6.9}/scripts/file-issue.sh +0 -0
  20. {housebroken_cli-0.6.8 → housebroken_cli-0.6.9}/scripts/file-pr.sh +0 -0
  21. {housebroken_cli-0.6.8 → housebroken_cli-0.6.9}/scripts/fork-hygiene.sh +0 -0
  22. {housebroken_cli-0.6.8 → housebroken_cli-0.6.9}/scripts/inbox.sh +0 -0
  23. {housebroken_cli-0.6.8 → housebroken_cli-0.6.9}/scripts/notes.sh +0 -0
  24. {housebroken_cli-0.6.8 → housebroken_cli-0.6.9}/scripts/pr-sweep.sh +0 -0
  25. {housebroken_cli-0.6.8 → housebroken_cli-0.6.9}/scripts/prior-art.sh +0 -0
  26. {housebroken_cli-0.6.8 → housebroken_cli-0.6.9}/scripts/verify-filed-pr.sh +0 -0
  27. {housebroken_cli-0.6.8 → housebroken_cli-0.6.9}/src/housebroken/cli.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: housebroken-cli
3
- Version: 0.6.8
3
+ Version: 0.6.9
4
4
  Summary: Agent-written pull requests that do not make a mess in someone else's house.
5
5
  Project-URL: Repository, https://github.com/lenamonj/housebroken
6
6
  License-Expression: MIT
@@ -76,8 +76,8 @@ Before the first pull request to an organization: CLA, DCO, signed-commit requir
76
76
  A memory-safety, remote-abort, injection or path-escape finding goes by the project's SECURITY.md route, privately, and never becomes a public pull request until the project answers.
77
77
 
78
78
  **9. File through the gate.**
79
- `branch-check.sh` refuses a dirty working tree, a file whose mode disagrees with its siblings, a file the repository's own `.gitignore` excludes, a working artifact, a commit carrying a tool trailer, a session link or a tool identity, a sign-off naming a username, a branch not on top of its base, and any comment added to code; it prints every absolute claim in added prose for falsification, and stamps the head it passed.
80
- `review.sh` names the adversarial reviewer: a different model from the one that wrote the change, one tier down, never below Sonnet. The reviewer gets a fresh context, hard read-only limits and an attack list that starts with every claim the prose makes and includes the form of the code: the reviewer writes the changed block the way the strongest engineer in that language would, in the repository's own idioms, and a smaller or clearer version is a finding; every finding carries evidence it produced itself, and its report is bound to the head and the text it read. A fix is a new head and gets a new review.
79
+ `branch-check.sh` refuses a dirty working tree, a file whose mode disagrees with its siblings, a file the repository's own `.gitignore` excludes, a working artifact, a commit carrying a tool trailer, a session link or a tool identity, a sign-off naming a username, a branch not on top of its base, any comment added to code, a warning suppression no build log shows firing, and reflection added to a .NET project that declares AOT or trim support without an AOT publish log; it prints every absolute claim in added prose for falsification, and stamps the head it passed.
80
+ `review.sh` names the adversarial reviewer: a different model from the one that wrote the change, one tier down, never below Sonnet. The reviewer gets a fresh context, hard read-only limits, and before it reads the diff it writes its own fix from the bug alone, so it is not anchored on ours; the report names that fix and the gate refuses one that does not. Its attack list starts with every claim the prose makes and includes the form of the code: the reviewer writes the changed block the way the strongest engineer in that language would, in the repository's own idioms, and a smaller or clearer version is a finding; every finding carries evidence it produced itself, and its report is bound to the head and the text it read. A fix is a new head and gets a new review.
81
81
  `file-pr.sh` is the only way a pull request is opened. It refuses without a prior-art printout under a day old, a policy printout under a day old that does not read BAN, a body that discloses when the policy asks, a branch stamp for the exact head, and a POST AS IS review of that head and that body.
82
82
  `file-issue.sh` is the only way an issue is opened. It refuses without the same prior-art and policy printouts, refuses the same prose, and refuses a body that mentions a fix, a patch or a pull request without a GitHub link to the branch or commit, so work that exists is attributable to whoever did it.
83
83
 
@@ -64,8 +64,8 @@ Before the first pull request to an organization: CLA, DCO, signed-commit requir
64
64
  A memory-safety, remote-abort, injection or path-escape finding goes by the project's SECURITY.md route, privately, and never becomes a public pull request until the project answers.
65
65
 
66
66
  **9. File through the gate.**
67
- `branch-check.sh` refuses a dirty working tree, a file whose mode disagrees with its siblings, a file the repository's own `.gitignore` excludes, a working artifact, a commit carrying a tool trailer, a session link or a tool identity, a sign-off naming a username, a branch not on top of its base, and any comment added to code; it prints every absolute claim in added prose for falsification, and stamps the head it passed.
68
- `review.sh` names the adversarial reviewer: a different model from the one that wrote the change, one tier down, never below Sonnet. The reviewer gets a fresh context, hard read-only limits and an attack list that starts with every claim the prose makes and includes the form of the code: the reviewer writes the changed block the way the strongest engineer in that language would, in the repository's own idioms, and a smaller or clearer version is a finding; every finding carries evidence it produced itself, and its report is bound to the head and the text it read. A fix is a new head and gets a new review.
67
+ `branch-check.sh` refuses a dirty working tree, a file whose mode disagrees with its siblings, a file the repository's own `.gitignore` excludes, a working artifact, a commit carrying a tool trailer, a session link or a tool identity, a sign-off naming a username, a branch not on top of its base, any comment added to code, a warning suppression no build log shows firing, and reflection added to a .NET project that declares AOT or trim support without an AOT publish log; it prints every absolute claim in added prose for falsification, and stamps the head it passed.
68
+ `review.sh` names the adversarial reviewer: a different model from the one that wrote the change, one tier down, never below Sonnet. The reviewer gets a fresh context, hard read-only limits, and before it reads the diff it writes its own fix from the bug alone, so it is not anchored on ours; the report names that fix and the gate refuses one that does not. Its attack list starts with every claim the prose makes and includes the form of the code: the reviewer writes the changed block the way the strongest engineer in that language would, in the repository's own idioms, and a smaller or clearer version is a finding; every finding carries evidence it produced itself, and its report is bound to the head and the text it read. A fix is a new head and gets a new review.
69
69
  `file-pr.sh` is the only way a pull request is opened. It refuses without a prior-art printout under a day old, a policy printout under a day old that does not read BAN, a body that discloses when the policy asks, a branch stamp for the exact head, and a POST AS IS review of that head and that body.
70
70
  `file-issue.sh` is the only way an issue is opened. It refuses without the same prior-art and policy printouts, refuses the same prose, and refuses a body that mentions a fix, a patch or a pull request without a GitHub link to the branch or commit, so work that exists is attributable to whoever did it.
71
71
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "housebroken-cli"
7
- version = "0.6.8"
7
+ version = "0.6.9"
8
8
  description = "Agent-written pull requests that do not make a mess in someone else's house."
9
9
  dynamic = ["readme"]
10
10
  license = "MIT"
@@ -7,20 +7,29 @@
7
7
  # .gitignore excludes; a working artifact; a commit carrying a tool trailer, a
8
8
  # session link or a tool identity; a sign-off naming a username; a branch that
9
9
  # is not on top of its base; and a comment added to code, test files included,
10
- # unless a maintainer asked for it (comment-check.sh). Absolute claims in added
11
- # prose are printed for you to falsify one by one; some of them are true.
10
+ # unless a maintainer asked for it (comment-check.sh); a warning suppression the
11
+ # branch adds, until a build log shows the warning it suppresses firing; and
12
+ # reflection added to a .NET project that declares itself AOT compatible or
13
+ # trimmable, until an AOT publish log is given. shouldly #1335 suppressed an
14
+ # IL2075 that never fired, and the reflection under it found nothing under
15
+ # Native AOT. Absolute claims in added prose are printed for you to falsify one
16
+ # by one; some of them are true.
12
17
  #
13
18
  # A branch that passes gets a stamp at $HOUSEBROKEN_HOME/branch-checks/<head>,
14
19
  # which file-pr.sh requires for the head it files.
15
20
  #
16
21
  # Usage:
17
22
  # bash branch-check.sh [CLONE] [--base REF] [--asked URL]
23
+ # [--warning-log FILE] [--aot-log FILE]
18
24
  # bash branch-check.sh --help
19
25
  #
20
26
  # CLONE defaults to the current directory. REF defaults to the first of
21
27
  # upstream/main, upstream/master, origin/main, origin/master that resolves.
22
28
  # --asked URL is the maintainer's request for documentation, which turns the
23
- # comment refusal into a check.
29
+ # comment refusal into a check. --warning-log FILE is a build log of the
30
+ # branch without its suppressions; it must name every warning id they suppress.
31
+ # --aot-log FILE is the output of an AOT publish (dotnet publish
32
+ # -p:PublishAot=true) of the branch, run and read.
24
33
  #
25
34
  # Exits 0 when nothing blocks, 1 on a refusal, 2 on a usage error.
26
35
  set -u
@@ -32,6 +41,8 @@ home="${HOUSEBROKEN_HOME:-$HOME/.housebroken}"
32
41
  clone="."
33
42
  base=""
34
43
  asked=""
44
+ warnlog=""
45
+ aotlog=""
35
46
  while [ "$#" -gt 0 ]; do
36
47
  case "$1" in
37
48
  --help|-h) usage; exit 0 ;;
@@ -47,6 +58,16 @@ while [ "$#" -gt 0 ]; do
47
58
  [ -n "$asked" ] || { echo "REFUSED: --asked needs the URL of the maintainer's ask" >&2; exit 2; }
48
59
  ;;
49
60
  --asked=*) asked="${1#--asked=}" ;;
61
+ --warning-log)
62
+ shift
63
+ warnlog="${1:-}"
64
+ [ -f "$warnlog" ] || { echo "REFUSED: --warning-log needs a build log file" >&2; exit 2; }
65
+ ;;
66
+ --aot-log)
67
+ shift
68
+ aotlog="${1:-}"
69
+ [ -f "$aotlog" ] || { echo "REFUSED: --aot-log needs an AOT publish log file" >&2; exit 2; }
70
+ ;;
50
71
  -*) echo "REFUSED: unknown option $1" >&2; exit 2 ;;
51
72
  *) clone="$1" ;;
52
73
  esac
@@ -161,6 +182,39 @@ case "$comment_rc" in
161
182
  esac
162
183
  printf '%s\n' "$comments" | grep -E '^CHECK: ' | sed 's/^/ /'
163
184
 
185
+ # A suppression hides a warning from the maintainer too, so it has to be shown
186
+ # that the warning exists. A suppression covering nothing usually covers code
187
+ # that is wrong in a way the analyzer cannot see.
188
+ added=$(git diff -U0 "$base..HEAD" -- . ':(exclude)*.md' ':(exclude)*.rst' ':(exclude)*.txt' 2>/dev/null \
189
+ | grep '^+' | grep -v '^+++' | sed 's/^+//')
190
+ suppressions=$(printf '%s\n' "$added" | grep -E 'UnconditionalSuppressMessage|SuppressMessage\(|#pragma warning disable|@SuppressWarnings|@Suppress\(|#!?\[allow\(|nolint|NOLINT|noqa|eslint-disable|@ts-ignore|@ts-expect-error|type: *ignore|pylint: *disable|rubocop:disable|swiftlint:disable')
191
+ if [ -n "$suppressions" ]; then
192
+ ids=$(printf '%s\n' "$suppressions" | grep -oE '\b[A-Z]{1,4}[0-9]{3,5}\b' | sort -u)
193
+ unshown=""
194
+ if [ -z "$warnlog" ]; then
195
+ unshown="no --warning-log given"
196
+ else
197
+ for id in $ids; do grep -q "$id" "$warnlog" || unshown="$unshown $id"; done
198
+ fi
199
+ if [ -n "$unshown" ]; then
200
+ block "the branch adds a warning suppression, and no build log shows the warning firing ($unshown)"
201
+ printf '%s\n' "$suppressions" | sed 's/^/ /'
202
+ fi
203
+ fi
204
+
205
+ # The trim analyzer does not flag object.GetType().GetProperty(...), so a clean
206
+ # build proves nothing about reflection under Native AOT; only a publish does.
207
+ aotdecl=$(git grep -lE '<(IsAotCompatible|IsTrimmable|PublishAot|EnableTrimAnalyzer|EnableAotAnalyzer)( [^>]*)?>[[:space:]]*true' HEAD -- '*.csproj' '*.props' '*.targets' 2>/dev/null \
208
+ | sed 's/^HEAD://' | tr '\n' ' ')
209
+ if [ -n "$aotdecl" ]; then
210
+ reflection=$(git diff -U0 "$base..HEAD" -- '*.cs' 2>/dev/null | grep '^+' | grep -v '^+++' | sed 's/^+//' \
211
+ | grep -E '\.Get(Property|Properties|Method|Methods|Field|Fields|Member|Members|Interfaces)\(|Activator\.CreateInstance|MakeGenericType|MakeGenericMethod|Type\.GetType\(|\.InvokeMember\(')
212
+ if [ -n "$reflection" ] && ! { [ -n "$aotlog" ] && grep -q "Generating native code" "$aotlog"; }; then
213
+ block "the branch adds reflection to a project that declares AOT or trim support (${aotdecl% }), and no --aot-log shows an AOT publish"
214
+ printf '%s\n' "$reflection" | sed 's/^/ /'
215
+ fi
216
+ fi
217
+
164
218
  # Absolutes in added prose are the claims a maintainer can falsify in one grep.
165
219
  claims=$(git diff -U0 "$base..HEAD" -- '*.md' '*.mdx' '*.rst' '*.txt' 2>/dev/null \
166
220
  | grep '^+' | grep -v '^+++' | sed 's/^+//' \
@@ -180,6 +180,11 @@ EOF
180
180
  printf -- '- context from the author, to attack rather than trust: %s\n' "$t"
181
181
  done
182
182
 
183
+ local blind="$home/reviews/blind-${repo%%/*}-${repo##*/}-$key.diff"
184
+ if [ -n "$clone" ]; then
185
+ printf '\n0. Before you read the diff, fix it yourself.\n'
186
+ printf ' Read only the problem: the issue or the description of the bug, and the code at %s. In a copy of the clone at that commit, write the fix you would send, with its test, and save it as a diff to %s. Only then read the change under review and compare. A design that differs from yours in where it fixes the problem, what it recomputes or what it can break is a finding: SHOULD FIX when yours is better, with both versions side by side. The point is the design you reach without the author'"'"'s anchoring it; a maintainer reads the bug, not our diff, and writes their own.\n' "${mb:-the base}" "$blind"
187
+ fi
183
188
  printf '\nAttack at least\n'
184
189
  printf '1. Every claim the text makes, re-derived now against the exact revision it names.\n'
185
190
  for t in ${texts[@]+"${texts[@]}"}; do
@@ -194,9 +199,15 @@ EOF
194
199
  6. Prior art: nothing duplicates an open pull request or argues with a ruling in a closed issue.
195
200
  7. The text: it leads with the fact; no verdict on the reviewer, no thanks, apology or offer of help; a reply runs one to three sentences and a body stays under 120 words; no footer, trailer or typographic dash; every sentence is true as literally worded.
196
201
  8. Anything else that would embarrass the author in front of this maintainer.
197
-
198
- Report
199
202
  EOF
203
+ if [ -n "$clone" ]; then
204
+ cat <<'EOF'
205
+ 9. Where the information is lost: trace every value the change uses back to the last place its type, comparer or source was known. A change that recomputes what a caller already had (a second lookup, a second enumeration, reflection to recover a type the generic code knew, a default comparer standing in for the caller's) fixes the symptom where it surfaced, not where it began. That is SHOULD FIX, with the version that carries the caller's result forward.
206
+ 10. Inputs the project already tests: list the input shapes the test files beside the changed code use, such as custom comparers, culture, single-use or lazy sequences, null, empty, very large, concurrent callers. Every shape the changed code can receive that the new tests leave out is a finding; run the change on it.
207
+ 11. What the project promises to run on: read the manifests and CI matrix for AOT, trimming, no_std, wasm, minimum language or runtime versions, and every platform leg. Run the changed path in each mode the project promises, not only the default build; a clean build is not a run. A suppression the change adds has to be shown covering a warning that fires.
208
+ EOF
209
+ fi
210
+ printf '\nReport\n'
200
211
  printf 'Write it to %s. It must start with exactly these lines, with the verdict filled in:\n\n' "$report"
201
212
  printf 'review-of: %s\n' "$repo"
202
213
  [ -n "$head" ] && printf 'head: %s\n' "$head"
@@ -204,6 +215,7 @@ EOF
204
215
  printf 'text: sha256:%s %s\n' "$(sha256 "$t")" "$(basename "$t")"
205
216
  done
206
217
  printf 'author-model: %s\nreviewer-model: %s\n' "$author" "$reviewer"
218
+ [ -n "$head" ] && printf 'blind-fix: %s\n' "$blind"
207
219
  printf 'verdict: POST AS IS | POST WITH CHANGES | DO NOT POST\n\n'
208
220
  cat <<'EOF'
209
221
  POST AS IS means nothing BLOCKING or SHOULD FIX remains. POST WITH CHANGES means the author fixes what you found and the fixed version comes back for another review. DO NOT POST means it should not go at all. After the header, number your findings, each with a severity (BLOCKING, SHOULD FIX or NIT), the evidence, and the exact fix, with replacement text in full for any wording. A report with no findings says what was checked and how.
@@ -242,6 +254,15 @@ cmd_check() {
242
254
  [ "$verdict" = "POST AS IS" ] ||
243
255
  refuse "the verdict is '${verdict:-missing}' and only POST AS IS clears the gate: fix what the review found and review the new version"
244
256
 
257
+ # A reviewer that read our diff first critiques our design; shouldly #1335
258
+ # went out with a fix the maintainer replaced, because nobody wrote another.
259
+ if [ -n "$head" ]; then
260
+ local blind
261
+ blind=$(field blind-fix)
262
+ [ -n "$blind" ] || refuse "$report reviews code at ${head:0:12} and names no blind-fix: the reviewer's own fix, written before reading ours"
263
+ [ -f "$blind" ] || refuse "the blind fix $blind named in $report does not exist"
264
+ fi
265
+
245
266
  if [ -n "$clone" ]; then
246
267
  now=$(git -C "$clone" rev-parse HEAD 2>/dev/null) || bad_usage "$clone is not a git clone"
247
268
  [ -n "$head" ] || refuse "$report records no head, so it cannot clear a branch"
@@ -157,8 +157,11 @@ report it in one line and do not proceed to the next step.
157
157
  whose mode disagrees with its own siblings, a file the branch adds that the
158
158
  repository ignores, a commit carrying a tool trailer, a session link or a
159
159
  tool identity, a sign-off that names a username, a branch that is not on
160
- top of its base, and any comment added to code (`--asked <URL>` when the
161
- maintainer asked for it); it prints every absolute claim your added prose
160
+ top of its base, any comment added to code (`--asked <URL>` when the
161
+ maintainer asked for it), a warning suppression the branch adds until
162
+ `--warning-log` shows each suppressed warning firing, and reflection added
163
+ to a .NET project that declares AOT or trim support until `--aot-log`
164
+ shows an AOT publish you ran the changed path under; it prints every absolute claim your added prose
162
165
  makes so you can falsify each one against the code, and it stamps the
163
166
  head it passed, which the filing requires. Then the adversarial review:
164
167
  `housebroken review brief --author <your model> --repo owner/repo --clone <clone> --text <body file>`
@@ -166,7 +169,14 @@ report it in one line and do not proceed to the next step.
166
169
  that wrote the change: one tier down, Fable to Opus and Opus to Sonnet,
167
170
  and never below Sonnet, so Sonnet's work goes to Opus. Hand the brief to a
168
171
  fresh agent running that model; anything of yours it reads is for it to
169
- attack, not to trust. It attacks the form as well as the facts: it writes
172
+ attack, not to trust. Before it reads the diff, it reads only the bug and
173
+ the code at the base and writes the fix it would send, saved where the
174
+ brief says; the report names that file, and the gate refuses a code review
175
+ without it. A maintainer reads the bug, not our diff, and writes their own
176
+ fix; the reviewer does the same first. It then traces every value the change
177
+ uses to where its type or comparer was last known, covers the input shapes
178
+ the neighbouring tests use, and runs the changed path in every mode the
179
+ project promises to run on. It attacks the form as well as the facts: it writes
170
180
  the changed block the way the strongest engineer in that language would,
171
181
  and a smaller or clearer version is a finding you fix before filing. It
172
182
  writes its report where the brief says, with its own evidence behind
@@ -0,0 +1 @@
1
+ __version__ = "0.6.9"
@@ -1 +0,0 @@
1
- __version__ = "0.6.8"
File without changes