Skip to content

Commit bba26b2

Browse files
committed
Merge branch 'main' of github.com:tninja/ai-code-interface.el
2 parents 327db45 + adb438b commit bba26b2

6 files changed

Lines changed: 602 additions & 17 deletions

ai-code-agent-shell.el

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
(declare-function agent-shell "agent-shell" (&optional arg))
1616
(declare-function agent-shell--shell-buffer "agent-shell" (&key viewport-buffer no-error no-create))
17-
(declare-function agent-shell-queue-request "agent-shell" (prompt))
17+
(declare-function agent-shell-prompt-queue "agent-shell" (prompt))
1818

1919
(defvar agent-shell-session-strategy)
2020

@@ -27,7 +27,7 @@
2727
"Ensure `agent-shell' can be used."
2828
(unless (require 'agent-shell nil t)
2929
(user-error "Agent-shell backend is not available; please install agent-shell"))
30-
(dolist (fn '(agent-shell agent-shell--shell-buffer agent-shell-queue-request))
30+
(dolist (fn '(agent-shell agent-shell--shell-buffer agent-shell-prompt-queue))
3131
(unless (fboundp fn)
3232
(user-error "Agent-shell backend missing required function: %s" fn))))
3333

@@ -62,7 +62,7 @@ When FORCE-PROMPT is non-nil, prompt to choose a shell."
6262
(let ((buffer (agent-shell--shell-buffer :no-create t :no-error t)))
6363
(if buffer
6464
(with-current-buffer buffer
65-
(agent-shell-queue-request line))
65+
(agent-shell-prompt-queue line))
6666
(user-error "No agent-shell session for this project"))))
6767

6868
;;;###autoload

ai-code-harness.el

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -177,18 +177,20 @@ When INLINE is non-nil, use the inline-formatted diagnostics instruction."
177177
(_ (ai-code--auto-test-inline-suffix-for-type type))))
178178

179179
(defun ai-code--ensure-auto-test-harness-file (type)
180-
"Write and return the package prompt file path for auto test TYPE."
181-
(when-let ((content (ai-code--auto-test-harness-text-for-type type)))
182-
(let* ((directory (ai-code--ensure-auto-test-harness-prompt-directory))
183-
(file-path (expand-file-name
184-
(ai-code--auto-test-harness-file-name type)
185-
directory)))
186-
(unless (file-exists-p file-path)
180+
"Return the package prompt file for TYPE, generating it when needed."
181+
(let* ((directory (ai-code--auto-test-harness-directory))
182+
(file-path (expand-file-name
183+
(ai-code--auto-test-harness-file-name type)
184+
directory)))
185+
(if (file-exists-p file-path)
186+
file-path
187+
(when-let ((content (ai-code--auto-test-harness-text-for-type type)))
188+
(ai-code--ensure-auto-test-harness-prompt-directory)
187189
(with-temp-file file-path
188190
(insert content)
189191
(unless (bolp)
190-
(insert "\n"))))
191-
file-path)))
192+
(insert "\n")))
193+
file-path))))
192194

