@codyswann/lisa 2.226.1 → 2.227.0
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.
- package/package.json +1 -1
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/rules/eager/history-audit.md +27 -0
- package/plugins/lisa/rules/reference/history-audit.md +42 -0
- package/plugins/lisa/scripts/remote-agent-aws-setup.sh +32 -3
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/scripts/remote-agent-aws-setup.sh +32 -3
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/rules/eager/history-audit.md +27 -0
- package/plugins/lisa-copilot/rules/reference/history-audit.md +42 -0
- package/plugins/lisa-copilot/scripts/remote-agent-aws-setup.sh +32 -3
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/rules/history-audit-reference.mdc +47 -0
- package/plugins/lisa-cursor/rules/history-audit.mdc +32 -0
- package/plugins/lisa-cursor/scripts/remote-agent-aws-setup.sh +32 -3
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/src/base/rules/eager/history-audit.md +27 -0
- package/plugins/src/base/rules/reference/history-audit.md +42 -0
- package/plugins/src/base/scripts/remote-agent-aws-setup.sh +32 -3
package/package.json
CHANGED
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
"form-data": ">=4.0.6"
|
|
103
103
|
},
|
|
104
104
|
"name": "@codyswann/lisa",
|
|
105
|
-
"version": "2.
|
|
105
|
+
"version": "2.227.0",
|
|
106
106
|
"description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
|
|
107
107
|
"main": "dist/index.js",
|
|
108
108
|
"exports": {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# History Audit — Before Removing or Changing Existing Behavior (load-bearing)
|
|
2
|
+
|
|
3
|
+
When a proposed change would **remove, gate, skip, consolidate, weaken, or relax existing behavior** — and the motivation is your own assessment that the code looks redundant, wasteful, slow, or wrong (rather than a ticket, bug report, or spec) — audit the history **before presenting the change as safe or implementing it**.
|
|
4
|
+
|
|
5
|
+
## How to apply
|
|
6
|
+
|
|
7
|
+
1. `git log --follow` the affected files and `git log --grep` for related keywords.
|
|
8
|
+
2. Read **full commit bodies** (never just subjects), code comments, and covering tests — the defense usually lives there, often naming the exact incident the behavior prevents.
|
|
9
|
+
3. Deliver every such recommendation with an explicit verdict:
|
|
10
|
+
- **Defended by \<commit/comment/test\>** — adapt the proposal to preserve that reason.
|
|
11
|
+
- **No defense found** — genuinely accidental; safe to change, and say so.
|
|
12
|
+
|
|
13
|
+
## Scope
|
|
14
|
+
|
|
15
|
+
- **Diagnosis doesn't need the audit; prescriptions do.** Analyzing what is slow or broken is free; recommending that existing behavior stop happening is what triggers the audit. If presenting unaudited ideas, label them as such.
|
|
16
|
+
- Changes driven by an external requirement may cite that requirement as their defense and move on.
|
|
17
|
+
- "Nothing was deleted" is not an exemption — a change that weakens a guarantee (e.g. adding a cache/stamp that skips a self-healing pass) alters existing behavior and needs the same audit.
|
|
18
|
+
|
|
19
|
+
## Forbidden
|
|
20
|
+
|
|
21
|
+
- Recommending removal or weakening of existing behavior as "safe" without the verdict.
|
|
22
|
+
- Auditing subjects only (`--oneline` skims miss the evidence).
|
|
23
|
+
- Treating redundant-looking behavior as accidental by default — defended is the norm, not the exception.
|
|
24
|
+
|
|
25
|
+
This rule compounds with commit discipline: documenting the **why** in commit bodies is what makes future audits cheap.
|
|
26
|
+
|
|
27
|
+
Full prose: [reference/history-audit.md](../reference/history-audit.md).
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# History Audit — Before Removing or Changing Existing Behavior
|
|
2
|
+
|
|
3
|
+
When a proposed change would remove, gate, skip, consolidate, weaken, or relax existing behavior — and the motivation is your own assessment that the code looks redundant, wasteful, slow, or wrong, rather than a ticket, bug report, or spec — **audit the history before presenting the change as safe or implementing it**. This is Chesterton's fence made operational: the fence's reason is usually written down; go read it.
|
|
4
|
+
|
|
5
|
+
This is the historical counterpart to the `empirical-inquiry` rule: `empirical-inquiry` establishes facts about how the system behaves *now* by probing it; this rule establishes *why the system behaves that way* by reading the record. Both reject confident-sounding reasoning as a substitute for evidence.
|
|
6
|
+
|
|
7
|
+
## Why this rule exists
|
|
8
|
+
|
|
9
|
+
Optimization and cleanup recommendations fail in a characteristic way: the code genuinely *is* doing redundant-looking work, the diagnosis is correct, and the proposed fix would still ship a regression — because the redundancy is load-bearing and its reason lives in a commit body, a code comment, or a test the recommender never read. In a real Lisa incident, a performance audit of the postinstall pipeline produced five recommendations; the history audit walked back two of them (a "redundant" apply pass existed to fix a bootstrap chicken-and-egg; a "wasteful" detached re-run existed because the package manager clobbers `package.json` after lifecycle scripts finish) and confirmed the rest were genuinely accidental. Without the audit, the confident-sounding fixes would have re-shipped bugs that earlier commits had explicitly fixed.
|
|
10
|
+
|
|
11
|
+
## When this rule applies
|
|
12
|
+
|
|
13
|
+
- A recommendation proposes that existing behavior stop happening: deleting a code path, gating an unconditional step, deduplicating repeated work, relaxing a guard or retry, skipping a pass "when nothing changed."
|
|
14
|
+
- The motivation is internal — the code *looks* redundant, wasteful, slow, dead, or overcautious — rather than an external requirement.
|
|
15
|
+
- **Nothing needs to be deleted to trigger it.** A change that weakens a guarantee alters existing behavior just as much: adding a cache or version-stamp that skips a self-healing pass, narrowing a matcher, batching what was deliberately serialized.
|
|
16
|
+
|
|
17
|
+
## When it does not apply
|
|
18
|
+
|
|
19
|
+
- **Diagnosis is free.** Measuring, profiling, and explaining what is slow or broken needs no audit. The audit gates *prescriptions* — the moment an observation is about to become "so we should remove/skip/gate X."
|
|
20
|
+
- **Requirement-driven changes may cite the requirement.** Implementing a ticket, fixing a reproduced bug, or following a spec supplies external evidence; cite it as the defense and move on. Normal verification discipline covers those.
|
|
21
|
+
- **Spitballing is fine when labeled.** Presenting early ideas before the audit is acceptable if they are explicitly marked as not yet history-audited. What is forbidden is presenting them as safe.
|
|
22
|
+
|
|
23
|
+
## How to apply it
|
|
24
|
+
|
|
25
|
+
1. **Trace the artifact history.** `git log --follow` on each affected file; `git log --grep` for related keywords (feature names, flag names, error strings). Find the commits that introduced and last modified the behavior.
|
|
26
|
+
2. **Read the full commit bodies.** Subjects rarely carry the defense; bodies do — often naming the exact incident, the affected projects, and the failure mode the behavior prevents. `--oneline` skims are how the evidence gets missed. Extend the same reading to code comments around the behavior and to tests whose names encode a philosophy (a test called `*-guard` or `*-preserves-*` is a defense).
|
|
27
|
+
3. **Check for a prior removal.** Search for commits that removed the same behavior before — if it was removed and later restored, the restoration commit is the strongest defense on record, and your proposal must answer it specifically.
|
|
28
|
+
4. **Issue a per-recommendation verdict.** Every prescription ships in one of two states:
|
|
29
|
+
- **Defended by \<commit/comment/test\>** — the behavior has a recorded reason. Adapt the proposal so that reason keeps holding (gate instead of delete, preserve the invariant, keep the escape hatch), and say what the defense was.
|
|
30
|
+
- **No defense found** — you searched and no commit, comment, or test justifies it. That absence is itself a finding: state it, and proceed.
|
|
31
|
+
|
|
32
|
+
The verdict is the enforcement mechanism — it cannot be filled in without doing the audit.
|
|
33
|
+
|
|
34
|
+
## What this rule forbids
|
|
35
|
+
|
|
36
|
+
- Presenting the removal or weakening of existing behavior as safe without a verdict.
|
|
37
|
+
- Auditing by subject line only.
|
|
38
|
+
- Treating redundant-looking behavior as accidental by default. In a codebase with disciplined commit messages, *defended* is the norm; genuine accidents are the exception, and the audit is how you tell them apart.
|
|
39
|
+
|
|
40
|
+
## The compounding loop
|
|
41
|
+
|
|
42
|
+
This rule only works in a repository whose commit messages record the **why** — which the commit-discipline rules already mandate. The two form a loop: writing down why a behavior exists makes the future audit a five-minute read instead of an archaeology project, and the audit is what makes writing it down pay off. When your own change survives an audit and ships, document its why with the same care — the next agent's audit depends on it.
|
|
@@ -114,6 +114,27 @@ AWS_CLI_PUBLIC_KEY
|
|
|
114
114
|
trap - EXIT
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
remove_profile_setting() {
|
|
118
|
+
local credentials_file profile setting temporary_file
|
|
119
|
+
credentials_file="$1"
|
|
120
|
+
profile="$2"
|
|
121
|
+
setting="$3"
|
|
122
|
+
[ -f "$credentials_file" ] || return 0
|
|
123
|
+
|
|
124
|
+
temporary_file="$(mktemp "${credentials_file}.XXXXXX")"
|
|
125
|
+
awk -v profile="$profile" -v setting="$setting" '
|
|
126
|
+
/^\[[^]]+\][[:space:]]*$/ {
|
|
127
|
+
section = $0
|
|
128
|
+
sub(/^\[/, "", section)
|
|
129
|
+
sub(/\][[:space:]]*$/, "", section)
|
|
130
|
+
in_profile = section == profile
|
|
131
|
+
}
|
|
132
|
+
!(in_profile && $0 ~ "^[[:space:]]*" setting "[[:space:]]*=") { print }
|
|
133
|
+
' "$credentials_file" >"$temporary_file"
|
|
134
|
+
chmod 600 "$temporary_file"
|
|
135
|
+
mv "$temporary_file" "$credentials_file"
|
|
136
|
+
}
|
|
137
|
+
|
|
117
138
|
sanitize_session_name() {
|
|
118
139
|
local candidate
|
|
119
140
|
candidate="$(printf '%s' "${LISA_REMOTE_AGENT:-remote-agent}" \
|
|
@@ -154,22 +175,30 @@ profiles_json="$(printf '%s' "$bootstrap_json" | jq -c '
|
|
|
154
175
|
end
|
|
155
176
|
')"
|
|
156
177
|
|
|
157
|
-
printf '%s' "$profiles_json" | jq -e '
|
|
178
|
+
printf '%s' "$profiles_json" | jq -e --arg bootstrap_profile "$BOOTSTRAP_PROFILE" '
|
|
158
179
|
type == "object" and length > 0 and
|
|
159
180
|
all(to_entries[];
|
|
181
|
+
(.key != $bootstrap_profile) and
|
|
160
182
|
(.key | test("^[A-Za-z0-9_-]+$")) and
|
|
161
183
|
(.value.roleArn | type == "string" and startswith("arn:aws:iam::")) and
|
|
162
184
|
(.value.region | type == "string" and length > 0)
|
|
163
185
|
)
|
|
164
186
|
' >/dev/null || fail "bootstrap profiles must map safe names to roleArn and region"
|
|
165
187
|
|
|
166
|
-
|
|
188
|
+
credentials_file="${AWS_SHARED_CREDENTIALS_FILE:-$HOME/.aws/credentials}"
|
|
189
|
+
config_file="${AWS_CONFIG_FILE:-$HOME/.aws/config}"
|
|
190
|
+
mkdir -p "$HOME/.aws" "$(dirname "$credentials_file")" "$(dirname "$config_file")"
|
|
167
191
|
chmod 700 "$HOME/.aws"
|
|
168
192
|
|
|
169
193
|
aws configure set aws_access_key_id "$access_key_id" --profile "$BOOTSTRAP_PROFILE"
|
|
170
194
|
aws configure set aws_secret_access_key "$secret_access_key" --profile "$BOOTSTRAP_PROFILE"
|
|
171
195
|
if [ -n "$session_token" ]; then
|
|
172
196
|
aws configure set aws_session_token "$session_token" --profile "$BOOTSTRAP_PROFILE"
|
|
197
|
+
else
|
|
198
|
+
remove_profile_setting \
|
|
199
|
+
"$credentials_file" \
|
|
200
|
+
"$BOOTSTRAP_PROFILE" \
|
|
201
|
+
"aws_session_token"
|
|
173
202
|
fi
|
|
174
203
|
|
|
175
204
|
session_name="$(sanitize_session_name)"
|
|
@@ -194,7 +223,7 @@ aws configure set external_id "$external_id" --profile default
|
|
|
194
223
|
aws configure set role_session_name "$session_name" --profile default
|
|
195
224
|
aws configure set region "$default_region" --profile default
|
|
196
225
|
|
|
197
|
-
chmod 600 "$
|
|
226
|
+
chmod 600 "$credentials_file" "$config_file"
|
|
198
227
|
|
|
199
228
|
if [ "${LISA_AWS_SKIP_VERIFY:-0}" != "1" ]; then
|
|
200
229
|
AWS_PAGER="" aws sts get-caller-identity --profile "$default_profile" >/dev/null
|
|
@@ -114,6 +114,27 @@ AWS_CLI_PUBLIC_KEY
|
|
|
114
114
|
trap - EXIT
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
remove_profile_setting() {
|
|
118
|
+
local credentials_file profile setting temporary_file
|
|
119
|
+
credentials_file="$1"
|
|
120
|
+
profile="$2"
|
|
121
|
+
setting="$3"
|
|
122
|
+
[ -f "$credentials_file" ] || return 0
|
|
123
|
+
|
|
124
|
+
temporary_file="$(mktemp "${credentials_file}.XXXXXX")"
|
|
125
|
+
awk -v profile="$profile" -v setting="$setting" '
|
|
126
|
+
/^\[[^]]+\][[:space:]]*$/ {
|
|
127
|
+
section = $0
|
|
128
|
+
sub(/^\[/, "", section)
|
|
129
|
+
sub(/\][[:space:]]*$/, "", section)
|
|
130
|
+
in_profile = section == profile
|
|
131
|
+
}
|
|
132
|
+
!(in_profile && $0 ~ "^[[:space:]]*" setting "[[:space:]]*=") { print }
|
|
133
|
+
' "$credentials_file" >"$temporary_file"
|
|
134
|
+
chmod 600 "$temporary_file"
|
|
135
|
+
mv "$temporary_file" "$credentials_file"
|
|
136
|
+
}
|
|
137
|
+
|
|
117
138
|
sanitize_session_name() {
|
|
118
139
|
local candidate
|
|
119
140
|
candidate="$(printf '%s' "${LISA_REMOTE_AGENT:-remote-agent}" \
|
|
@@ -154,22 +175,30 @@ profiles_json="$(printf '%s' "$bootstrap_json" | jq -c '
|
|
|
154
175
|
end
|
|
155
176
|
')"
|
|
156
177
|
|
|
157
|
-
printf '%s' "$profiles_json" | jq -e '
|
|
178
|
+
printf '%s' "$profiles_json" | jq -e --arg bootstrap_profile "$BOOTSTRAP_PROFILE" '
|
|
158
179
|
type == "object" and length > 0 and
|
|
159
180
|
all(to_entries[];
|
|
181
|
+
(.key != $bootstrap_profile) and
|
|
160
182
|
(.key | test("^[A-Za-z0-9_-]+$")) and
|
|
161
183
|
(.value.roleArn | type == "string" and startswith("arn:aws:iam::")) and
|
|
162
184
|
(.value.region | type == "string" and length > 0)
|
|
163
185
|
)
|
|
164
186
|
' >/dev/null || fail "bootstrap profiles must map safe names to roleArn and region"
|
|
165
187
|
|
|
166
|
-
|
|
188
|
+
credentials_file="${AWS_SHARED_CREDENTIALS_FILE:-$HOME/.aws/credentials}"
|
|
189
|
+
config_file="${AWS_CONFIG_FILE:-$HOME/.aws/config}"
|
|
190
|
+
mkdir -p "$HOME/.aws" "$(dirname "$credentials_file")" "$(dirname "$config_file")"
|
|
167
191
|
chmod 700 "$HOME/.aws"
|
|
168
192
|
|
|
169
193
|
aws configure set aws_access_key_id "$access_key_id" --profile "$BOOTSTRAP_PROFILE"
|
|
170
194
|
aws configure set aws_secret_access_key "$secret_access_key" --profile "$BOOTSTRAP_PROFILE"
|
|
171
195
|
if [ -n "$session_token" ]; then
|
|
172
196
|
aws configure set aws_session_token "$session_token" --profile "$BOOTSTRAP_PROFILE"
|
|
197
|
+
else
|
|
198
|
+
remove_profile_setting \
|
|
199
|
+
"$credentials_file" \
|
|
200
|
+
"$BOOTSTRAP_PROFILE" \
|
|
201
|
+
"aws_session_token"
|
|
173
202
|
fi
|
|
174
203
|
|
|
175
204
|
session_name="$(sanitize_session_name)"
|
|
@@ -194,7 +223,7 @@ aws configure set external_id "$external_id" --profile default
|
|
|
194
223
|
aws configure set role_session_name "$session_name" --profile default
|
|
195
224
|
aws configure set region "$default_region" --profile default
|
|
196
225
|
|
|
197
|
-
chmod 600 "$
|
|
226
|
+
chmod 600 "$credentials_file" "$config_file"
|
|
198
227
|
|
|
199
228
|
if [ "${LISA_AWS_SKIP_VERIFY:-0}" != "1" ]; then
|
|
200
229
|
AWS_PAGER="" aws sts get-caller-identity --profile "$default_profile" >/dev/null
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# History Audit — Before Removing or Changing Existing Behavior (load-bearing)
|
|
2
|
+
|
|
3
|
+
When a proposed change would **remove, gate, skip, consolidate, weaken, or relax existing behavior** — and the motivation is your own assessment that the code looks redundant, wasteful, slow, or wrong (rather than a ticket, bug report, or spec) — audit the history **before presenting the change as safe or implementing it**.
|
|
4
|
+
|
|
5
|
+
## How to apply
|
|
6
|
+
|
|
7
|
+
1. `git log --follow` the affected files and `git log --grep` for related keywords.
|
|
8
|
+
2. Read **full commit bodies** (never just subjects), code comments, and covering tests — the defense usually lives there, often naming the exact incident the behavior prevents.
|
|
9
|
+
3. Deliver every such recommendation with an explicit verdict:
|
|
10
|
+
- **Defended by \<commit/comment/test\>** — adapt the proposal to preserve that reason.
|
|
11
|
+
- **No defense found** — genuinely accidental; safe to change, and say so.
|
|
12
|
+
|
|
13
|
+
## Scope
|
|
14
|
+
|
|
15
|
+
- **Diagnosis doesn't need the audit; prescriptions do.** Analyzing what is slow or broken is free; recommending that existing behavior stop happening is what triggers the audit. If presenting unaudited ideas, label them as such.
|
|
16
|
+
- Changes driven by an external requirement may cite that requirement as their defense and move on.
|
|
17
|
+
- "Nothing was deleted" is not an exemption — a change that weakens a guarantee (e.g. adding a cache/stamp that skips a self-healing pass) alters existing behavior and needs the same audit.
|
|
18
|
+
|
|
19
|
+
## Forbidden
|
|
20
|
+
|
|
21
|
+
- Recommending removal or weakening of existing behavior as "safe" without the verdict.
|
|
22
|
+
- Auditing subjects only (`--oneline` skims miss the evidence).
|
|
23
|
+
- Treating redundant-looking behavior as accidental by default — defended is the norm, not the exception.
|
|
24
|
+
|
|
25
|
+
This rule compounds with commit discipline: documenting the **why** in commit bodies is what makes future audits cheap.
|
|
26
|
+
|
|
27
|
+
Full prose: [reference/history-audit.md](../reference/history-audit.md).
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# History Audit — Before Removing or Changing Existing Behavior
|
|
2
|
+
|
|
3
|
+
When a proposed change would remove, gate, skip, consolidate, weaken, or relax existing behavior — and the motivation is your own assessment that the code looks redundant, wasteful, slow, or wrong, rather than a ticket, bug report, or spec — **audit the history before presenting the change as safe or implementing it**. This is Chesterton's fence made operational: the fence's reason is usually written down; go read it.
|
|
4
|
+
|
|
5
|
+
This is the historical counterpart to the `empirical-inquiry` rule: `empirical-inquiry` establishes facts about how the system behaves *now* by probing it; this rule establishes *why the system behaves that way* by reading the record. Both reject confident-sounding reasoning as a substitute for evidence.
|
|
6
|
+
|
|
7
|
+
## Why this rule exists
|
|
8
|
+
|
|
9
|
+
Optimization and cleanup recommendations fail in a characteristic way: the code genuinely *is* doing redundant-looking work, the diagnosis is correct, and the proposed fix would still ship a regression — because the redundancy is load-bearing and its reason lives in a commit body, a code comment, or a test the recommender never read. In a real Lisa incident, a performance audit of the postinstall pipeline produced five recommendations; the history audit walked back two of them (a "redundant" apply pass existed to fix a bootstrap chicken-and-egg; a "wasteful" detached re-run existed because the package manager clobbers `package.json` after lifecycle scripts finish) and confirmed the rest were genuinely accidental. Without the audit, the confident-sounding fixes would have re-shipped bugs that earlier commits had explicitly fixed.
|
|
10
|
+
|
|
11
|
+
## When this rule applies
|
|
12
|
+
|
|
13
|
+
- A recommendation proposes that existing behavior stop happening: deleting a code path, gating an unconditional step, deduplicating repeated work, relaxing a guard or retry, skipping a pass "when nothing changed."
|
|
14
|
+
- The motivation is internal — the code *looks* redundant, wasteful, slow, dead, or overcautious — rather than an external requirement.
|
|
15
|
+
- **Nothing needs to be deleted to trigger it.** A change that weakens a guarantee alters existing behavior just as much: adding a cache or version-stamp that skips a self-healing pass, narrowing a matcher, batching what was deliberately serialized.
|
|
16
|
+
|
|
17
|
+
## When it does not apply
|
|
18
|
+
|
|
19
|
+
- **Diagnosis is free.** Measuring, profiling, and explaining what is slow or broken needs no audit. The audit gates *prescriptions* — the moment an observation is about to become "so we should remove/skip/gate X."
|
|
20
|
+
- **Requirement-driven changes may cite the requirement.** Implementing a ticket, fixing a reproduced bug, or following a spec supplies external evidence; cite it as the defense and move on. Normal verification discipline covers those.
|
|
21
|
+
- **Spitballing is fine when labeled.** Presenting early ideas before the audit is acceptable if they are explicitly marked as not yet history-audited. What is forbidden is presenting them as safe.
|
|
22
|
+
|
|
23
|
+
## How to apply it
|
|
24
|
+
|
|
25
|
+
1. **Trace the artifact history.** `git log --follow` on each affected file; `git log --grep` for related keywords (feature names, flag names, error strings). Find the commits that introduced and last modified the behavior.
|
|
26
|
+
2. **Read the full commit bodies.** Subjects rarely carry the defense; bodies do — often naming the exact incident, the affected projects, and the failure mode the behavior prevents. `--oneline` skims are how the evidence gets missed. Extend the same reading to code comments around the behavior and to tests whose names encode a philosophy (a test called `*-guard` or `*-preserves-*` is a defense).
|
|
27
|
+
3. **Check for a prior removal.** Search for commits that removed the same behavior before — if it was removed and later restored, the restoration commit is the strongest defense on record, and your proposal must answer it specifically.
|
|
28
|
+
4. **Issue a per-recommendation verdict.** Every prescription ships in one of two states:
|
|
29
|
+
- **Defended by \<commit/comment/test\>** — the behavior has a recorded reason. Adapt the proposal so that reason keeps holding (gate instead of delete, preserve the invariant, keep the escape hatch), and say what the defense was.
|
|
30
|
+
- **No defense found** — you searched and no commit, comment, or test justifies it. That absence is itself a finding: state it, and proceed.
|
|
31
|
+
|
|
32
|
+
The verdict is the enforcement mechanism — it cannot be filled in without doing the audit.
|
|
33
|
+
|
|
34
|
+
## What this rule forbids
|
|
35
|
+
|
|
36
|
+
- Presenting the removal or weakening of existing behavior as safe without a verdict.
|
|
37
|
+
- Auditing by subject line only.
|
|
38
|
+
- Treating redundant-looking behavior as accidental by default. In a codebase with disciplined commit messages, *defended* is the norm; genuine accidents are the exception, and the audit is how you tell them apart.
|
|
39
|
+
|
|
40
|
+
## The compounding loop
|
|
41
|
+
|
|
42
|
+
This rule only works in a repository whose commit messages record the **why** — which the commit-discipline rules already mandate. The two form a loop: writing down why a behavior exists makes the future audit a five-minute read instead of an archaeology project, and the audit is what makes writing it down pay off. When your own change survives an audit and ships, document its why with the same care — the next agent's audit depends on it.
|
|
@@ -114,6 +114,27 @@ AWS_CLI_PUBLIC_KEY
|
|
|
114
114
|
trap - EXIT
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
remove_profile_setting() {
|
|
118
|
+
local credentials_file profile setting temporary_file
|
|
119
|
+
credentials_file="$1"
|
|
120
|
+
profile="$2"
|
|
121
|
+
setting="$3"
|
|
122
|
+
[ -f "$credentials_file" ] || return 0
|
|
123
|
+
|
|
124
|
+
temporary_file="$(mktemp "${credentials_file}.XXXXXX")"
|
|
125
|
+
awk -v profile="$profile" -v setting="$setting" '
|
|
126
|
+
/^\[[^]]+\][[:space:]]*$/ {
|
|
127
|
+
section = $0
|
|
128
|
+
sub(/^\[/, "", section)
|
|
129
|
+
sub(/\][[:space:]]*$/, "", section)
|
|
130
|
+
in_profile = section == profile
|
|
131
|
+
}
|
|
132
|
+
!(in_profile && $0 ~ "^[[:space:]]*" setting "[[:space:]]*=") { print }
|
|
133
|
+
' "$credentials_file" >"$temporary_file"
|
|
134
|
+
chmod 600 "$temporary_file"
|
|
135
|
+
mv "$temporary_file" "$credentials_file"
|
|
136
|
+
}
|
|
137
|
+
|
|
117
138
|
sanitize_session_name() {
|
|
118
139
|
local candidate
|
|
119
140
|
candidate="$(printf '%s' "${LISA_REMOTE_AGENT:-remote-agent}" \
|
|
@@ -154,22 +175,30 @@ profiles_json="$(printf '%s' "$bootstrap_json" | jq -c '
|
|
|
154
175
|
end
|
|
155
176
|
')"
|
|
156
177
|
|
|
157
|
-
printf '%s' "$profiles_json" | jq -e '
|
|
178
|
+
printf '%s' "$profiles_json" | jq -e --arg bootstrap_profile "$BOOTSTRAP_PROFILE" '
|
|
158
179
|
type == "object" and length > 0 and
|
|
159
180
|
all(to_entries[];
|
|
181
|
+
(.key != $bootstrap_profile) and
|
|
160
182
|
(.key | test("^[A-Za-z0-9_-]+$")) and
|
|
161
183
|
(.value.roleArn | type == "string" and startswith("arn:aws:iam::")) and
|
|
162
184
|
(.value.region | type == "string" and length > 0)
|
|
163
185
|
)
|
|
164
186
|
' >/dev/null || fail "bootstrap profiles must map safe names to roleArn and region"
|
|
165
187
|
|
|
166
|
-
|
|
188
|
+
credentials_file="${AWS_SHARED_CREDENTIALS_FILE:-$HOME/.aws/credentials}"
|
|
189
|
+
config_file="${AWS_CONFIG_FILE:-$HOME/.aws/config}"
|
|
190
|
+
mkdir -p "$HOME/.aws" "$(dirname "$credentials_file")" "$(dirname "$config_file")"
|
|
167
191
|
chmod 700 "$HOME/.aws"
|
|
168
192
|
|
|
169
193
|
aws configure set aws_access_key_id "$access_key_id" --profile "$BOOTSTRAP_PROFILE"
|
|
170
194
|
aws configure set aws_secret_access_key "$secret_access_key" --profile "$BOOTSTRAP_PROFILE"
|
|
171
195
|
if [ -n "$session_token" ]; then
|
|
172
196
|
aws configure set aws_session_token "$session_token" --profile "$BOOTSTRAP_PROFILE"
|
|
197
|
+
else
|
|
198
|
+
remove_profile_setting \
|
|
199
|
+
"$credentials_file" \
|
|
200
|
+
"$BOOTSTRAP_PROFILE" \
|
|
201
|
+
"aws_session_token"
|
|
173
202
|
fi
|
|
174
203
|
|
|
175
204
|
session_name="$(sanitize_session_name)"
|
|
@@ -194,7 +223,7 @@ aws configure set external_id "$external_id" --profile default
|
|
|
194
223
|
aws configure set role_session_name "$session_name" --profile default
|
|
195
224
|
aws configure set region "$default_region" --profile default
|
|
196
225
|
|
|
197
|
-
chmod 600 "$
|
|
226
|
+
chmod 600 "$credentials_file" "$config_file"
|
|
198
227
|
|
|
199
228
|
if [ "${LISA_AWS_SKIP_VERIFY:-0}" != "1" ]; then
|
|
200
229
|
AWS_PAGER="" aws sts get-caller-identity --profile "$default_profile" >/dev/null
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "History Audit — Before Removing or Changing Existing Behavior"
|
|
3
|
+
alwaysApply: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# History Audit — Before Removing or Changing Existing Behavior
|
|
7
|
+
|
|
8
|
+
When a proposed change would remove, gate, skip, consolidate, weaken, or relax existing behavior — and the motivation is your own assessment that the code looks redundant, wasteful, slow, or wrong, rather than a ticket, bug report, or spec — **audit the history before presenting the change as safe or implementing it**. This is Chesterton's fence made operational: the fence's reason is usually written down; go read it.
|
|
9
|
+
|
|
10
|
+
This is the historical counterpart to the `empirical-inquiry` rule: `empirical-inquiry` establishes facts about how the system behaves *now* by probing it; this rule establishes *why the system behaves that way* by reading the record. Both reject confident-sounding reasoning as a substitute for evidence.
|
|
11
|
+
|
|
12
|
+
## Why this rule exists
|
|
13
|
+
|
|
14
|
+
Optimization and cleanup recommendations fail in a characteristic way: the code genuinely *is* doing redundant-looking work, the diagnosis is correct, and the proposed fix would still ship a regression — because the redundancy is load-bearing and its reason lives in a commit body, a code comment, or a test the recommender never read. In a real Lisa incident, a performance audit of the postinstall pipeline produced five recommendations; the history audit walked back two of them (a "redundant" apply pass existed to fix a bootstrap chicken-and-egg; a "wasteful" detached re-run existed because the package manager clobbers `package.json` after lifecycle scripts finish) and confirmed the rest were genuinely accidental. Without the audit, the confident-sounding fixes would have re-shipped bugs that earlier commits had explicitly fixed.
|
|
15
|
+
|
|
16
|
+
## When this rule applies
|
|
17
|
+
|
|
18
|
+
- A recommendation proposes that existing behavior stop happening: deleting a code path, gating an unconditional step, deduplicating repeated work, relaxing a guard or retry, skipping a pass "when nothing changed."
|
|
19
|
+
- The motivation is internal — the code *looks* redundant, wasteful, slow, dead, or overcautious — rather than an external requirement.
|
|
20
|
+
- **Nothing needs to be deleted to trigger it.** A change that weakens a guarantee alters existing behavior just as much: adding a cache or version-stamp that skips a self-healing pass, narrowing a matcher, batching what was deliberately serialized.
|
|
21
|
+
|
|
22
|
+
## When it does not apply
|
|
23
|
+
|
|
24
|
+
- **Diagnosis is free.** Measuring, profiling, and explaining what is slow or broken needs no audit. The audit gates *prescriptions* — the moment an observation is about to become "so we should remove/skip/gate X."
|
|
25
|
+
- **Requirement-driven changes may cite the requirement.** Implementing a ticket, fixing a reproduced bug, or following a spec supplies external evidence; cite it as the defense and move on. Normal verification discipline covers those.
|
|
26
|
+
- **Spitballing is fine when labeled.** Presenting early ideas before the audit is acceptable if they are explicitly marked as not yet history-audited. What is forbidden is presenting them as safe.
|
|
27
|
+
|
|
28
|
+
## How to apply it
|
|
29
|
+
|
|
30
|
+
1. **Trace the artifact history.** `git log --follow` on each affected file; `git log --grep` for related keywords (feature names, flag names, error strings). Find the commits that introduced and last modified the behavior.
|
|
31
|
+
2. **Read the full commit bodies.** Subjects rarely carry the defense; bodies do — often naming the exact incident, the affected projects, and the failure mode the behavior prevents. `--oneline` skims are how the evidence gets missed. Extend the same reading to code comments around the behavior and to tests whose names encode a philosophy (a test called `*-guard` or `*-preserves-*` is a defense).
|
|
32
|
+
3. **Check for a prior removal.** Search for commits that removed the same behavior before — if it was removed and later restored, the restoration commit is the strongest defense on record, and your proposal must answer it specifically.
|
|
33
|
+
4. **Issue a per-recommendation verdict.** Every prescription ships in one of two states:
|
|
34
|
+
- **Defended by \<commit/comment/test\>** — the behavior has a recorded reason. Adapt the proposal so that reason keeps holding (gate instead of delete, preserve the invariant, keep the escape hatch), and say what the defense was.
|
|
35
|
+
- **No defense found** — you searched and no commit, comment, or test justifies it. That absence is itself a finding: state it, and proceed.
|
|
36
|
+
|
|
37
|
+
The verdict is the enforcement mechanism — it cannot be filled in without doing the audit.
|
|
38
|
+
|
|
39
|
+
## What this rule forbids
|
|
40
|
+
|
|
41
|
+
- Presenting the removal or weakening of existing behavior as safe without a verdict.
|
|
42
|
+
- Auditing by subject line only.
|
|
43
|
+
- Treating redundant-looking behavior as accidental by default. In a codebase with disciplined commit messages, *defended* is the norm; genuine accidents are the exception, and the audit is how you tell them apart.
|
|
44
|
+
|
|
45
|
+
## The compounding loop
|
|
46
|
+
|
|
47
|
+
This rule only works in a repository whose commit messages record the **why** — which the commit-discipline rules already mandate. The two form a loop: writing down why a behavior exists makes the future audit a five-minute read instead of an archaeology project, and the audit is what makes writing it down pay off. When your own change survives an audit and ships, document its why with the same care — the next agent's audit depends on it.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "History Audit — Before Removing or Changing Existing Behavior (load-bearing)"
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# History Audit — Before Removing or Changing Existing Behavior (load-bearing)
|
|
7
|
+
|
|
8
|
+
When a proposed change would **remove, gate, skip, consolidate, weaken, or relax existing behavior** — and the motivation is your own assessment that the code looks redundant, wasteful, slow, or wrong (rather than a ticket, bug report, or spec) — audit the history **before presenting the change as safe or implementing it**.
|
|
9
|
+
|
|
10
|
+
## How to apply
|
|
11
|
+
|
|
12
|
+
1. `git log --follow` the affected files and `git log --grep` for related keywords.
|
|
13
|
+
2. Read **full commit bodies** (never just subjects), code comments, and covering tests — the defense usually lives there, often naming the exact incident the behavior prevents.
|
|
14
|
+
3. Deliver every such recommendation with an explicit verdict:
|
|
15
|
+
- **Defended by \<commit/comment/test\>** — adapt the proposal to preserve that reason.
|
|
16
|
+
- **No defense found** — genuinely accidental; safe to change, and say so.
|
|
17
|
+
|
|
18
|
+
## Scope
|
|
19
|
+
|
|
20
|
+
- **Diagnosis doesn't need the audit; prescriptions do.** Analyzing what is slow or broken is free; recommending that existing behavior stop happening is what triggers the audit. If presenting unaudited ideas, label them as such.
|
|
21
|
+
- Changes driven by an external requirement may cite that requirement as their defense and move on.
|
|
22
|
+
- "Nothing was deleted" is not an exemption — a change that weakens a guarantee (e.g. adding a cache/stamp that skips a self-healing pass) alters existing behavior and needs the same audit.
|
|
23
|
+
|
|
24
|
+
## Forbidden
|
|
25
|
+
|
|
26
|
+
- Recommending removal or weakening of existing behavior as "safe" without the verdict.
|
|
27
|
+
- Auditing subjects only (`--oneline` skims miss the evidence).
|
|
28
|
+
- Treating redundant-looking behavior as accidental by default — defended is the norm, not the exception.
|
|
29
|
+
|
|
30
|
+
This rule compounds with commit discipline: documenting the **why** in commit bodies is what makes future audits cheap.
|
|
31
|
+
|
|
32
|
+
Full prose: [reference/history-audit.md](history-audit-reference.mdc).
|
|
@@ -114,6 +114,27 @@ AWS_CLI_PUBLIC_KEY
|
|
|
114
114
|
trap - EXIT
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
remove_profile_setting() {
|
|
118
|
+
local credentials_file profile setting temporary_file
|
|
119
|
+
credentials_file="$1"
|
|
120
|
+
profile="$2"
|
|
121
|
+
setting="$3"
|
|
122
|
+
[ -f "$credentials_file" ] || return 0
|
|
123
|
+
|
|
124
|
+
temporary_file="$(mktemp "${credentials_file}.XXXXXX")"
|
|
125
|
+
awk -v profile="$profile" -v setting="$setting" '
|
|
126
|
+
/^\[[^]]+\][[:space:]]*$/ {
|
|
127
|
+
section = $0
|
|
128
|
+
sub(/^\[/, "", section)
|
|
129
|
+
sub(/\][[:space:]]*$/, "", section)
|
|
130
|
+
in_profile = section == profile
|
|
131
|
+
}
|
|
132
|
+
!(in_profile && $0 ~ "^[[:space:]]*" setting "[[:space:]]*=") { print }
|
|
133
|
+
' "$credentials_file" >"$temporary_file"
|
|
134
|
+
chmod 600 "$temporary_file"
|
|
135
|
+
mv "$temporary_file" "$credentials_file"
|
|
136
|
+
}
|
|
137
|
+
|
|
117
138
|
sanitize_session_name() {
|
|
118
139
|
local candidate
|
|
119
140
|
candidate="$(printf '%s' "${LISA_REMOTE_AGENT:-remote-agent}" \
|
|
@@ -154,22 +175,30 @@ profiles_json="$(printf '%s' "$bootstrap_json" | jq -c '
|
|
|
154
175
|
end
|
|
155
176
|
')"
|
|
156
177
|
|
|
157
|
-
printf '%s' "$profiles_json" | jq -e '
|
|
178
|
+
printf '%s' "$profiles_json" | jq -e --arg bootstrap_profile "$BOOTSTRAP_PROFILE" '
|
|
158
179
|
type == "object" and length > 0 and
|
|
159
180
|
all(to_entries[];
|
|
181
|
+
(.key != $bootstrap_profile) and
|
|
160
182
|
(.key | test("^[A-Za-z0-9_-]+$")) and
|
|
161
183
|
(.value.roleArn | type == "string" and startswith("arn:aws:iam::")) and
|
|
162
184
|
(.value.region | type == "string" and length > 0)
|
|
163
185
|
)
|
|
164
186
|
' >/dev/null || fail "bootstrap profiles must map safe names to roleArn and region"
|
|
165
187
|
|
|
166
|
-
|
|
188
|
+
credentials_file="${AWS_SHARED_CREDENTIALS_FILE:-$HOME/.aws/credentials}"
|
|
189
|
+
config_file="${AWS_CONFIG_FILE:-$HOME/.aws/config}"
|
|
190
|
+
mkdir -p "$HOME/.aws" "$(dirname "$credentials_file")" "$(dirname "$config_file")"
|
|
167
191
|
chmod 700 "$HOME/.aws"
|
|
168
192
|
|
|
169
193
|
aws configure set aws_access_key_id "$access_key_id" --profile "$BOOTSTRAP_PROFILE"
|
|
170
194
|
aws configure set aws_secret_access_key "$secret_access_key" --profile "$BOOTSTRAP_PROFILE"
|
|
171
195
|
if [ -n "$session_token" ]; then
|
|
172
196
|
aws configure set aws_session_token "$session_token" --profile "$BOOTSTRAP_PROFILE"
|
|
197
|
+
else
|
|
198
|
+
remove_profile_setting \
|
|
199
|
+
"$credentials_file" \
|
|
200
|
+
"$BOOTSTRAP_PROFILE" \
|
|
201
|
+
"aws_session_token"
|
|
173
202
|
fi
|
|
174
203
|
|
|
175
204
|
session_name="$(sanitize_session_name)"
|
|
@@ -194,7 +223,7 @@ aws configure set external_id "$external_id" --profile default
|
|
|
194
223
|
aws configure set role_session_name "$session_name" --profile default
|
|
195
224
|
aws configure set region "$default_region" --profile default
|
|
196
225
|
|
|
197
|
-
chmod 600 "$
|
|
226
|
+
chmod 600 "$credentials_file" "$config_file"
|
|
198
227
|
|
|
199
228
|
if [ "${LISA_AWS_SKIP_VERIFY:-0}" != "1" ]; then
|
|
200
229
|
AWS_PAGER="" aws sts get-caller-identity --profile "$default_profile" >/dev/null
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.227.0",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.227.0",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, across Claude and Codex.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.227.0",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.227.0",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.227.0",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# History Audit — Before Removing or Changing Existing Behavior (load-bearing)
|
|
2
|
+
|
|
3
|
+
When a proposed change would **remove, gate, skip, consolidate, weaken, or relax existing behavior** — and the motivation is your own assessment that the code looks redundant, wasteful, slow, or wrong (rather than a ticket, bug report, or spec) — audit the history **before presenting the change as safe or implementing it**.
|
|
4
|
+
|
|
5
|
+
## How to apply
|
|
6
|
+
|
|
7
|
+
1. `git log --follow` the affected files and `git log --grep` for related keywords.
|
|
8
|
+
2. Read **full commit bodies** (never just subjects), code comments, and covering tests — the defense usually lives there, often naming the exact incident the behavior prevents.
|
|
9
|
+
3. Deliver every such recommendation with an explicit verdict:
|
|
10
|
+
- **Defended by \<commit/comment/test\>** — adapt the proposal to preserve that reason.
|
|
11
|
+
- **No defense found** — genuinely accidental; safe to change, and say so.
|
|
12
|
+
|
|
13
|
+
## Scope
|
|
14
|
+
|
|
15
|
+
- **Diagnosis doesn't need the audit; prescriptions do.** Analyzing what is slow or broken is free; recommending that existing behavior stop happening is what triggers the audit. If presenting unaudited ideas, label them as such.
|
|
16
|
+
- Changes driven by an external requirement may cite that requirement as their defense and move on.
|
|
17
|
+
- "Nothing was deleted" is not an exemption — a change that weakens a guarantee (e.g. adding a cache/stamp that skips a self-healing pass) alters existing behavior and needs the same audit.
|
|
18
|
+
|
|
19
|
+
## Forbidden
|
|
20
|
+
|
|
21
|
+
- Recommending removal or weakening of existing behavior as "safe" without the verdict.
|
|
22
|
+
- Auditing subjects only (`--oneline` skims miss the evidence).
|
|
23
|
+
- Treating redundant-looking behavior as accidental by default — defended is the norm, not the exception.
|
|
24
|
+
|
|
25
|
+
This rule compounds with commit discipline: documenting the **why** in commit bodies is what makes future audits cheap.
|
|
26
|
+
|
|
27
|
+
Full prose: [reference/history-audit.md](../reference/history-audit.md).
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# History Audit — Before Removing or Changing Existing Behavior
|
|
2
|
+
|
|
3
|
+
When a proposed change would remove, gate, skip, consolidate, weaken, or relax existing behavior — and the motivation is your own assessment that the code looks redundant, wasteful, slow, or wrong, rather than a ticket, bug report, or spec — **audit the history before presenting the change as safe or implementing it**. This is Chesterton's fence made operational: the fence's reason is usually written down; go read it.
|
|
4
|
+
|
|
5
|
+
This is the historical counterpart to the `empirical-inquiry` rule: `empirical-inquiry` establishes facts about how the system behaves *now* by probing it; this rule establishes *why the system behaves that way* by reading the record. Both reject confident-sounding reasoning as a substitute for evidence.
|
|
6
|
+
|
|
7
|
+
## Why this rule exists
|
|
8
|
+
|
|
9
|
+
Optimization and cleanup recommendations fail in a characteristic way: the code genuinely *is* doing redundant-looking work, the diagnosis is correct, and the proposed fix would still ship a regression — because the redundancy is load-bearing and its reason lives in a commit body, a code comment, or a test the recommender never read. In a real Lisa incident, a performance audit of the postinstall pipeline produced five recommendations; the history audit walked back two of them (a "redundant" apply pass existed to fix a bootstrap chicken-and-egg; a "wasteful" detached re-run existed because the package manager clobbers `package.json` after lifecycle scripts finish) and confirmed the rest were genuinely accidental. Without the audit, the confident-sounding fixes would have re-shipped bugs that earlier commits had explicitly fixed.
|
|
10
|
+
|
|
11
|
+
## When this rule applies
|
|
12
|
+
|
|
13
|
+
- A recommendation proposes that existing behavior stop happening: deleting a code path, gating an unconditional step, deduplicating repeated work, relaxing a guard or retry, skipping a pass "when nothing changed."
|
|
14
|
+
- The motivation is internal — the code *looks* redundant, wasteful, slow, dead, or overcautious — rather than an external requirement.
|
|
15
|
+
- **Nothing needs to be deleted to trigger it.** A change that weakens a guarantee alters existing behavior just as much: adding a cache or version-stamp that skips a self-healing pass, narrowing a matcher, batching what was deliberately serialized.
|
|
16
|
+
|
|
17
|
+
## When it does not apply
|
|
18
|
+
|
|
19
|
+
- **Diagnosis is free.** Measuring, profiling, and explaining what is slow or broken needs no audit. The audit gates *prescriptions* — the moment an observation is about to become "so we should remove/skip/gate X."
|
|
20
|
+
- **Requirement-driven changes may cite the requirement.** Implementing a ticket, fixing a reproduced bug, or following a spec supplies external evidence; cite it as the defense and move on. Normal verification discipline covers those.
|
|
21
|
+
- **Spitballing is fine when labeled.** Presenting early ideas before the audit is acceptable if they are explicitly marked as not yet history-audited. What is forbidden is presenting them as safe.
|
|
22
|
+
|
|
23
|
+
## How to apply it
|
|
24
|
+
|
|
25
|
+
1. **Trace the artifact history.** `git log --follow` on each affected file; `git log --grep` for related keywords (feature names, flag names, error strings). Find the commits that introduced and last modified the behavior.
|
|
26
|
+
2. **Read the full commit bodies.** Subjects rarely carry the defense; bodies do — often naming the exact incident, the affected projects, and the failure mode the behavior prevents. `--oneline` skims are how the evidence gets missed. Extend the same reading to code comments around the behavior and to tests whose names encode a philosophy (a test called `*-guard` or `*-preserves-*` is a defense).
|
|
27
|
+
3. **Check for a prior removal.** Search for commits that removed the same behavior before — if it was removed and later restored, the restoration commit is the strongest defense on record, and your proposal must answer it specifically.
|
|
28
|
+
4. **Issue a per-recommendation verdict.** Every prescription ships in one of two states:
|
|
29
|
+
- **Defended by \<commit/comment/test\>** — the behavior has a recorded reason. Adapt the proposal so that reason keeps holding (gate instead of delete, preserve the invariant, keep the escape hatch), and say what the defense was.
|
|
30
|
+
- **No defense found** — you searched and no commit, comment, or test justifies it. That absence is itself a finding: state it, and proceed.
|
|
31
|
+
|
|
32
|
+
The verdict is the enforcement mechanism — it cannot be filled in without doing the audit.
|
|
33
|
+
|
|
34
|
+
## What this rule forbids
|
|
35
|
+
|
|
36
|
+
- Presenting the removal or weakening of existing behavior as safe without a verdict.
|
|
37
|
+
- Auditing by subject line only.
|
|
38
|
+
- Treating redundant-looking behavior as accidental by default. In a codebase with disciplined commit messages, *defended* is the norm; genuine accidents are the exception, and the audit is how you tell them apart.
|
|
39
|
+
|
|
40
|
+
## The compounding loop
|
|
41
|
+
|
|
42
|
+
This rule only works in a repository whose commit messages record the **why** — which the commit-discipline rules already mandate. The two form a loop: writing down why a behavior exists makes the future audit a five-minute read instead of an archaeology project, and the audit is what makes writing it down pay off. When your own change survives an audit and ships, document its why with the same care — the next agent's audit depends on it.
|
|
@@ -114,6 +114,27 @@ AWS_CLI_PUBLIC_KEY
|
|
|
114
114
|
trap - EXIT
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
remove_profile_setting() {
|
|
118
|
+
local credentials_file profile setting temporary_file
|
|
119
|
+
credentials_file="$1"
|
|
120
|
+
profile="$2"
|
|
121
|
+
setting="$3"
|
|
122
|
+
[ -f "$credentials_file" ] || return 0
|
|
123
|
+
|
|
124
|
+
temporary_file="$(mktemp "${credentials_file}.XXXXXX")"
|
|
125
|
+
awk -v profile="$profile" -v setting="$setting" '
|
|
126
|
+
/^\[[^]]+\][[:space:]]*$/ {
|
|
127
|
+
section = $0
|
|
128
|
+
sub(/^\[/, "", section)
|
|
129
|
+
sub(/\][[:space:]]*$/, "", section)
|
|
130
|
+
in_profile = section == profile
|
|
131
|
+
}
|
|
132
|
+
!(in_profile && $0 ~ "^[[:space:]]*" setting "[[:space:]]*=") { print }
|
|
133
|
+
' "$credentials_file" >"$temporary_file"
|
|
134
|
+
chmod 600 "$temporary_file"
|
|
135
|
+
mv "$temporary_file" "$credentials_file"
|
|
136
|
+
}
|
|
137
|
+
|
|
117
138
|
sanitize_session_name() {
|
|
118
139
|
local candidate
|
|
119
140
|
candidate="$(printf '%s' "${LISA_REMOTE_AGENT:-remote-agent}" \
|
|
@@ -154,22 +175,30 @@ profiles_json="$(printf '%s' "$bootstrap_json" | jq -c '
|
|
|
154
175
|
end
|
|
155
176
|
')"
|
|
156
177
|
|
|
157
|
-
printf '%s' "$profiles_json" | jq -e '
|
|
178
|
+
printf '%s' "$profiles_json" | jq -e --arg bootstrap_profile "$BOOTSTRAP_PROFILE" '
|
|
158
179
|
type == "object" and length > 0 and
|
|
159
180
|
all(to_entries[];
|
|
181
|
+
(.key != $bootstrap_profile) and
|
|
160
182
|
(.key | test("^[A-Za-z0-9_-]+$")) and
|
|
161
183
|
(.value.roleArn | type == "string" and startswith("arn:aws:iam::")) and
|
|
162
184
|
(.value.region | type == "string" and length > 0)
|
|
163
185
|
)
|
|
164
186
|
' >/dev/null || fail "bootstrap profiles must map safe names to roleArn and region"
|
|
165
187
|
|
|
166
|
-
|
|
188
|
+
credentials_file="${AWS_SHARED_CREDENTIALS_FILE:-$HOME/.aws/credentials}"
|
|
189
|
+
config_file="${AWS_CONFIG_FILE:-$HOME/.aws/config}"
|
|
190
|
+
mkdir -p "$HOME/.aws" "$(dirname "$credentials_file")" "$(dirname "$config_file")"
|
|
167
191
|
chmod 700 "$HOME/.aws"
|
|
168
192
|
|
|
169
193
|
aws configure set aws_access_key_id "$access_key_id" --profile "$BOOTSTRAP_PROFILE"
|
|
170
194
|
aws configure set aws_secret_access_key "$secret_access_key" --profile "$BOOTSTRAP_PROFILE"
|
|
171
195
|
if [ -n "$session_token" ]; then
|
|
172
196
|
aws configure set aws_session_token "$session_token" --profile "$BOOTSTRAP_PROFILE"
|
|
197
|
+
else
|
|
198
|
+
remove_profile_setting \
|
|
199
|
+
"$credentials_file" \
|
|
200
|
+
"$BOOTSTRAP_PROFILE" \
|
|
201
|
+
"aws_session_token"
|
|
173
202
|
fi
|
|
174
203
|
|
|
175
204
|
session_name="$(sanitize_session_name)"
|
|
@@ -194,7 +223,7 @@ aws configure set external_id "$external_id" --profile default
|
|
|
194
223
|
aws configure set role_session_name "$session_name" --profile default
|
|
195
224
|
aws configure set region "$default_region" --profile default
|
|
196
225
|
|
|
197
|
-
chmod 600 "$
|
|
226
|
+
chmod 600 "$credentials_file" "$config_file"
|
|
198
227
|
|
|
199
228
|
if [ "${LISA_AWS_SKIP_VERIFY:-0}" != "1" ]; then
|
|
200
229
|
AWS_PAGER="" aws sts get-caller-identity --profile "$default_profile" >/dev/null
|