Skip to content

Commit d66794b

Browse files
tigclaude
andauthored
Fixes stale/contradictory AI agent instructions; adds agent docs lint and tuirec verification guidance (#5478)
* Fix inconsistencies in AI agent instruction files - Local function naming: camelCase -> PascalCase in REFRESH.md and copilot-instructions.md (matches .editorconfig local_functions_rule, AGENTS.md, and event-patterns.md) - Replace stale Tests/UnitTests references with current project names (UnitTestsParallelizable / UnitTests.NonParallelizable) across AGENTS.md, CONTRIBUTING.md, .aider.md, .cursorrules, .windsurfrules, copilot-instructions.md, and .claude workflows/tasks - Replace deprecated --filter "FullyQualifiedName~" syntax with xUnit v3 MTP --filter-method/--filter-class in copilot-instructions.md - Remove machine-local path (D:\s\...) from AGENTS.md planning section - build-app.md: use Accepted (post-event) for fire-and-forget handlers per event-patterns.md; show Accepting only for cancellation; fix v1-style new Button ("OK") to v2 object initializer - build-test-workflow.md: .NET SDK 8.0 -> 10.0.100 per global.json Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Add agent docs lint, tuirec verification guidance, promote local memories - Add Scripts/lint-agent-docs.ps1 + lint-agent-docs.yml CI workflow: fails when known rot patterns reappear in agent instruction files (stale test project names, machine-local paths, camelCase local-function guidance, deprecated FullyQualifiedName~ filter syntax, SDK version drift vs global.json). The lint immediately caught a stale .NET SDK 8.0 claim in CONTRIBUTING.md, now fixed. - Wire tuirec into agent entry points (CLAUDE.md, AGENTS.md, build-app.md): agents can verify TUI behavior by recording with tuirec and reading the asciinema .cast output back as text, per Scripts/tuirec/README.md. - Promote durable guidance from machine-specific .claude/projects/ memory files into shared rules (.claude/rules/logging-tracing.md and fragile-areas.md); untrack .claude/projects/ and gitignore it (the directory name encoded a local user path). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Document Windows ConPTY sixel limitation in tuirec README Discovered while verifying the About Box fire animation: ConPTY strips sixel DCS and the DA1 sixel handshake, so sixel content cannot be captured in tuirec recordings on Windows (apps detect Sixel support: False). Added to the troubleshooting table and validation checklist so the next agent does not burn recordings rediscovering it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * tuirec README: require measuring grid-anchored sixels, not eyeballing Agents (including me) recurrently verify the wrong invariant when checking sixel recordings: confirming the sixel appears, or that agg rendered it faithfully at the requested cursor cell, and calling it done. That misses size/position errors — notably the ~4% undersize from tuirec advertising a cell resolution that does not match agg's rendered font cell (tuirec #84). Adds a "Verifying Placement and Size (measure - don't eyeball)" section with the cell-calibration recipe (measure agg's real cell from a known grid reference; reconcile against the resolution the app used; confirm the rendered bbox covers the target region), a checklist item, a troubleshooting row for #84, and rewrites the workflow's "visual confirm" step to require measurement for grid-anchored content. Also states the general principle: verify the invariant the change was meant to satisfy, not a proxy. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Sync CONTRIBUTING.md TFM to net10.0; lint stale TFMs Codex review on #5478 flagged that build-test-workflow.md cites CONTRIBUTING.md as its source of truth, but CONTRIBUTING.md still described the project as net8.0 (line 28) even though the Required Tools section was updated to .NET 10 — so the declared source could revert the fix and mislead readers onto the wrong toolchain. Test-first: added Rule 6 to lint-agent-docs.ps1 that derives the expected target-framework moniker from global.json's SDK major and fails on any mismatched `net<major>.0` reference. It flagged CONTRIBUTING.md:28 (net8.0); fixed that to `C# 14 (net10.0)`. Lint now passes (32 files). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent 2a12625 commit d66794b

20 files changed

Lines changed: 393 additions & 80 deletions

