-
Notifications
You must be signed in to change notification settings - Fork 3
feat(plan): enrich a brief on first read, and open it by naming the role #92
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -185,3 +185,39 @@ func TestBriefWithoutPackIsPlanOnly(t *testing.T) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| t.Errorf("brief should still carry the feat's objective:\n%s", out) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // TestBriefOpensByNamingTheRole pins the first four lines. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // The brief IS the prompt — it is fed to `claude -p` on stdin with nothing in front | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // of it — so whatever it opens with is where the session's role is established. It | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // used to open on a feat row, leaving the model to infer what it was supposed to be | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // from a table of objectives. The preamble is deliberately short: it names the role | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // and the shape of what follows, and stops. Process belongs to the plan-session | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // CLAUDE.md and the `plan-dev` skill (see TestBriefCarriesNoProcess), so a preamble | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // that starts explaining the cycle is this boundary eroding again. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func TestBriefOpensByNamingTheRole(t *testing.T) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| out := briefFor(t, setupWorkspace(t, "p", briefPlan), "p", "upload") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if !strings.HasPrefix(out, "You are a senior software engineer.") { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| t.Errorf("the brief must open by naming the role it is written for:\n%s", firstLines(out, 6)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // The role sits BEFORE the feat header — everything after it reads as material | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // for that role rather than as a document that happened to arrive. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| role, feat := strings.Index(out, "You are a senior software engineer"), strings.Index(out, "# Feat:") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if feat < 0 || role > feat { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| t.Errorf("the role must come before the feat header:\n%s", firstLines(out, 8)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Four lines, then the mission. A preamble long enough to need a heading has | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // stopped being a preamble. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if head, _, _ := strings.Cut(out, "# Feat:"); strings.Count(head, "\n") > 6 { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| t.Errorf("the role preamble should stay short, got:\n%s", head) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+200
to
+212
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Pin the complete four-line preamble. The test fixes only the first sentence and permits extra lines; changes to the remaining role/mission text would still pass. Assert the exact preamble, including its blank separator before Proposed test tightening- if !strings.HasPrefix(out, "You are a senior software engineer.") {
+ const preamble = "You are a senior software engineer. You deliver ONE feat of an approved plan to\n" +
+ "completion on your own, in an autonomous session with no human at the gate.\n" +
+ "Everything below is the mission: what this feat is, what governs it, where it\n" +
+ "lives in this repository, and what verifies it.\n\n"
+ if !strings.HasPrefix(out, preamble) {
t.Errorf("the brief must open by naming the role it is written for:\n%s", firstLines(out, 6))
}
@@
- if head, _, _ := strings.Cut(out, "# Feat:"); strings.Count(head, "\n") > 6 {
- t.Errorf("the role preamble should stay short, got:\n%s", head)
- }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // firstLines returns at most n lines of s, for readable failure output. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func firstLines(s string, n int) string { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lines := strings.Split(s, "\n") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if len(lines) > n { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lines = lines[:n] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return strings.Join(lines, "\n") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Reconcile the ADR-body documentation.
This update says briefs carry governing refs, but README line 292 still says cited ADRs are inlined in full.
FeatBriefemits onlyadr:<slug>references and directs the session tocsdd graph explain; update that earlier sentence in this section.🤖 Prompt for AI Agents