193195
(defun ai-code--auto-test-harness-reference-suffix (type)
194196
"Return a short suffix that references the package prompt file for TYPE.
@@ -208,7 +210,8 @@ If the harness file cannot be prepared, fall back to the inline suffix."
208210
(defun ai-code--auto-test-suffix-for-type (type)
209211
"Return prompt suffix for auto test TYPE."
210212
(pcase type
211-
((or 'test-after-change 'tdd 'tdd-with-refactoring)
213+
((or 'test-after-change 'tdd 'tdd-with-refactoring
214+
'uncle-bob-coding-agent-harness)
212215
(ai-code--auto-test-harness-reference-suffix type))
213216
('no-test "Do not write or run any test.")
214217
(_ nil)))
@@ -331,7 +334,8 @@ See the later `defcustom' for user-facing documentation and default.")
331334
'(("Run tests after code change" . test-after-change)
332335
("Do not write or run tests" . no-test)
333336
("TDD Red + Green (write failing test, then make it pass)" . tdd)
334-
("TDD Red + Green + Blue (refactor after Green)" . tdd-with-refactoring))
337+
("TDD Red + Green + Blue (refactor after Green)" . tdd-with-refactoring)
338+
("Uncle Bob's coding agent harness" . uncle-bob-coding-agent-harness))
335339
"Resolve auto test suffix choices for `ask-me` mode.")
336340

337341
(defconst ai-code--auto-test-type-persistent-choices
@@ -437,7 +441,6 @@ Use simple string matching first, then fall back to GPTel."
437441
(defun ai-code--gptel-classify-prompt-code-change (prompt-text)
438442
"Classify whether PROMPT-TEXT requests a code change using GPTel.
439443
Return one of: `code-change`, `non-code-change`, or `unknown`."
440-
;; TODO DONE: Make prompt code-change classification more strict.
441444
(let ((classification
442445
(condition-case err
443446
(if (require 'gptel nil t)
Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
# Uncle Bob's Coding Agent Harness
2+
3+
Use evidence-first development: surround the implementation with an executable
4+
specification and a gauntlet of constraints so confidence comes from auditable
5+
evidence instead of line-by-line review.
6+
7+
The trust model has two primary artifacts: an executable specification approved
8+
before implementation, and an evidence report produced after real verification.
9+
The gauntlet proves only the constraints expressed by the specification, so be
10+
explicit about assumptions, invariants, skipped checks, and remaining risk.
11+
12+
## Diagnostics-first constraint
13+
14+
Before editing, record a diagnostics baseline by calling the
15+
`diagnostics_baseline` MCP tool. After each edit, call the `get_diagnostics` MCP
16+
tool with `since="baseline"` for every touched file. Do not finish until its
17+
status is `clean`, meaning no new diagnostics versus the baseline.
18+
19+
## Required loop
20+
21+
SPEC → (human approves spec, not code) → RED → GREEN → REFACTOR → GAUNTLET → EVIDENCE
22+
23+
Repeat RED through REFACTOR for each behavior. Never weaken the gauntlet to make
24+
the implementation appear successful.
25+
26+
### 1. SPEC
27+
28+
Before changing implementation files, turn the request into executable
29+
acceptance criteria:
30+
31+
- Describe concrete inputs, outputs, edge cases, and error cases as Gherkin
32+
scenarios or a named test list.
33+
- Include negative constraints: existing behavior, public APIs, data integrity,
34+
performance budgets, and anything else that must not change.
35+
- Include the setup plan: tools to install, files to add, git/checkpoint usage,
36+
and every new dependency with a one-line justification.
37+
- Show the specification to the human and obtain approval before implementation.
38+
In autonomous mode, proceed only if allowed, and record that approval was not
39+
obtained so the final confidence claim is correspondingly weaker.
40+
- Treat the specification as append-only. If it is wrong, revise it visibly and
41+
explain why; never let implementation silently redefine it.
42+
43+
### 2. RED
44+
45+
Write the smallest test for one approved behavior and run it before changing the
46+
implementation. Observe the expected assertion failure. A collection or import
47+
failure is weaker evidence; create a minimal stub when needed so the failure is
48+
about behavior. If the new test already passes, use a temporary mutant to prove
49+
the test can fail, restore the source, and record the behavior as pre-existing.
50+
51+
### 3. GREEN
52+
53+
Write the least implementation needed to pass the failing test, then run the
54+
full suite. Do not refactor or expand the feature during Green.
55+
56+
### 4. REFACTOR
57+
58+
With the suite green, improve naming, cohesion, duplication, and control flow
59+
without changing behavior. Implementation refactors must not edit tests.
60+
Test-structure refactors are a separate step: keep assertions unchanged, run
61+
the suite before and after, and rerun mutation checks. Any assertion change is a
62+
behavior change and returns to SPEC.
63+
64+
### 5. GAUNTLET
65+
66+
Run every applicable constraint layer. Scale the effort using Calibration, but
67+
never skip a layer silently.
68+
69+
| Layer | Constraint |
70+
|---|---|
71+
| Full test suite | Zero new failures; record any pre-existing baseline failures verbatim. |
72+
| Static types | Zero new compiler or type-checker errors. |
73+
| Lint and format | Zero new warnings or formatting drift. |
74+
| Changed-line coverage | Every changed behavior-bearing line and branch is exercised; do not chase a global percentage. |
75+
| Mutation testing | Use a mutation tool or 3-5 scripted manual mutants; every non-equivalent mutant must be killed. |
76+
| Property tests | Add invariant-based tests for parsing, math, serialization, ordering, or round trips when applicable. |
77+
| Complexity budget | Keep new functions small, cohesive, and easy to explain. |
78+
| Real execution | Run the application, CLI, or endpoint once with realistic input. |
79+
| Supply chain and secrets | Audit dependency changes, licenses, secrets, and newly introduced capabilities. |
80+
| Suite health | Check determinism, randomized order where supported, and suspected flakes. |
81+
82+
Mutation kills validate the suite as a whole unless a layer is run separately.
83+
Classify tool-generated equivalent mutants honestly. Hand-written mutants must
84+
represent real bugs and receive no equivalent-mutant exemption.
85+
86+
### 6. EVIDENCE
87+
88+
Finish with a reproducible report containing:
89+
90+
- The approved specification and a scenario-to-test mapping.
91+
- Every gauntlet command and its actual numeric result from one fresh run after
92+
the final edit.
93+
- A single persisted entry-point command that reruns every applicable layer,
94+
with tool versions pinned or recorded.
95+
- The source state, using a commit SHA or a reproducible tree hash.
96+
- Every skipped layer and the reason.
97+
- Failures encountered and how they were resolved.
98+
- Remaining risks and limits, without claiming absolute proof.
99+
100+
## Anti-gaming rules
101+
102+
1. Never weaken, skip, broaden, or delete a test to make it pass.
103+
2. Never edit a test and its implementation in the same step on the path to
104+
Green. Change one, run it, then change the other.
105+
3. Never mock the unit under test. Mock only true boundaries such as network,
106+
clock, filesystem, or process execution.
107+
4. Never add vacuous tests merely to raise coverage.
108+
5. Never report a layer that was not run.
109+
6. A failing applicable gauntlet layer blocks completion. If blocked, report the
110+
exact failure instead of weakening the constraint.
111+
112+
## Calibration
113+
114+
- Tier 1, trivial: full suite plus lint. Explain why a new test is unnecessary
115+
or why existing coverage is sufficient.
116+
- Tier 2, normal feature or bug fix: the full SPEC, RED, GREEN, REFACTOR,
117+
GAUNTLET, EVIDENCE loop. Bug fixes start with a regression test.
118+
- Tier 3, high stakes: first write a failure model for risks such as money,
119+
authentication, data loss, concurrency, migrations, public API compatibility,
120+
unbounded growth, or silent production failure. Add targeted stress, fuzz,
121+
rollback, contract, observability, compatibility, or benchmark layers. Also
122+
require property tests, mutation testing, and an adversarial pass.
123+
124+
## Setup rules
125+
126+
Prefer the repository's current tools. If essential tooling is missing, put its
127+
installation and every environment change in the approved SPEC. Prefer standard
128+
libraries and existing dependencies. Do not initialize git, install packages, or
129+
create checkpoint commits without authorization. If tooling is declined or
130+
unavailable, use the best manual layer and record the reduced confidence.
131+
132+
# Gauntlet Tooling by Ecosystem
133+
134+
Use project-native commands when they exist. The following are defaults only.
135+
136+
## Python
137+
138+
| Layer | Default |
139+
|---|---|
140+
| Tests | `pytest -q` |
141+
| Types | `mypy <pkg>` or pyright |
142+
| Lint and format | `ruff check .` and `ruff format --check .` |
143+
| Coverage | pytest-cov with branch coverage; use diff-cover when configured |
144+
| Mutation | mutmut scoped to changed modules |
145+
| Property tests | hypothesis |
146+
147+
## JavaScript and TypeScript
148+
149+
| Layer | Default |
150+
|---|---|
151+
| Tests | `npx vitest run` or `npx jest` |
152+
| Types | `npx tsc --noEmit` |
153+
| Lint | `npx eslint .` |
154+
| Coverage | Vitest or Jest coverage, checked against changed lines |
155+
| Mutation | Stryker scoped to changed files |
156+
| Property tests | fast-check |
157+
158+
## Java
159+
160+
| Layer | Default |
161+
|---|---|
162+
| Tests | `mvn test` or `./gradlew test` |
163+
| Types and build | `mvn -DskipTests compile` or `./gradlew classes` |
164+
| Lint and static analysis | Checkstyle, SpotBugs, or Error Prone, as configured |
165+
| Coverage | JaCoCo with changed-line and branch coverage review |
166+
| Mutation | PIT scoped to changed packages or classes |
167+
| Property tests | jqwik or QuickTheories |
168+
169+
## Go
170+
171+
| Layer | Default |
172+
|---|---|
173+
| Tests | `go test ./... -race` |
174+
| Types and build | `go build ./...` |
175+
| Lint | `go vet ./...` and staticcheck |
176+
| Coverage | `go test -coverprofile=c.out ./...` then `go tool cover -func=c.out` |
177+
| Mutation | scripted manual mutation |
178+
| Property tests | testing/quick or rapid |
179+
180+
## Rust
181+
182+
| Layer | Default |
183+
|---|---|
184+
| Tests | `cargo test` |
185+
| Types | `cargo check` |
186+
| Lint | `cargo clippy -- -D warnings` |
187+
| Coverage | cargo-llvm-cov with branch coverage |
188+
| Mutation | cargo-mutants scoped to changed files |
189+
| Property tests | proptest |
190+
191+
## Emacs Lisp
192+
193+
| Layer | Default |
194+
|---|---|
195+
| Tests | ERT through the project's batch test command |
196+
| Byte compilation | `emacs -Q --batch -L . -f batch-byte-compile *.el`; allow no new warnings |
197+
| Lint and documentation | checkdoc and package-lint, as configured |
198+
| Coverage | Undercover when configured; otherwise verify changed behavior with focused ERT and mutation |
199+
| Mutation | Scripted manual mutation scoped to changed forms |
200+
| Property tests | Deterministic generated ERT cases or the project's property library |
201+
202+
## Extended layer menu
203+
204+
Select additional layers from the failure model:
205+
206+
- Dependency and license audit whenever dependencies change.
207+
- Secret scan and a manual capability diff for new network, subprocess,
208+
filesystem, or environment access.
209+
- Randomized test order and repeated runs for suite-health concerns.
210+
- API compatibility checks when a public API changes.
211+
- Race detectors and stress tests for concurrency.
212+
- Benchmarks only when the SPEC states a measurable performance budget.
213+
- Accessibility, screenshot, and browser checks for user-facing UI.
214+
- Version-matrix checks when the project claims multiple supported versions.
215+
- Log or metric assertions when silent production failure is a risk.
216+
217+
## Manual mutation procedure
218+
219+
When no mutation tool is available, persist a repository script that saves the
220+
original source, applies one plausible bug at a time, runs the relevant suite,
221+
and restores the source. Use 3-5 mutants such as a flipped comparison, off-by-one
222+
bound, removed branch, swapped boolean operator, or constant return. Every mutant
223+
must fail at least one test. Verify restoration with the final diff and suite,
224+
then report `manual mutation: N/N killed`.
225+
226+
## Reproducible gauntlet entry point
227+
228+
Persist one command that removes stale artifacts, runs every applicable layer in
229+
sequence, and fails on the first broken layer. Pin or record development-tool
230+
versions. The final evidence numbers must come from one fresh execution of this
231+
entry point after the last edit.
232+
233+
## Executable specification template
234+
235+
```gherkin
236+
Feature: <capability in user language>
237+
Scenario: <one concrete behavior>
238+
Given <concrete starting state>
239+
When <concrete action with concrete input>
240+
Then <concrete observable outcome>
241+
242+
Scenario: <error or invariant case>
243+
Given <concrete starting state>
244+
When <invalid, hostile, or boundary input>
245+
Then <exact error and state that must not change>
246+
```
247+
248+
## Evidence report template
249+
250+
```markdown
251+
## Evidence Report — <task name> (Tier <1|2|3>)
252+
253+
- Spec approval: <obtained | not obtained, confidence downgraded>
254+
- Source state: <commit SHA | reproducible tree hash>
255+
- Toolchain: <versions file or recorded versions>
256+
- Entry point: <one command that reruns the gauntlet>
257+
258+
### Spec to test mapping
259+
| Scenario or invariant | Test or layer | Status |
260+
|---|---|---|
261+
| <behavior> | <test name> | pass, fail, unverified, or n-a |
262+
263+
### Fresh gauntlet results
264+
| Layer | Command | Numeric result |
265+
|---|---|---|
266+
| Tests | <command> | <passed and failed counts> |
267+
| Types | <command> | <error count> |
268+
| Lint | <command> | <warning count> |
269+
| Changed-line coverage | <command> | <covered/total> |
270+
| Mutation | <command> | <killed/total> |
271+
| Real execution | <command> | <observed result> |
272+
273+
### Skipped layers and honest notes
274+
- <layer>: <reason>
275+
- <failures, fixes, and remaining risks>
276+
```

0 commit comments

Comments
 (0)