.aider.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Terminal.Gui v2 is a **complete rewrite**. Pre-2025 training data about Terminal
3434
dotnet restore
3535
dotnet build --no-restore
3636
dotnet test --project Tests/UnitTestsParallelizable --no-build
37-
dotnet test --project Tests/UnitTests --no-build
37+
dotnet test --project Tests/UnitTests.NonParallelizable --no-build
3838
```
3939

4040
---

.claude/REFRESH.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
3. **Use `[...]`** not `new () { ... }` for collections
1010
4. **SubView/SuperView** - never say "child", "parent", or "container"
1111
5. **Unused lambda params** - use `_` discard: `(_, _) => { }`
12-
6. **Local functions** - use camelCase: `void myLocalFunc ()`
12+
6. **Local functions** - use PascalCase: `void MyLocalFunc ()`
1313
7. **Backing fields** - place immediately before their property (ReSharper bug, must do manually)
1414
8. **SPACE BEFORE PARENTHESES** - `Method ()` not `Method()`, `array [i]` not `array[i]` (see `formatting.md`)
1515
9. **Braces on next line** - ALL opening braces on next line (Allman style)

.claude/projects/C--Users-Tig-s-gui-cs-Terminal-Gui/memory/feedback_no_console_writeline.md

Lines changed: 0 additions & 32 deletions
This file was deleted.

.claude/projects/C--Users-Tig-s-gui-cs-Terminal-Gui/memory/feedback_textview_fragile.md

Lines changed: 0 additions & 11 deletions
This file was deleted.

.claude/rules/fragile-areas.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Known Fragile Areas
2+
3+
Areas of the codebase where seemingly-safe refactors cause cascading failures. Do not "fix" these in passing — file a separate issue instead.
4+
5+
## TextView Initialization Ordering
6+
7+
Do not change `TextView`'s `EndInit` ordering or initialization flow. Moving `base.EndInit ()` before `UpdateContentSize ()`/`UpdateScrollBars ()` fixes some tests but breaks others in the non-parallel test project.
8+
9+
**Why:** `TextView` has complex initialization dependencies, and the non-parallel tests rely on specific ordering.
10+
11+
**How to apply:** If `TextView` ContentSize tests fail, note the root cause (`UpdateContentSize` runs before `IsInitialized` is set) but do NOT fix it by reordering `EndInit`. File a separate issue or let a maintainer decide when to address it.

.claude/rules/logging-tracing.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Logging and Tracing
2+
3+
**Never use `Console.WriteLine` or `Console.Error.WriteLine` for debug output.** Console output interferes with the terminal UI framework. Use the project's logging infrastructure instead:
4+
5+
| Need | Use |
6+
|------|-----|
7+
| Library logging | `Terminal.Gui.App.Logging` |
8+
| Test output | `Terminal.Gui.Tests.TestLogging` |
9+
| Debug tracing | `Terminal.Gui.Tracing.Trace` |
10+
11+
## Test Pattern
12+
13+
```csharp
14+
using Terminal.Gui.Tests;
15+
using Terminal.Gui.Tracing;
16+
17+
[Fact]
18+
public void MyTest ()
19+
{
20+
// Enable logging and tracing in one call
21+
using (TestLogging.Verbose (_output, TraceCategory.Command))
22+
{
23+
// Logs and traces appear in xUnit test output
24+
CheckBox checkbox = new () { Id = "test" };
25+
checkbox.InvokeCommand (Command.Activate);
26+
}
27+
}
28+
```
29+
30+
## Rules
31+
32+
- `Tracing.Trace` is only available in DEBUG builds; do not use it to validate test results — all tests must pass in RELEASE builds.
33+
- Remove temporary debug tracing before committing.
34+
35+
See `docfx/docs/logging.md` for full details.

.claude/tasks/build-app.md

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,9 @@ public sealed class MainWindow : Runnable
6161

6262
// Add controls here
6363
Button button = new () { Text = "Click Me", X = Pos.Center (), Y = Pos.Center () };
64-
button.Accepting += (_, e) =>
64+
button.Accepted += (_, _) =>
6565
{
6666
MessageBox.Query (App!, "Hello", "Button clicked!", "OK");
67-
e.Handled = true;
6867
};
6968

7069
Add (button);
@@ -80,11 +79,10 @@ public sealed class LoginWindow : Runnable<string?>
8079
{
8180
// ... setup UI ...
8281
83-
loginButton.Accepting += (_, e) =>
82+
loginButton.Accepted += (_, _) =>
8483
{
8584
Result = usernameField.Text; // Set return value
8685
App!.RequestStop (); // Close window
87-
e.Handled = true;
8886
};
8987
}
9088
}
@@ -150,10 +148,19 @@ See `.claude/cookbook/common-patterns.md` for recipes including:
150148

151149
### Button Click
152150
```csharp
153-
button.Accepting += (sender, e) =>
151+
// Simple side-effect handler — use Accepted (post-event)
152+
button.Accepted += (_, _) =>
154153
{
155154
// Handle the click
156-
e.Handled = true; // Prevent further processing
155+
};
156+
157+
// Use Accepting (pre-event) ONLY to inspect or cancel the in-flight action
158+
button.Accepting += (_, e) =>
159+
{
160+
if (!CanProceed ())
161+
{
162+
e.Handled = true; // Cancel — prevents Accepted from firing
163+
}
157164
};
158165
```
159166

@@ -200,7 +207,7 @@ Dialog dialog = new ()
200207
Title = "Custom Dialog",
201208
Width = 40,
202209
Height = 10,
203-
Buttons = [new Button ("OK"), new Button ("Cancel")]
210+
Buttons = [new Button { Text = "OK" }, new Button { Text = "Cancel" }]
204211
};
205212
// Add controls to dialog...
206213
app.Run (dialog);
@@ -235,18 +242,44 @@ ConfigurationManager.Enable (ConfigLocations.All);
235242

236243
Available themes: `Default`, `Dark`, `Light`, `Amber Phosphor`, `Green Phosphor`, `Blue Phosphor`
237244

245+
## Verify Your App Actually Works (Give Yourself Eyes)
246+
247+
You cannot see a TUI from a build log. Before declaring an app done, **run it and observe it** with [`tuirec`](https://github.com/gui-cs/tuirec) — it spawns the app in a PTY, injects keystrokes, and records the terminal output:
248+
249+
```powershell
250+
dotnet build -c Release
251+
$ks = 'wait:1000,Tab,Enter,wait:800,Escape'
252+
253+
tuirec record `
254+
--binary dotnet `
255+
--args "./bin/Release/net10.0/MyApp.dll" `
256+
--name MyApp `
257+
--keystrokes $ks `
258+
--startup-delay 2000 --drain 1500 `
259+
--cols 120 --rows 30
260+
```
261+
262+
Then **verify the output yourself**:
263+
264+
1. **Read `artifacts/MyApp.cast`** — it is asciinema v2 JSON (plain text). Inspect the frames to confirm the UI rendered what you expect (controls visible, focus moved, dialog appeared).
265+
2. Grep the cast for failures: `Select-String -Path artifacts/MyApp.cast -Pattern "error|exception|usage:"`.
266+
3. Check `artifacts/MyApp.gif` exists and is > 100KB (a blank recording is typically < 50KB).
267+
268+
See [Scripts/tuirec/README.md](../../Scripts/tuirec/README.md) for the full keystroke syntax, validation checklist, and troubleshooting table. For in-process assertions (no PTY), use `InputInjector` and `VirtualTimeProvider` — see `docfx/docs/input-injection.md`.
269+
238270
## Checklist for Building Apps
239271

240272
- [ ] Project setup with correct packages
241273
- [ ] Main window class inheriting from `Runnable` or `Runnable<T>`
242274
- [ ] Application lifecycle: Create -> Init -> Run -> Dispose
243275
- [ ] Layout using Pos/Dim (not hardcoded positions)
244-
- [ ] Event handlers with `e.Handled = true` when appropriate
276+
- [ ] `-ed` events (`Accepted`) for side effects; `-ing` events (`Accepting`) only to cancel
245277
- [ ] Proper cleanup with `Dispose` pattern
278+
- [ ] Behavior verified by running the app (tuirec recording or input injection), not just by compiling
246279

247280
## What NOT to Do
248281

249282
- Don't use `Application.Init()` / `Application.Shutdown()` (legacy static API)
250283
- Don't hardcode sizes - use `Dim.Fill()`, `Dim.Auto()`, `Dim.Percent()`
251-
- Don't forget `e.Handled = true` in Accepting handlers
284+
- Don't use `Accepting` for fire-and-forget side effects - use `Accepted`; reserve `Accepting` (with `e.Handled = true`) for canceling
252285
- Don't block the main thread - use `Application.AddTimeout` for async work

.claude/tasks/clean-code-review.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ Run these for each commit:
5151
```bash
5252
dotnet build --no-restore
5353
dotnet test --project Tests/IntegrationTests --no-build
54-
dotnet test --project Tests/UnitTests --no-build
5554
dotnet test --project Tests/UnitTestsParallelizable --no-build
55+
dotnet test --project Tests/UnitTests.NonParallelizable --no-build
5656
```
5757

5858
## Terminal.Gui Specific Requirements

.claude/workflows/build-test-workflow.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
## Required Tools
66

7-
- **.NET SDK**: 8.0.0 (see `global.json`)
8-
- **Runtime**: .NET 8.x (latest GA)
7+
- **.NET SDK**: 10.0.100 (see `global.json`)
8+
- **Runtime**: .NET 10.x (latest GA)
99
- **Optional**: ReSharper/Rider for code formatting (honor `.editorconfig` and `Terminal.sln.DotSettings`)
1010

1111
## Build Commands
@@ -47,7 +47,7 @@ dotnet build --configuration Release --no-restore
4747
**Time:** ~10 min timeout
4848

4949
```bash
50-
dotnet test --project Tests/UnitTests --no-build --verbosity normal
50+
dotnet test --project Tests/UnitTests.NonParallelizable --no-build --verbosity normal
5151
```
5252

5353
- Uses `Application.Init` and static state
@@ -75,7 +75,7 @@ dotnet test --project Tests/IntegrationTests --no-build --verbosity normal
7575
### Run All Tests
7676

7777
```bash
78-
dotnet test --project Tests/UnitTests --no-build --verbosity normal && dotnet test --project Tests/UnitTestsParallelizable --no-build --verbosity normal
78+
dotnet test --project Tests/UnitTestsParallelizable --no-build --verbosity normal && dotnet test --project Tests/UnitTests.NonParallelizable --no-build --verbosity normal
7979
```
8080

8181
## Common Build Issues
@@ -94,7 +94,7 @@ dotnet publish ./Tests/NativeAotSmoke/NativeAotSmoke.csproj --configuration Rele
9494
**For clean builds, always run in this order:**
9595

9696
```bash
97-
dotnet restore && dotnet build --no-restore && dotnet test --project Tests/UnitTests --no-build && dotnet test --project Tests/UnitTestsParallelizable --no-build
97+
dotnet restore && dotnet build --no-restore && dotnet test --project Tests/UnitTestsParallelizable --no-build && dotnet test --project Tests/UnitTests.NonParallelizable --no-build
9898
```
9999

100100
This ensures:

.claude/workflows/pr-workflow.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Before submitting a PR, ensure:
2727

2828
- [ ] **Build passes** locally: `dotnet build --no-restore`
2929

30-
- [ ] **Tests pass** locally: `dotnet test --project Tests/UnitTests --no-build && dotnet test --project Tests/UnitTestsParallelizable --no-build`
30+
- [ ] **Tests pass** locally: `dotnet test --project Tests/UnitTestsParallelizable --no-build && dotnet test --project Tests/UnitTests.NonParallelizable --no-build`
3131

3232
## PR Description Template
3333

@@ -70,7 +70,7 @@ dotnet build --configuration Debug --no-restore
7070
### 2. Run Tests
7171

7272
```bash
73-
dotnet test --project Tests/UnitTests --no-build --verbosity normal && dotnet test --project Tests/UnitTestsParallelizable --no-build --verbosity normal
73+
dotnet test --project Tests/UnitTestsParallelizable --no-build --verbosity normal && dotnet test --project Tests/UnitTests.NonParallelizable --no-build --verbosity normal
7474
```
7575

7676
**Expected:** All tests pass
@@ -106,7 +106,7 @@ git diff
106106
- ❌ Don't modify unrelated code
107107
- ❌ Don't remove/edit unrelated tests
108108
- ❌ Don't break existing functionality
109-
- ❌ Don't add tests to `UnitTests` if they can be parallelizable
109+
- ❌ Don't add tests to `UnitTests.NonParallelizable` if they can be parallelizable; never add tests to `UnitTests.Legacy`
110110
- ❌ Don't decrease code coverage
111111
- ❌ Don't introduce new warnings
112112
- ❌ Don't include commented-out code without explanation

0 commit comments

Comments
 (0)