housebroken-cli 0.3.0__tar.gz → 0.5.0__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.
- {housebroken_cli-0.3.0 → housebroken_cli-0.5.0}/PKG-INFO +10 -3
- {housebroken_cli-0.3.0 → housebroken_cli-0.5.0}/README.md +9 -2
- {housebroken_cli-0.3.0 → housebroken_cli-0.5.0}/bin/housebroken +4 -0
- {housebroken_cli-0.3.0 → housebroken_cli-0.5.0}/pyproject.toml +1 -1
- {housebroken_cli-0.3.0 → housebroken_cli-0.5.0}/scripts/branch-check.sh +34 -5
- housebroken_cli-0.5.0/scripts/claim-check.sh +67 -0
- {housebroken_cli-0.3.0 → housebroken_cli-0.5.0}/scripts/file-pr.sh +29 -2
- housebroken_cli-0.5.0/scripts/review.sh +263 -0
- {housebroken_cli-0.3.0 → housebroken_cli-0.5.0}/skills/housebroken/SKILL.md +33 -11
- housebroken_cli-0.5.0/src/housebroken/__init__.py +1 -0
- housebroken_cli-0.3.0/src/housebroken/__init__.py +0 -1
- {housebroken_cli-0.3.0 → housebroken_cli-0.5.0}/.gitignore +0 -0
- {housebroken_cli-0.3.0 → housebroken_cli-0.5.0}/LICENSE +0 -0
- {housebroken_cli-0.3.0 → housebroken_cli-0.5.0}/hatch_build.py +0 -0
- {housebroken_cli-0.3.0 → housebroken_cli-0.5.0}/scripts/check-ai-policy.sh +0 -0
- {housebroken_cli-0.3.0 → housebroken_cli-0.5.0}/scripts/comment-census.sh +0 -0
- {housebroken_cli-0.3.0 → housebroken_cli-0.5.0}/scripts/diff-defaults.sh +0 -0
- {housebroken_cli-0.3.0 → housebroken_cli-0.5.0}/scripts/distinct-outside.sh +0 -0
- {housebroken_cli-0.3.0 → housebroken_cli-0.5.0}/scripts/fork-hygiene.sh +0 -0
- {housebroken_cli-0.3.0 → housebroken_cli-0.5.0}/scripts/inbox.sh +0 -0
- {housebroken_cli-0.3.0 → housebroken_cli-0.5.0}/scripts/notes.sh +0 -0
- {housebroken_cli-0.3.0 → housebroken_cli-0.5.0}/scripts/pr-sweep.sh +0 -0
- {housebroken_cli-0.3.0 → housebroken_cli-0.5.0}/scripts/prior-art.sh +0 -0
- {housebroken_cli-0.3.0 → housebroken_cli-0.5.0}/scripts/verify-filed-pr.sh +0 -0
- {housebroken_cli-0.3.0 → housebroken_cli-0.5.0}/src/housebroken/cli.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: housebroken-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
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
|
|
@@ -57,6 +57,7 @@ one finding, one pull request
|
|
|
57
57
|
body under 120 words, in their template, no footer
|
|
58
58
|
prior art read and quoted before the branch existed
|
|
59
59
|
their CI target green on a fresh clone of their main
|
|
60
|
+
attacked by a second model before it left, evidence behind every finding
|
|
60
61
|
the CLA known before filing, the SECURITY.md route taken when it applies
|
|
61
62
|
```
|
|
62
63
|
|
|
@@ -109,7 +110,11 @@ Every organization gets a card before the first filing: CLA, DCO, signed-commit
|
|
|
109
110
|
A memory-safety or remote-abort finding in a library goes by the project's SECURITY.md route, privately, and never becomes a public pull request until the project answers.
|
|
110
111
|
|
|
111
112
|
**9. File through the gate.**
|
|
112
|
-
`branch-check.sh` reads the branch before anything leaves the machine: it refuses a dirty working tree, a file whose mode disagrees with its own siblings, a
|
|
113
|
+
`branch-check.sh` reads the branch before anything leaves the machine: it refuses a dirty working tree, a file whose mode disagrees with its own siblings, a file the branch adds that the repository's own `.gitignore` excludes, a working artifact, a commit carrying a tool trailer or a session link, a sign-off that names a username, and a branch that is not on top of its base, and it prints every absolute claim the added prose makes so each can be falsified against the code. Three of those came from one review round on a single pull request.
|
|
114
|
+
|
|
115
|
+
Then a different model attacks the change. `review.sh brief` names the reviewer, never the model that wrote the change: one tier down, Fable to Opus and Opus to Sonnet, and 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 every finding it reports carries evidence it produced itself. Its report records the head and the text it read, so a fix it asks for is a new head and gets a new review. The defects reviews like this caught before anything was sent are in [the ledger](https://github.com/lenamonj/housebroken/blob/main/docs/lessons.md).
|
|
116
|
+
|
|
117
|
+
`file-pr.sh` wraps the pull request creation and refuses when the prior-art printout for that repository is missing or older than a day, when the body carries a footer, a trailer, or a typographic dash, or when there is no POST AS IS review of the exact head and body being filed.
|
|
113
118
|
|
|
114
119
|
**10. Watch it land.**
|
|
115
120
|
`verify-filed-pr.sh` re-derives from GitHub that the head is the intended commit, the diff is exactly the intended files, and CI settled green. `pr-sweep.sh` lists every open pull request where the ball is in your court: a maintainer's comment unanswered, a review requesting changes, a red check, a conflict. Every maintainer comment gets a same-day answer. A ruling in a closed issue is never argued with. When the maintainer is right, concede and let them close it.
|
|
@@ -146,7 +151,9 @@ uv tool install git+https://github.com/lenamonj/housebroken
|
|
|
146
151
|
| `scripts/prior-art.sh` | issues and pull requests on the touched files, type stated, rulings quoted |
|
|
147
152
|
| `scripts/comment-census.sh` | added code versus added comments, per branch |
|
|
148
153
|
| `scripts/diff-defaults.sh` | default arguments and one-line wrappers added to keep call sites untouched |
|
|
149
|
-
| `scripts/
|
|
154
|
+
| `scripts/claim-check.sh` | every falsifiable claim in a body or a reply, listed to re-derive |
|
|
155
|
+
| `scripts/branch-check.sh` | the branch's mechanical facts: clean tree, file modes, artifacts, trailers, sign-offs, absolute claims |
|
|
156
|
+
| `scripts/review.sh` | the adversarial review: a different model attacks the change, and the filing is held to exactly what it read |
|
|
150
157
|
| `scripts/file-pr.sh` | the only way a pull request gets filed |
|
|
151
158
|
| `scripts/verify-filed-pr.sh` | the filed pull request is what was meant, and CI settled |
|
|
152
159
|
| `scripts/pr-sweep.sh` | every open pull request where the ball is in your court |
|
|
@@ -45,6 +45,7 @@ one finding, one pull request
|
|
|
45
45
|
body under 120 words, in their template, no footer
|
|
46
46
|
prior art read and quoted before the branch existed
|
|
47
47
|
their CI target green on a fresh clone of their main
|
|
48
|
+
attacked by a second model before it left, evidence behind every finding
|
|
48
49
|
the CLA known before filing, the SECURITY.md route taken when it applies
|
|
49
50
|
```
|
|
50
51
|
|
|
@@ -97,7 +98,11 @@ Every organization gets a card before the first filing: CLA, DCO, signed-commit
|
|
|
97
98
|
A memory-safety or remote-abort finding in a library goes by the project's SECURITY.md route, privately, and never becomes a public pull request until the project answers.
|
|
98
99
|
|
|
99
100
|
**9. File through the gate.**
|
|
100
|
-
`branch-check.sh` reads the branch before anything leaves the machine: it refuses a dirty working tree, a file whose mode disagrees with its own siblings, a
|
|
101
|
+
`branch-check.sh` reads the branch before anything leaves the machine: it refuses a dirty working tree, a file whose mode disagrees with its own siblings, a file the branch adds that the repository's own `.gitignore` excludes, a working artifact, a commit carrying a tool trailer or a session link, a sign-off that names a username, and a branch that is not on top of its base, and it prints every absolute claim the added prose makes so each can be falsified against the code. Three of those came from one review round on a single pull request.
|
|
102
|
+
|
|
103
|
+
Then a different model attacks the change. `review.sh brief` names the reviewer, never the model that wrote the change: one tier down, Fable to Opus and Opus to Sonnet, and 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 every finding it reports carries evidence it produced itself. Its report records the head and the text it read, so a fix it asks for is a new head and gets a new review. The defects reviews like this caught before anything was sent are in [the ledger](docs/lessons.md).
|
|
104
|
+
|
|
105
|
+
`file-pr.sh` wraps the pull request creation and refuses when the prior-art printout for that repository is missing or older than a day, when the body carries a footer, a trailer, or a typographic dash, or when there is no POST AS IS review of the exact head and body being filed.
|
|
101
106
|
|
|
102
107
|
**10. Watch it land.**
|
|
103
108
|
`verify-filed-pr.sh` re-derives from GitHub that the head is the intended commit, the diff is exactly the intended files, and CI settled green. `pr-sweep.sh` lists every open pull request where the ball is in your court: a maintainer's comment unanswered, a review requesting changes, a red check, a conflict. Every maintainer comment gets a same-day answer. A ruling in a closed issue is never argued with. When the maintainer is right, concede and let them close it.
|
|
@@ -134,7 +139,9 @@ uv tool install git+https://github.com/lenamonj/housebroken
|
|
|
134
139
|
| `scripts/prior-art.sh` | issues and pull requests on the touched files, type stated, rulings quoted |
|
|
135
140
|
| `scripts/comment-census.sh` | added code versus added comments, per branch |
|
|
136
141
|
| `scripts/diff-defaults.sh` | default arguments and one-line wrappers added to keep call sites untouched |
|
|
137
|
-
| `scripts/
|
|
142
|
+
| `scripts/claim-check.sh` | every falsifiable claim in a body or a reply, listed to re-derive |
|
|
143
|
+
| `scripts/branch-check.sh` | the branch's mechanical facts: clean tree, file modes, artifacts, trailers, sign-offs, absolute claims |
|
|
144
|
+
| `scripts/review.sh` | the adversarial review: a different model attacks the change, and the filing is held to exactly what it read |
|
|
138
145
|
| `scripts/file-pr.sh` | the only way a pull request gets filed |
|
|
139
146
|
| `scripts/verify-filed-pr.sh` | the filed pull request is what was meant, and CI settled |
|
|
140
147
|
| `scripts/pr-sweep.sh` | every open pull request where the ball is in your court |
|
|
@@ -48,7 +48,9 @@ usage: housebroken <subcommand> [args...]
|
|
|
48
48
|
1 outside count outside contributors merged in the last 120 days
|
|
49
49
|
2 prior-art issues and pull requests on the touched files, rulings quoted
|
|
50
50
|
6 census added code lines against added comment lines, per branch
|
|
51
|
+
6 claims every falsifiable claim in outbound text, listed to re-derive
|
|
51
52
|
9 branch the mechanical facts about the branch: tree, modes, artifacts, claims
|
|
53
|
+
9 review a different model attacks the change before it is filed
|
|
52
54
|
9 file the only way a pull request gets filed
|
|
53
55
|
10 verify the filed pull request is what was meant, and CI settled
|
|
54
56
|
10 sweep every open pull request where the ball is in your court
|
|
@@ -90,7 +92,9 @@ case "$cmd" in
|
|
|
90
92
|
outside) script=distinct-outside.sh ;;
|
|
91
93
|
prior-art) script=prior-art.sh ;;
|
|
92
94
|
census) script=comment-census.sh ;;
|
|
95
|
+
claims) script=claim-check.sh ;;
|
|
93
96
|
branch) script=branch-check.sh ;;
|
|
97
|
+
review) script=review.sh ;;
|
|
94
98
|
file) script=file-pr.sh ;;
|
|
95
99
|
verify) script=verify-filed-pr.sh ;;
|
|
96
100
|
sweep) script=pr-sweep.sh ;;
|
|
@@ -103,9 +103,16 @@ while IFS= read -r f; do
|
|
|
103
103
|
fi
|
|
104
104
|
fi
|
|
105
105
|
|
|
106
|
-
# The repository's own .gitignore is the authority on what is build output
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
# The repository's own .gitignore is the authority on what is build output,
|
|
107
|
+
# but only for a file this branch adds. Ignore rules never apply to a file the
|
|
108
|
+
# project already tracks, which is why check-ignore skips tracked files unless
|
|
109
|
+
# forced. NVIDIA/go-nvml ignores "dl" for a built binary, and that pattern also
|
|
110
|
+
# matches the directory pkg/dl, so forcing the check called two upstream source
|
|
111
|
+
# files build output.
|
|
112
|
+
if ! git cat-file -e "$base:$f" 2>/dev/null; then
|
|
113
|
+
if git check-ignore -q --no-index -- "$f" 2>/dev/null; then
|
|
114
|
+
block "$f is added by this branch and the repository's .gitignore excludes it"
|
|
115
|
+
fi
|
|
109
116
|
fi
|
|
110
117
|
|
|
111
118
|
case "$f" in
|
|
@@ -116,6 +123,28 @@ done <<EOF
|
|
|
116
123
|
$files
|
|
117
124
|
EOF
|
|
118
125
|
|
|
126
|
+
# A tool trailer is the one thing in a commit that cannot be argued as style.
|
|
127
|
+
# Thirteen open pull requests across ten organisations were found carrying
|
|
128
|
+
# "Co-Authored-By: Claude ..." and four of them a live claude.ai session URL,
|
|
129
|
+
# on NVIDIA, Microsoft, Apple, Uber, Tesla, Apache and IBM repositories. No
|
|
130
|
+
# project asked for it; a harness adds it by default and nobody read the commit
|
|
131
|
+
# before pushing. The body is checked for this at step 9; the commits were not.
|
|
132
|
+
trailers=$(git log --format='%H %s%n%b' "$base..HEAD" 2>/dev/null \
|
|
133
|
+
| grep -inE 'Co-Authored-By: *Claude|Claude-Session:|https://claude\.ai/code|Generated with .*Claude')
|
|
134
|
+
if [ -n "$trailers" ]; then
|
|
135
|
+
block "a commit carries a tool trailer or a session link, which no project asked for"
|
|
136
|
+
printf '%s\n' "$trailers" | sed 's/^/ /'
|
|
137
|
+
fi
|
|
138
|
+
|
|
139
|
+
# DCO wants a human being, and several projects say so in as many words.
|
|
140
|
+
if git log --format='%b' "$base..HEAD" 2>/dev/null | grep -qE '^Signed-off-by:'; then
|
|
141
|
+
usernames=$(git log --format='%b' "$base..HEAD" 2>/dev/null | grep -E '^Signed-off-by: [a-z0-9_-]+ <')
|
|
142
|
+
if [ -n "$usernames" ]; then
|
|
143
|
+
block "a Signed-off-by names a username; the DCO asks for a real name"
|
|
144
|
+
printf '%s\n' "$usernames" | sed 's/^/ /'
|
|
145
|
+
fi
|
|
146
|
+
fi
|
|
147
|
+
|
|
119
148
|
# Absolutes in added prose are the claims a maintainer can falsify in one grep.
|
|
120
149
|
claims=$(git diff -U0 "$base..HEAD" -- '*.md' '*.mdx' '*.rst' '*.txt' 2>/dev/null \
|
|
121
150
|
| grep '^+' | grep -v '^+++' | sed 's/^+//' \
|
|
@@ -128,8 +157,8 @@ fi
|
|
|
128
157
|
echo
|
|
129
158
|
echo "commits:"
|
|
130
159
|
git log --oneline "$base..HEAD" | sed 's/^/ /'
|
|
131
|
-
echo "diff:"
|
|
132
|
-
git diff --stat "$base..HEAD" | sed 's/^/ /'
|
|
160
|
+
echo "diff (against the merge base, which is what the maintainer sees):"
|
|
161
|
+
git diff --stat "$(git merge-base "$base" HEAD)..HEAD" | sed 's/^/ /'
|
|
133
162
|
|
|
134
163
|
if [ "$blocked" -ne 0 ]; then
|
|
135
164
|
echo
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# claim-check.sh - lists every claim in outbound text that a maintainer can
|
|
3
|
+
# falsify, so each one gets re-derived before it is sent.
|
|
4
|
+
#
|
|
5
|
+
# On microsoft/GSL #1272 a reply draft said "The five new static_asserts fail on
|
|
6
|
+
# main." A reviewer falsified it in one pass. The number had come from a red arm
|
|
7
|
+
# that grepped only for `static assertion failed`, so it counted five matches
|
|
8
|
+
# and never saw the twenty-one other errors beside them; and against the commit
|
|
9
|
+
# a maintainer would actually revert to, only four of the five fail. The
|
|
10
|
+
# sentence named a basis and was still wrong about it.
|
|
11
|
+
#
|
|
12
|
+
# So this does not try to judge a claim. Text checks cannot: the bad sentence
|
|
13
|
+
# named its revision and read perfectly. It lists them, and the rule in step 6
|
|
14
|
+
# is that every listed line is re-measured, at the moment of writing, against
|
|
15
|
+
# the exact revision the sentence names. The gap this closes is that until now
|
|
16
|
+
# every gate here read code and nothing read the prose, while the prose is what
|
|
17
|
+
# the maintainer reads first.
|
|
18
|
+
#
|
|
19
|
+
# Usage:
|
|
20
|
+
# bash claim-check.sh FILE
|
|
21
|
+
# bash claim-check.sh --help
|
|
22
|
+
#
|
|
23
|
+
# Exits 1 when it finds claims to re-derive, 0 when it finds none, 2 on a usage
|
|
24
|
+
# error. Exit 1 is not a refusal to send; it is a refusal to send unread.
|
|
25
|
+
set -u
|
|
26
|
+
|
|
27
|
+
usage() { awk 'NR>1 && /^#/ {sub(/^# ?/, ""); print; next} NR>1 {exit}' "$0"; }
|
|
28
|
+
|
|
29
|
+
case "${1:-}" in
|
|
30
|
+
--help|-h) usage; exit 0 ;;
|
|
31
|
+
"") echo "REFUSED: name the file holding the text" >&2; exit 2 ;;
|
|
32
|
+
esac
|
|
33
|
+
file="$1"
|
|
34
|
+
[ -f "$file" ] || { echo "REFUSED: $file does not exist" >&2; exit 2; }
|
|
35
|
+
|
|
36
|
+
# Strip fenced code and quoted logs: a number inside pasted output is evidence,
|
|
37
|
+
# not a claim being made.
|
|
38
|
+
body=$(awk '/^```/ {fence = !fence; next} !fence && !/^ *[|>]/ {print NR": "$0}' "$file")
|
|
39
|
+
|
|
40
|
+
quantified=$(printf '%s
|
|
41
|
+
' "$body" | grep -nEi '[0-9]+ *(of|/) *[0-9]+|\b([0-9]+|one|two|three|four|five|six|seven|eight|nine|ten|no) +([a-z_-]+ +){0,3}(tests?|assertions?|static_asserts?|checks?|errors?|failures?|jobs?|files?|warnings?|projects?|commits?|suites?)\b' | cut -d: -f2-)
|
|
42
|
+
|
|
43
|
+
absolute=$(printf '%s\n' "$body" | grep -nEi \
|
|
44
|
+
'\b(only|exactly|always|never|every|all|none|nothing|everything|guaranteed|any)\b' \
|
|
45
|
+
| cut -d: -f2-)
|
|
46
|
+
|
|
47
|
+
found=0
|
|
48
|
+
if [ -n "$quantified" ]; then
|
|
49
|
+
found=1
|
|
50
|
+
echo "COUNTED: re-derive each, against the revision the sentence names, now:"
|
|
51
|
+
printf '%s\n' "$quantified" | sed 's/^/ /'
|
|
52
|
+
fi
|
|
53
|
+
if [ -n "$absolute" ]; then
|
|
54
|
+
found=1
|
|
55
|
+
echo "ABSOLUTE: falsify each against the code, not against your memory of it:"
|
|
56
|
+
printf '%s\n' "$absolute" | sed 's/^/ /'
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
if [ "$found" -eq 0 ]; then
|
|
60
|
+
echo "claim-check: no falsifiable claim found in $file"
|
|
61
|
+
exit 0
|
|
62
|
+
fi
|
|
63
|
+
echo
|
|
64
|
+
echo "claim-check: $file makes claims a maintainer can check. Re-measure each"
|
|
65
|
+
echo "one before sending. A sentence that names its revision can still be wrong"
|
|
66
|
+
echo "about it; that is the failure this exists for."
|
|
67
|
+
exit 1
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# file-pr.sh - the only way a PR gets filed: gh pr create behind
|
|
2
|
+
# file-pr.sh - the only way a PR gets filed: gh pr create behind three gates.
|
|
3
3
|
#
|
|
4
4
|
# Gate one is prior art. typer #1946 (closed 2026-08-31) duplicated an open PR
|
|
5
5
|
# and swift-http-types #153 (closed 2026-09-04) reargued a closed issue, both
|
|
@@ -9,6 +9,10 @@
|
|
|
9
9
|
# Gate two is the prose. Tool footers, session trailers and em or en dashes have
|
|
10
10
|
# no place in somebody else's repository, so a body carrying one is refused.
|
|
11
11
|
# Written 2026-09-07.
|
|
12
|
+
# Gate three is the adversarial review (review.sh). A different model attacked
|
|
13
|
+
# this exact head and this exact body file and said POST AS IS. An inline
|
|
14
|
+
# --body is refused, because a review cannot be bound to text that was never a
|
|
15
|
+
# file. Added 2026-09-12.
|
|
12
16
|
#
|
|
13
17
|
# Usage:
|
|
14
18
|
# bash file-pr.sh owner/repo <gh pr create args...>
|
|
@@ -39,6 +43,10 @@ gates:
|
|
|
39
43
|
exist and be under 24 hours old
|
|
40
44
|
prose no tool footer, session trailer, co-author trailer, em dash or
|
|
41
45
|
en dash in --body or --body-file
|
|
46
|
+
review run from the clone being filed; the report at
|
|
47
|
+
$HOUSEBROKEN_HOME/reviews/review-<owner>-<repo>-<head12>.md must
|
|
48
|
+
pass review.sh check for this head and the --body-file, and an
|
|
49
|
+
inline --body is refused
|
|
42
50
|
|
|
43
51
|
environment:
|
|
44
52
|
HOUSEBROKEN_HOME work directory, default $HOME/.housebroken
|
|
@@ -88,14 +96,18 @@ check_text() {
|
|
|
88
96
|
}
|
|
89
97
|
|
|
90
98
|
prev=""
|
|
99
|
+
bodyfile=""
|
|
100
|
+
inline_body=0
|
|
91
101
|
for arg in "$@"; do
|
|
92
102
|
case "$prev" in
|
|
93
103
|
--body-file|-F)
|
|
94
104
|
[ -f "$arg" ] || { echo "REFUSED: body file $arg does not exist" >&2; exit 2; }
|
|
95
105
|
check_text "body file $arg" "$(cat "$arg")"
|
|
106
|
+
bodyfile="$arg"
|
|
96
107
|
;;
|
|
97
108
|
--body|-b)
|
|
98
109
|
check_text "--body" "$arg"
|
|
110
|
+
inline_body=1
|
|
99
111
|
;;
|
|
100
112
|
esac
|
|
101
113
|
case "$arg" in
|
|
@@ -103,12 +115,27 @@ for arg in "$@"; do
|
|
|
103
115
|
f="${arg#--body-file=}"
|
|
104
116
|
[ -f "$f" ] || { echo "REFUSED: body file $f does not exist" >&2; exit 2; }
|
|
105
117
|
check_text "body file $f" "$(cat "$f")"
|
|
118
|
+
bodyfile="$f"
|
|
106
119
|
;;
|
|
107
|
-
--body=*) check_text "--body" "${arg#--body=}" ;;
|
|
120
|
+
--body=*) check_text "--body" "${arg#--body=}"; inline_body=1 ;;
|
|
108
121
|
esac
|
|
109
122
|
prev="$arg"
|
|
110
123
|
done
|
|
111
124
|
|
|
125
|
+
head=$(git rev-parse HEAD 2>/dev/null) || { echo "REFUSED: run file-pr.sh from inside the clone being filed" >&2; exit 2; }
|
|
126
|
+
if [ "$inline_body" -eq 1 ]; then
|
|
127
|
+
echo "REFUSED: pass the body as --body-file so the review can be bound to it" >&2
|
|
128
|
+
exit 2
|
|
129
|
+
fi
|
|
130
|
+
review="$home/reviews/review-${repo%%/*}-${repo##*/}-${head:0:12}.md"
|
|
131
|
+
if [ ! -f "$review" ]; then
|
|
132
|
+
echo "REFUSED: no adversarial review at $review - run review.sh brief and have a different model attack this head" >&2
|
|
133
|
+
exit 2
|
|
134
|
+
fi
|
|
135
|
+
review_args=(check "$review" --clone .)
|
|
136
|
+
[ -n "$bodyfile" ] && review_args+=(--text "$bodyfile")
|
|
137
|
+
bash "$(dirname "$0")/review.sh" "${review_args[@]}" >/dev/null || exit 2
|
|
138
|
+
|
|
112
139
|
if [ "${FILE_PR_DRY:-0}" = "1" ]; then
|
|
113
140
|
printf 'DRY RUN, not filed:\ngh pr create -R %s' "$repo"
|
|
114
141
|
for arg in "$@"; do printf ' %q' "$arg"; done
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# review.sh - the adversarial review: a different model attacks the change
|
|
3
|
+
# before it leaves the machine, and the filing is held to exactly what it read.
|
|
4
|
+
#
|
|
5
|
+
# The gates before this one read code and count prose. None of them asks
|
|
6
|
+
# whether the idea of the patch was complete, or whether a sentence is true,
|
|
7
|
+
# and those are the defects that got furthest: a reply saying five new
|
|
8
|
+
# static_asserts fail on main when four did, a new test file committed 100755
|
|
9
|
+
# among 100644 siblings, a patch that removed behaviour the repository
|
|
10
|
+
# documents. A second session's review caught each of them (docs/lessons.md,
|
|
11
|
+
# 2026-09-10). Asked how a smaller model could catch what a larger one missed,
|
|
12
|
+
# the ledger answered that it was the seat, not the model: the author had
|
|
13
|
+
# decided the patch was good before writing the sentence. So the reviewer is
|
|
14
|
+
# never the model that wrote the change. It is one tier down by default, which
|
|
15
|
+
# costs less and still brings different blind spots, and never below Sonnet,
|
|
16
|
+
# because a review has to be able to check a standard citation or a CI matrix:
|
|
17
|
+
# Fable's work goes to Opus, Opus's to Sonnet, Sonnet's to Opus.
|
|
18
|
+
#
|
|
19
|
+
# A review that passed is not a proof. On 2026-09-12 a review passed a reply
|
|
20
|
+
# packet whose author then found, re-reading, that the two functions it cited
|
|
21
|
+
# as precedent compile only under MSVC. The author still re-reads every claim
|
|
22
|
+
# the reviewer did not re-derive.
|
|
23
|
+
#
|
|
24
|
+
# The report is bound to what it read. Its header records the head it attacked
|
|
25
|
+
# and the sha256 of every text, and check refuses when the branch or the text
|
|
26
|
+
# has moved since, or when the verdict is anything but POST AS IS: a fix the
|
|
27
|
+
# reviewer asked for is a new head, and a new head is reviewed again.
|
|
28
|
+
#
|
|
29
|
+
# Usage:
|
|
30
|
+
# bash review.sh reviewer MODEL
|
|
31
|
+
# bash review.sh brief --author MODEL --repo owner/repo [--reviewer MODEL]
|
|
32
|
+
# [--clone DIR [--base REF]] [--text FILE]...
|
|
33
|
+
# [--context FILE]...
|
|
34
|
+
# bash review.sh check REPORT [--clone DIR] [--text FILE]...
|
|
35
|
+
# bash review.sh --help
|
|
36
|
+
#
|
|
37
|
+
# reviewer prints the model that reviews work written by MODEL.
|
|
38
|
+
# brief prints on stdout the brief to hand a fresh session running the
|
|
39
|
+
# reviewer model, and on stderr who that is and where its report
|
|
40
|
+
# goes: $HOUSEBROKEN_HOME/reviews/review-<owner>-<repo>-<key>.md,
|
|
41
|
+
# keyed by the clone's head, or by the first text's sha256 when there
|
|
42
|
+
# is no clone.
|
|
43
|
+
# check exits 0 when REPORT may gate a filing or a reply, 1 when it may
|
|
44
|
+
# not, with the reason on stderr, and 2 on a usage error.
|
|
45
|
+
#
|
|
46
|
+
# Environment:
|
|
47
|
+
# HOUSEBROKEN_HOME work directory, default $HOME/.housebroken.
|
|
48
|
+
#
|
|
49
|
+
# Assumes git, and sha256sum or shasum.
|
|
50
|
+
set -u
|
|
51
|
+
|
|
52
|
+
usage() { awk 'NR>1 && /^#/ {sub(/^# ?/, ""); print; next} NR>1 {exit}' "$0"; }
|
|
53
|
+
refuse() { echo "REFUSED: $1" >&2; exit 1; }
|
|
54
|
+
bad_usage() { echo "review.sh: $1" >&2; exit 2; }
|
|
55
|
+
|
|
56
|
+
home="${HOUSEBROKEN_HOME:-$HOME/.housebroken}"
|
|
57
|
+
here=$(cd "$(dirname "$0")" && pwd)
|
|
58
|
+
|
|
59
|
+
family() {
|
|
60
|
+
local m
|
|
61
|
+
m=$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]')
|
|
62
|
+
case "$m" in
|
|
63
|
+
*fable*) echo fable ;;
|
|
64
|
+
*opus*) echo opus ;;
|
|
65
|
+
*sonnet*) echo sonnet ;;
|
|
66
|
+
*haiku*) echo haiku ;;
|
|
67
|
+
*) printf '%s\n' "$m" ;;
|
|
68
|
+
esac
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
# One tier down, never below sonnet. A family not listed has no default.
|
|
72
|
+
default_reviewer() {
|
|
73
|
+
case "$1" in
|
|
74
|
+
fable) echo opus ;;
|
|
75
|
+
opus) echo sonnet ;;
|
|
76
|
+
sonnet) echo opus ;;
|
|
77
|
+
haiku) echo sonnet ;;
|
|
78
|
+
esac
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
# Prints why REVIEWER may not review AUTHOR's work, or nothing when it may.
|
|
82
|
+
objection() {
|
|
83
|
+
if [ -z "$2" ]; then
|
|
84
|
+
echo "no reviewer model named"
|
|
85
|
+
elif [ "$2" = "$1" ]; then
|
|
86
|
+
echo "the reviewer is the model that wrote the change ($1)"
|
|
87
|
+
elif [ "$2" = haiku ]; then
|
|
88
|
+
echo "haiku is below the floor: a reviewer has to be able to check a standard citation or a CI matrix"
|
|
89
|
+
fi
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
sha256() {
|
|
93
|
+
if command -v sha256sum >/dev/null 2>&1; then
|
|
94
|
+
sha256sum "$1" | awk '{print $1}'
|
|
95
|
+
else
|
|
96
|
+
shasum -a 256 "$1" | awk '{print $1}'
|
|
97
|
+
fi
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
cmd_reviewer() {
|
|
101
|
+
[ "$#" -eq 1 ] || bad_usage "reviewer takes one model name"
|
|
102
|
+
local r
|
|
103
|
+
r=$(default_reviewer "$(family "$1")")
|
|
104
|
+
[ -n "$r" ] || bad_usage "no default reviewer for '$1'; name one with brief --reviewer: any model other than the author's, not below sonnet"
|
|
105
|
+
echo "$r"
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
cmd_brief() {
|
|
109
|
+
local author="" repo="" reviewer="" clone="" base="" head="" key="" mb="" t
|
|
110
|
+
local texts=() contexts=()
|
|
111
|
+
while [ "$#" -gt 0 ]; do
|
|
112
|
+
case "$1" in
|
|
113
|
+
--author) author="${2:-}"; shift ;;
|
|
114
|
+
--repo) repo="${2:-}"; shift ;;
|
|
115
|
+
--reviewer) reviewer="${2:-}"; shift ;;
|
|
116
|
+
--clone) clone="${2:-}"; shift ;;
|
|
117
|
+
--base) base="${2:-}"; shift ;;
|
|
118
|
+
--text) texts+=("${2:-}"); shift ;;
|
|
119
|
+
--context) contexts+=("${2:-}"); shift ;;
|
|
120
|
+
*) bad_usage "unknown argument: $1" ;;
|
|
121
|
+
esac
|
|
122
|
+
shift
|
|
123
|
+
done
|
|
124
|
+
[ -n "$author" ] || bad_usage "brief needs --author, the model that wrote the change"
|
|
125
|
+
case "$repo" in */*) : ;; *) bad_usage "brief needs --repo owner/repo" ;; esac
|
|
126
|
+
local ntext=${#texts[@]}
|
|
127
|
+
[ -n "$clone" ] || [ "$ntext" -gt 0 ] || bad_usage "brief needs --clone, --text, or both"
|
|
128
|
+
for t in ${texts[@]+"${texts[@]}"} ${contexts[@]+"${contexts[@]}"}; do
|
|
129
|
+
[ -f "$t" ] || bad_usage "$t does not exist"
|
|
130
|
+
done
|
|
131
|
+
|
|
132
|
+
local fa fr why
|
|
133
|
+
fa=$(family "$author")
|
|
134
|
+
if [ -n "$reviewer" ]; then fr=$(family "$reviewer"); else fr=$(default_reviewer "$fa"); fi
|
|
135
|
+
[ -n "$fr" ] || refuse "no default reviewer for '$author'; name one with --reviewer"
|
|
136
|
+
why=$(objection "$fa" "$fr")
|
|
137
|
+
[ -z "$why" ] || refuse "$why"
|
|
138
|
+
reviewer="${reviewer:-$fr}"
|
|
139
|
+
|
|
140
|
+
if [ -n "$clone" ]; then
|
|
141
|
+
head=$(git -C "$clone" rev-parse HEAD 2>/dev/null) || bad_usage "$clone is not a git clone"
|
|
142
|
+
if [ -z "$base" ]; then
|
|
143
|
+
for t in upstream/main upstream/master origin/main origin/master; do
|
|
144
|
+
if git -C "$clone" rev-parse --verify --quiet "$t" >/dev/null; then base="$t"; break; fi
|
|
145
|
+
done
|
|
146
|
+
fi
|
|
147
|
+
[ -n "$base" ] && mb=$(git -C "$clone" merge-base "$base" HEAD 2>/dev/null)
|
|
148
|
+
key="${head:0:12}"
|
|
149
|
+
else
|
|
150
|
+
key=$(sha256 "${texts[0]}" | cut -c1-12)
|
|
151
|
+
fi
|
|
152
|
+
local report="$home/reviews/review-${repo%%/*}-${repo##*/}-$key.md"
|
|
153
|
+
mkdir -p "$home/reviews"
|
|
154
|
+
echo "housebroken review: hand the brief below to a fresh session running $reviewer; its report goes to $report" >&2
|
|
155
|
+
|
|
156
|
+
printf 'ADVERSARIAL REVIEW BRIEF\n\n'
|
|
157
|
+
printf 'You are the reviewer. The change below was written by %s. You are %s, chosen because you did not write it. ' "$author" "$reviewer"
|
|
158
|
+
cat <<'EOF'
|
|
159
|
+
Find what is wrong with it before a maintainer does. Assume there is at least one defect and hunt for it. A finding needs evidence you produced yourself: a command and its output, a quoted line of code, a quoted document. An impression is not a finding.
|
|
160
|
+
|
|
161
|
+
Hard limits
|
|
162
|
+
- Nothing leaves this machine: no git push; no gh pr create, comment, review or merge; no gh api call with -X POST, PATCH, PUT or DELETE, or with -f or -F fields. Read-only gh calls are fine.
|
|
163
|
+
- Do not edit, commit in, or check out branches in the clone. To experiment, copy it and work in the copy. A copied build directory still points at the tree it was configured in, so reconfigure the build in the copy and make every arm's build log name the file that arm changed.
|
|
164
|
+
- Do not edit the text under review. Write only your report.
|
|
165
|
+
|
|
166
|
+
Under review
|
|
167
|
+
EOF
|
|
168
|
+
printf -- '- repository: %s\n' "$repo"
|
|
169
|
+
if [ -n "$clone" ]; then
|
|
170
|
+
printf -- '- clone: %s at %s, the branch exactly as it will be filed\n' "$clone" "$head"
|
|
171
|
+
if [ -n "$mb" ]; then
|
|
172
|
+
printf -- '- what the maintainer sees: git -C %s diff %s..%s\n' "$clone" "$mb" "$head"
|
|
173
|
+
git -C "$clone" diff --stat "$mb..HEAD" | sed 's/^/ /'
|
|
174
|
+
else
|
|
175
|
+
printf -- '- no upstream base found in the clone: ask which ref the branch is filed against\n'
|
|
176
|
+
fi
|
|
177
|
+
fi
|
|
178
|
+
for t in ${texts[@]+"${texts[@]}"}; do
|
|
179
|
+
printf -- '- text: %s (sha256 %s)\n' "$t" "$(sha256 "$t")"
|
|
180
|
+
done
|
|
181
|
+
for t in ${contexts[@]+"${contexts[@]}"}; do
|
|
182
|
+
printf -- '- context from the author, to attack rather than trust: %s\n' "$t"
|
|
183
|
+
done
|
|
184
|
+
|
|
185
|
+
printf '\nAttack at least\n'
|
|
186
|
+
printf '1. Every claim the text makes, re-derived now against the exact revision it names.\n'
|
|
187
|
+
for t in ${texts[@]+"${texts[@]}"}; do
|
|
188
|
+
printf ' %s:\n' "$t"
|
|
189
|
+
bash "$here/claim-check.sh" "$t" | awk 'NF == 0 {exit} {print " " $0}'
|
|
190
|
+
done
|
|
191
|
+
cat <<'EOF'
|
|
192
|
+
2. The proof: the new test fails on the base and passes with the change. Swap file content with git show <base>:<path> rather than switching branches, compare hashes, and make sure the two arms differ. Ask what each step would print if it did nothing.
|
|
193
|
+
3. The project's own CI, read from its workflow files: tests, lint, format, API and mutation checks, run on the change.
|
|
194
|
+
4. Scope: every changed line is needed for what was asked, nothing is unrequested, no comment appears where the surrounding code has none, and documentation, README and CHANGELOG that describe the changed behaviour change with it.
|
|
195
|
+
5. Prior art: nothing duplicates an open pull request or argues with a ruling in a closed issue.
|
|
196
|
+
6. 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.
|
|
197
|
+
7. Anything else that would embarrass the author in front of this maintainer.
|
|
198
|
+
|
|
199
|
+
Report
|
|
200
|
+
EOF
|
|
201
|
+
printf 'Write it to %s. It must start with exactly these lines, with the verdict filled in:\n\n' "$report"
|
|
202
|
+
printf 'review-of: %s\n' "$repo"
|
|
203
|
+
[ -n "$head" ] && printf 'head: %s\n' "$head"
|
|
204
|
+
for t in ${texts[@]+"${texts[@]}"}; do
|
|
205
|
+
printf 'text: sha256:%s %s\n' "$(sha256 "$t")" "$(basename "$t")"
|
|
206
|
+
done
|
|
207
|
+
printf 'author-model: %s\nreviewer-model: %s\n' "$author" "$reviewer"
|
|
208
|
+
printf 'verdict: POST AS IS | POST WITH CHANGES | DO NOT POST\n\n'
|
|
209
|
+
cat <<'EOF'
|
|
210
|
+
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.
|
|
211
|
+
EOF
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
cmd_check() {
|
|
215
|
+
local report="${1:-}" clone="" t
|
|
216
|
+
local texts=()
|
|
217
|
+
[ -n "$report" ] || bad_usage "check needs the report path"
|
|
218
|
+
shift
|
|
219
|
+
while [ "$#" -gt 0 ]; do
|
|
220
|
+
case "$1" in
|
|
221
|
+
--clone) clone="${2:-}"; shift ;;
|
|
222
|
+
--text) texts+=("${2:-}"); shift ;;
|
|
223
|
+
*) bad_usage "unknown argument: $1" ;;
|
|
224
|
+
esac
|
|
225
|
+
shift
|
|
226
|
+
done
|
|
227
|
+
[ -f "$report" ] || refuse "no review report at $report"
|
|
228
|
+
|
|
229
|
+
field() { sed -n "s/^$1: *//p" "$report" | head -1 | tr -d '\r' | sed 's/ *$//'; }
|
|
230
|
+
local author reviewer verdict head why now
|
|
231
|
+
author=$(field author-model)
|
|
232
|
+
reviewer=$(field reviewer-model)
|
|
233
|
+
verdict=$(field verdict | tr '[:lower:]' '[:upper:]')
|
|
234
|
+
head=$(field head)
|
|
235
|
+
[ -n "$author" ] || refuse "$report names no author-model"
|
|
236
|
+
why=$(objection "$(family "$author")" "$(family "$reviewer")")
|
|
237
|
+
[ -z "$why" ] || refuse "$why"
|
|
238
|
+
[ "$verdict" = "POST AS IS" ] ||
|
|
239
|
+
refuse "the verdict is '${verdict:-missing}' and only POST AS IS clears the gate: fix what the review found and review the new version"
|
|
240
|
+
|
|
241
|
+
if [ -n "$clone" ]; then
|
|
242
|
+
now=$(git -C "$clone" rev-parse HEAD 2>/dev/null) || bad_usage "$clone is not a git clone"
|
|
243
|
+
[ -n "$head" ] || refuse "$report records no head, so it cannot clear a branch"
|
|
244
|
+
if [ "${#head}" -lt 12 ] || [ "${now#"$head"}" = "$now" ]; then
|
|
245
|
+
refuse "the branch moved after the review: it attacked ${head:0:12}, the clone is at ${now:0:12}"
|
|
246
|
+
fi
|
|
247
|
+
fi
|
|
248
|
+
for t in ${texts[@]+"${texts[@]}"}; do
|
|
249
|
+
[ -f "$t" ] || bad_usage "$t does not exist"
|
|
250
|
+
grep -q "^text: sha256:$(sha256 "$t")" "$report" ||
|
|
251
|
+
refuse "$t is not the text that was reviewed: its sha256 is not in $report"
|
|
252
|
+
done
|
|
253
|
+
echo "review: POST AS IS by $reviewer on work by $author${head:+ at ${head:0:12}}"
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
case "${1:-}" in
|
|
257
|
+
--help|-h) usage; exit 0 ;;
|
|
258
|
+
reviewer) shift; cmd_reviewer "$@" ;;
|
|
259
|
+
brief) shift; cmd_brief "$@" ;;
|
|
260
|
+
check) shift; cmd_check "$@" ;;
|
|
261
|
+
"") usage >&2; exit 2 ;;
|
|
262
|
+
*) bad_usage "unknown subcommand: $1 (reviewer, brief or check)" ;;
|
|
263
|
+
esac
|
|
@@ -118,7 +118,11 @@ report it in one line and do not proceed to the next step.
|
|
|
118
118
|
you reproduced on the fresh clone in this session, never a line carried
|
|
119
119
|
from a journal. No tool footer, no session link, no
|
|
120
120
|
co-author trailer, no typographic dashes. When a template asks whether AI
|
|
121
|
-
was used, answer in one truthful sentence.
|
|
121
|
+
was used, answer in one truthful sentence. Run `housebroken claims` over
|
|
122
|
+
the body and re-measure every line it lists, now, against the exact
|
|
123
|
+
revision that sentence names. A claim that names its revision can still
|
|
124
|
+
be wrong about it, which is why the listing is the whole gate: the
|
|
125
|
+
re-derivation is yours to do.
|
|
122
126
|
|
|
123
127
|
7. **Know the paperwork.**
|
|
124
128
|
Before the first pull request to an organization, find its agreement: CLA,
|
|
@@ -136,15 +140,26 @@ report it in one line and do not proceed to the next step.
|
|
|
136
140
|
|
|
137
141
|
9. **File through the gate.**
|
|
138
142
|
`housebroken branch <clone>` first. It refuses a dirty working tree, a file
|
|
139
|
-
whose mode disagrees with its own siblings, a
|
|
140
|
-
ignores,
|
|
141
|
-
|
|
142
|
-
|
|
143
|
+
whose mode disagrees with its own siblings, a file the branch adds that the
|
|
144
|
+
repository ignores, a commit carrying a tool trailer or a session link, a
|
|
145
|
+
sign-off that names a username, and a branch that is not on top of its
|
|
146
|
+
base, and it prints every absolute claim your added prose makes so you can
|
|
147
|
+
falsify each one against the code. Then the adversarial review:
|
|
148
|
+
`housebroken review brief --author <your model> --repo owner/repo --clone <clone> --text <body file>`
|
|
149
|
+
names the reviewer and prints its brief. The reviewer is never the model
|
|
150
|
+
that wrote the change: one tier down, Fable to Opus and Opus to Sonnet,
|
|
151
|
+
and never below Sonnet, so Sonnet's work goes to Opus. Hand the brief to a
|
|
152
|
+
fresh agent running that model; anything of yours it reads is for it to
|
|
153
|
+
attack, not to trust. It writes its report where the brief says, with its
|
|
154
|
+
own evidence behind every finding. Every fix it asks for is a new head,
|
|
155
|
+
and a new head is reviewed again. When it passes, re-read every claim it
|
|
156
|
+
did not re-derive itself: a passed review is not a proof. Then
|
|
143
157
|
`housebroken file owner/repo --title ... --body-file ...`, the only way a
|
|
144
158
|
pull request is opened. Never run the pull request creation command
|
|
145
159
|
directly. The gate refuses when the prior-art printout for that repository
|
|
146
|
-
is missing or older than a day,
|
|
147
|
-
|
|
160
|
+
is missing or older than a day, when the body carries a footer, a trailer
|
|
161
|
+
or a dash character, or when there is no POST AS IS review of the exact
|
|
162
|
+
head and body being filed. A refusal is a result; fix the cause.
|
|
148
163
|
|
|
149
164
|
10. **Watch it land.**
|
|
150
165
|
`housebroken verify owner/repo PR` re-derives from GitHub that the head is
|
|
@@ -157,7 +172,12 @@ report it in one line and do not proceed to the next step.
|
|
|
157
172
|
on every open pull request. A list of who commented is not a read, and a
|
|
158
173
|
conversion to draft is a review. Act on every human item, then run
|
|
159
174
|
`housebroken inbox --ack`. Answer every maintainer comment the same day,
|
|
160
|
-
in the user's voice
|
|
175
|
+
in the user's voice, and run `housebroken claims` over the reply before
|
|
176
|
+
it is posted: the only claim that has gone out wrong here was in a
|
|
177
|
+
reply, not a body. A reply that concedes a point, disagrees, or rides on
|
|
178
|
+
a code change goes through the adversarial review of step 9 first, with
|
|
179
|
+
the reply as its `--text`, and `housebroken review check <report> --text
|
|
180
|
+
<reply file>` must pass before it is posted. Rework what is asked for as a second commit so the reviewer sees
|
|
161
181
|
the change. When the maintainer is
|
|
162
182
|
right, concede in one sentence and let them close it. Never nudge a
|
|
163
183
|
silent maintainer without the user's explicit word. After answering a
|
|
@@ -207,8 +227,9 @@ report it in one line and do not proceed to the next step.
|
|
|
207
227
|
## What you say to the user
|
|
208
228
|
|
|
209
229
|
Before filing: the repository, the finding in one sentence, the prior-art
|
|
210
|
-
result in one sentence, the red-then-green result, the
|
|
211
|
-
|
|
230
|
+
result in one sentence, the red-then-green result, the review's verdict and
|
|
231
|
+
the model that gave it, the agreement the organization wants, and the exact
|
|
232
|
+
command you are about to run. After
|
|
212
233
|
filing: the pull request URL and the verify result. At the end of the run:
|
|
213
234
|
what went into the ledger, or that nothing did. On a refusal at any
|
|
214
235
|
step: which step, and the one sentence that explains it.
|
|
@@ -219,4 +240,5 @@ Never open a pull request without the prior-art printout. Never argue with a
|
|
|
219
240
|
ruling in a closed issue. Never file where the policy asks you not to. Never
|
|
220
241
|
put a footer, a session link or a co-author trailer on anything that leaves
|
|
221
242
|
the user's repositories. Never post a comment upstream that the user has not
|
|
222
|
-
seen. Never
|
|
243
|
+
seen. Never file a change a different model has not attacked. Never claim a
|
|
244
|
+
test ran that you did not run.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.5.0"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.2.1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|