mirror of
https://github.com/glittercowboy/get-shit-done
synced 2026-04-25 17:25:23 +02:00
Before framework-specific research, phase-researcher now maps each capability to its architectural tier owner (browser, frontend server, API, database, CDN). The planner sanity-checks task assignments against this map, and plan-checker enforces tier compliance as Dimension 7c. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -276,6 +276,12 @@ Priority: Context7 > Exa (verified) > Firecrawl (official docs) > Official GitHu
|
|||||||
|
|
||||||
**Primary recommendation:** [one-liner actionable guidance]
|
**Primary recommendation:** [one-liner actionable guidance]
|
||||||
|
|
||||||
|
## Architectural Responsibility Map
|
||||||
|
|
||||||
|
| Capability | Primary Tier | Secondary Tier | Rationale |
|
||||||
|
|------------|-------------|----------------|-----------|
|
||||||
|
| [capability] | [tier] | [tier or —] | [why this tier owns it] |
|
||||||
|
|
||||||
## Standard Stack
|
## Standard Stack
|
||||||
|
|
||||||
### Core
|
### Core
|
||||||
@@ -520,6 +526,33 @@ cat "$phase_dir"/*-CONTEXT.md 2>/dev/null
|
|||||||
- User decided "simple UI, no animations" → don't research animation libraries
|
- User decided "simple UI, no animations" → don't research animation libraries
|
||||||
- Marked as Claude's discretion → research options and recommend
|
- Marked as Claude's discretion → research options and recommend
|
||||||
|
|
||||||
|
## Step 1.5: Architectural Responsibility Mapping
|
||||||
|
|
||||||
|
Before diving into framework-specific research, map each capability in this phase to its standard architectural tier owner. This is a pure reasoning step — no tool calls needed.
|
||||||
|
|
||||||
|
**For each capability in the phase description:**
|
||||||
|
|
||||||
|
1. Identify what the capability does (e.g., "user authentication", "data visualization", "file upload")
|
||||||
|
2. Determine which architectural tier owns the primary responsibility:
|
||||||
|
|
||||||
|
| Tier | Examples |
|
||||||
|
|------|----------|
|
||||||
|
| **Browser / Client** | DOM manipulation, client-side routing, local storage, service workers |
|
||||||
|
| **Frontend Server (SSR)** | Server-side rendering, hydration, middleware, auth cookies |
|
||||||
|
| **API / Backend** | REST/GraphQL endpoints, business logic, auth, data validation |
|
||||||
|
| **CDN / Static** | Static assets, edge caching, image optimization |
|
||||||
|
| **Database / Storage** | Persistence, queries, migrations, caching layers |
|
||||||
|
|
||||||
|
3. Record the mapping in a table:
|
||||||
|
|
||||||
|
| Capability | Primary Tier | Secondary Tier | Rationale |
|
||||||
|
|------------|-------------|----------------|-----------|
|
||||||
|
| [capability] | [tier] | [tier or —] | [why this tier owns it] |
|
||||||
|
|
||||||
|
**Output:** Include an `## Architectural Responsibility Map` section in RESEARCH.md immediately after the Summary section. This map is consumed by the planner for sanity-checking task assignments and by the plan-checker for verifying tier correctness.
|
||||||
|
|
||||||
|
**Why this matters:** Multi-tier applications frequently have capabilities misassigned during planning — e.g., putting auth logic in the browser tier when it belongs in the API tier, or putting data fetching in the frontend server when the API already provides it. Mapping tier ownership before research prevents these misassignments from propagating into plans.
|
||||||
|
|
||||||
## Step 2: Identify Research Domains
|
## Step 2: Identify Research Domains
|
||||||
|
|
||||||
Based on phase description, identify what needs investigating:
|
Based on phase description, identify what needs investigating:
|
||||||
|
|||||||
@@ -369,6 +369,54 @@ Plans reduce {N} user decisions. Options:
|
|||||||
2. Split phase: [suggested grouping of D-XX into sub-phases]
|
2. Split phase: [suggested grouping of D-XX into sub-phases]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Dimension 7c: Architectural Tier Compliance
|
||||||
|
|
||||||
|
**Question:** Do plan tasks assign capabilities to the correct architectural tier as defined in the Architectural Responsibility Map?
|
||||||
|
|
||||||
|
**Skip if:** No RESEARCH.md exists for this phase, or RESEARCH.md has no `## Architectural Responsibility Map` section. Output: "Dimension 7c: SKIPPED (no responsibility map found)"
|
||||||
|
|
||||||
|
**Process:**
|
||||||
|
1. Read the phase's RESEARCH.md and extract the `## Architectural Responsibility Map` table
|
||||||
|
2. For each plan task, identify which capability it implements and which tier it targets (inferred from file paths, action description, and artifacts)
|
||||||
|
3. Cross-reference against the responsibility map — does the task place work in the tier that owns the capability?
|
||||||
|
4. Flag any tier mismatch where a task assigns logic to a tier that doesn't own the capability
|
||||||
|
|
||||||
|
**Red flags:**
|
||||||
|
- Auth validation logic placed in browser/client tier when responsibility map assigns it to API tier
|
||||||
|
- Data persistence logic in frontend server when it belongs in database tier
|
||||||
|
- Business rule enforcement in CDN/static tier when it belongs in API tier
|
||||||
|
- Server-side rendering logic assigned to API tier when frontend server owns it
|
||||||
|
|
||||||
|
**Severity:** WARNING for potential tier mismatches. BLOCKER if a security-sensitive capability (auth, access control, input validation) is assigned to a less-trusted tier than the responsibility map specifies.
|
||||||
|
|
||||||
|
**Example — tier mismatch:**
|
||||||
|
```yaml
|
||||||
|
issue:
|
||||||
|
dimension: architectural_tier_compliance
|
||||||
|
severity: blocker
|
||||||
|
description: "Task places auth token validation in browser tier, but Architectural Responsibility Map assigns auth to API tier"
|
||||||
|
plan: "01"
|
||||||
|
task: 2
|
||||||
|
capability: "Authentication token validation"
|
||||||
|
expected_tier: "API / Backend"
|
||||||
|
actual_tier: "Browser / Client"
|
||||||
|
fix_hint: "Move token validation to API route handler per Architectural Responsibility Map"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example — non-security mismatch (warning):**
|
||||||
|
```yaml
|
||||||
|
issue:
|
||||||
|
dimension: architectural_tier_compliance
|
||||||
|
severity: warning
|
||||||
|
description: "Task places data formatting in API tier, but Architectural Responsibility Map assigns it to Frontend Server"
|
||||||
|
plan: "02"
|
||||||
|
task: 1
|
||||||
|
capability: "Date/currency formatting for display"
|
||||||
|
expected_tier: "Frontend Server (SSR)"
|
||||||
|
actual_tier: "API / Backend"
|
||||||
|
fix_hint: "Consider moving display formatting to frontend server per Architectural Responsibility Map"
|
||||||
|
```
|
||||||
|
|
||||||
## Dimension 8: Nyquist Compliance
|
## Dimension 8: Nyquist Compliance
|
||||||
|
|
||||||
Skip if: `workflow.nyquist_validation` is explicitly set to `false` in config.json (absent key = enabled), phase has no RESEARCH.md, or RESEARCH.md has no "Validation Architecture" section. Output: "Dimension 8: SKIPPED (nyquist_validation disabled or not applicable)"
|
Skip if: `workflow.nyquist_validation` is explicitly set to `false` in config.json (absent key = enabled), phase has no RESEARCH.md, or RESEARCH.md has no "Validation Architecture" section. Output: "Dimension 8: SKIPPED (nyquist_validation disabled or not applicable)"
|
||||||
@@ -859,6 +907,7 @@ Plan verification complete when:
|
|||||||
- [ ] No tasks contradict locked decisions
|
- [ ] No tasks contradict locked decisions
|
||||||
- [ ] Deferred ideas not included in plans
|
- [ ] Deferred ideas not included in plans
|
||||||
- [ ] Overall status determined (passed | issues_found)
|
- [ ] Overall status determined (passed | issues_found)
|
||||||
|
- [ ] Architectural tier compliance checked (tasks match responsibility map tiers)
|
||||||
- [ ] Cross-plan data contracts checked (no conflicting transforms on shared data)
|
- [ ] Cross-plan data contracts checked (no conflicting transforms on shared data)
|
||||||
- [ ] CLAUDE.md compliance checked (plans respect project conventions)
|
- [ ] CLAUDE.md compliance checked (plans respect project conventions)
|
||||||
- [ ] Structured issues returned (if any found)
|
- [ ] Structured issues returned (if any found)
|
||||||
|
|||||||
@@ -1026,6 +1026,8 @@ cat "$phase_dir"/*-DISCOVERY.md 2>/dev/null # From mandatory discovery
|
|||||||
**If CONTEXT.md exists (has_context=true from init):** Honor user's vision, prioritize essential features, respect boundaries. Locked decisions — do not revisit.
|
**If CONTEXT.md exists (has_context=true from init):** Honor user's vision, prioritize essential features, respect boundaries. Locked decisions — do not revisit.
|
||||||
|
|
||||||
**If RESEARCH.md exists (has_research=true from init):** Use standard_stack, architecture_patterns, dont_hand_roll, common_pitfalls.
|
**If RESEARCH.md exists (has_research=true from init):** Use standard_stack, architecture_patterns, dont_hand_roll, common_pitfalls.
|
||||||
|
|
||||||
|
**Architectural Responsibility Map sanity check:** If RESEARCH.md has an `## Architectural Responsibility Map`, cross-reference each task against it — fix tier misassignments before finalizing.
|
||||||
</step>
|
</step>
|
||||||
|
|
||||||
<step name="break_into_tasks">
|
<step name="break_into_tasks">
|
||||||
|
|||||||
@@ -38,6 +38,18 @@ Template for `.planning/phases/XX-name/{phase_num}-RESEARCH.md` - comprehensive
|
|||||||
**If no CONTEXT.md exists:** Write "No user constraints - all decisions at Claude's discretion"
|
**If no CONTEXT.md exists:** Write "No user constraints - all decisions at Claude's discretion"
|
||||||
</user_constraints>
|
</user_constraints>
|
||||||
|
|
||||||
|
<architectural_responsibility_map>
|
||||||
|
## Architectural Responsibility Map
|
||||||
|
|
||||||
|
Map each phase capability to its standard architectural tier owner before diving into framework research. This prevents tier misassignment from propagating into plans.
|
||||||
|
|
||||||
|
| Capability | Primary Tier | Secondary Tier | Rationale |
|
||||||
|
|------------|-------------|----------------|-----------|
|
||||||
|
| [capability from phase description] | [Browser/Client, Frontend Server, API/Backend, CDN/Static, or Database/Storage] | [secondary tier or —] | [why this tier owns it] |
|
||||||
|
|
||||||
|
**If single-tier application:** Write "Single-tier application — all capabilities reside in [tier]" and omit the table.
|
||||||
|
</architectural_responsibility_map>
|
||||||
|
|
||||||
<research_summary>
|
<research_summary>
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
|
|||||||
177
tests/phase-researcher-app-aware.test.cjs
Normal file
177
tests/phase-researcher-app-aware.test.cjs
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
/**
|
||||||
|
* Phase Researcher Application-Aware Tests (#1988)
|
||||||
|
*
|
||||||
|
* Validates that gsd-phase-researcher maps capabilities to architectural
|
||||||
|
* tiers before diving into framework-specific research. Also validates
|
||||||
|
* that gsd-planner and gsd-plan-checker consume the Architectural
|
||||||
|
* Responsibility Map downstream.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const { test, describe } = require('node:test');
|
||||||
|
const assert = require('node:assert/strict');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const AGENTS_DIR = path.join(__dirname, '..', 'agents');
|
||||||
|
const TEMPLATES_DIR = path.join(__dirname, '..', 'get-shit-done', 'templates');
|
||||||
|
|
||||||
|
// ─── Phase Researcher: Architectural Responsibility Mapping ─────────────────
|
||||||
|
|
||||||
|
describe('phase-researcher: Architectural Responsibility Mapping', () => {
|
||||||
|
const researcherPath = path.join(AGENTS_DIR, 'gsd-phase-researcher.md');
|
||||||
|
const content = fs.readFileSync(researcherPath, 'utf-8');
|
||||||
|
|
||||||
|
test('contains Architectural Responsibility Mapping step', () => {
|
||||||
|
assert.ok(
|
||||||
|
content.includes('Architectural Responsibility Map'),
|
||||||
|
'gsd-phase-researcher.md must contain "Architectural Responsibility Map"'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Architectural Responsibility Mapping step comes after Step 1 and before Step 2', () => {
|
||||||
|
const step1Pos = content.indexOf('## Step 1:');
|
||||||
|
// Look for the step heading specifically (not the output format section)
|
||||||
|
const stepARMPos = content.indexOf('## Step 1.5:');
|
||||||
|
const step2Pos = content.indexOf('## Step 2:');
|
||||||
|
|
||||||
|
assert.ok(step1Pos !== -1, 'Step 1 must exist');
|
||||||
|
assert.ok(stepARMPos !== -1, 'Step 1.5 Architectural Responsibility Mapping step must exist');
|
||||||
|
assert.ok(step2Pos !== -1, 'Step 2 must exist');
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
stepARMPos > step1Pos,
|
||||||
|
'Step 1.5 (Architectural Responsibility Mapping) must come after Step 1'
|
||||||
|
);
|
||||||
|
assert.ok(
|
||||||
|
stepARMPos < step2Pos,
|
||||||
|
'Step 1.5 (Architectural Responsibility Mapping) must come before Step 2'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('step is a pure reasoning step with no tool calls', () => {
|
||||||
|
// Extract the ARM section content (between the ARM heading and the next ## Step heading)
|
||||||
|
const armHeadingMatch = content.match(/## Step 1\.5[^\n]*Architectural Responsibility Map/);
|
||||||
|
assert.ok(armHeadingMatch, 'Must have a Step 1.5 heading for Architectural Responsibility Mapping');
|
||||||
|
|
||||||
|
const armStart = content.indexOf(armHeadingMatch[0]);
|
||||||
|
const nextStepMatch = content.indexOf('## Step 2:', armStart);
|
||||||
|
const armSection = content.substring(armStart, nextStepMatch);
|
||||||
|
|
||||||
|
// Should not contain tool invocation patterns
|
||||||
|
const toolPatterns = [
|
||||||
|
/```bash/,
|
||||||
|
/node "\$HOME/,
|
||||||
|
/gsd-tools\.cjs/,
|
||||||
|
/WebSearch/,
|
||||||
|
/Context7/,
|
||||||
|
/mcp__/,
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const pattern of toolPatterns) {
|
||||||
|
assert.ok(
|
||||||
|
!pattern.test(armSection),
|
||||||
|
`Architectural Responsibility Mapping step must be pure reasoning (no tool calls), but found: ${pattern}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('mentions standard architectural tiers', () => {
|
||||||
|
const armStart = content.indexOf('Architectural Responsibility Map');
|
||||||
|
const nextStep = content.indexOf('## Step 2:', armStart);
|
||||||
|
const armSection = content.substring(armStart, nextStep);
|
||||||
|
|
||||||
|
// Should reference standard tiers
|
||||||
|
const tiers = ['browser', 'frontend', 'API', 'database'];
|
||||||
|
const foundTiers = tiers.filter(tier =>
|
||||||
|
armSection.toLowerCase().includes(tier.toLowerCase())
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
foundTiers.length >= 3,
|
||||||
|
`Must mention at least 3 standard architectural tiers, found: ${foundTiers.join(', ')}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('specifies output format as a table in RESEARCH.md', () => {
|
||||||
|
const armStart = content.indexOf('Architectural Responsibility Map');
|
||||||
|
const nextStep = content.indexOf('## Step 2:', armStart);
|
||||||
|
const armSection = content.substring(armStart, nextStep);
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
armSection.includes('|') && armSection.includes('Capability'),
|
||||||
|
'ARM step must specify a table output format with Capability column'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ─── Planner: Architectural Responsibility Map Sanity Check ─────────────────
|
||||||
|
|
||||||
|
describe('planner: Architectural Responsibility Map sanity check', () => {
|
||||||
|
const plannerPath = path.join(AGENTS_DIR, 'gsd-planner.md');
|
||||||
|
const content = fs.readFileSync(plannerPath, 'utf-8');
|
||||||
|
|
||||||
|
test('references Architectural Responsibility Map', () => {
|
||||||
|
assert.ok(
|
||||||
|
content.includes('Architectural Responsibility Map'),
|
||||||
|
'gsd-planner.md must reference the Architectural Responsibility Map'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('includes sanity check against the map', () => {
|
||||||
|
// Must mention checking/verifying plan tasks against the responsibility map
|
||||||
|
assert.ok(
|
||||||
|
content.includes('sanity check') || content.includes('sanity-check'),
|
||||||
|
'gsd-planner.md must include a sanity check against the Architectural Responsibility Map'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ─── Plan Checker: Architectural Tier Verification Dimension ────────────────
|
||||||
|
|
||||||
|
describe('plan-checker: Architectural Tier verification dimension', () => {
|
||||||
|
const checkerPath = path.join(AGENTS_DIR, 'gsd-plan-checker.md');
|
||||||
|
const content = fs.readFileSync(checkerPath, 'utf-8');
|
||||||
|
|
||||||
|
test('has verification dimension for architectural tier', () => {
|
||||||
|
assert.ok(
|
||||||
|
content.includes('Architectural Responsibility Map') ||
|
||||||
|
content.includes('Architectural Tier'),
|
||||||
|
'gsd-plan-checker.md must have a verification dimension for architectural tier mapping'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('verification dimension checks plans against the map', () => {
|
||||||
|
// Should have a dimension that references tier/responsibility checking
|
||||||
|
assert.ok(
|
||||||
|
content.includes('tier owner') || content.includes('tier mismatch') || content.includes('responsibility map'),
|
||||||
|
'plan-checker verification dimension must check for tier mismatches against the responsibility map'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ─── Research Template: Architectural Responsibility Map Section ─────────────
|
||||||
|
|
||||||
|
describe('research template: Architectural Responsibility Map section', () => {
|
||||||
|
const templatePath = path.join(TEMPLATES_DIR, 'research.md');
|
||||||
|
const content = fs.readFileSync(templatePath, 'utf-8');
|
||||||
|
|
||||||
|
test('mentions Architectural Responsibility Map section', () => {
|
||||||
|
assert.ok(
|
||||||
|
content.includes('Architectural Responsibility Map'),
|
||||||
|
'Research template must include an Architectural Responsibility Map section'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('template includes tier table format', () => {
|
||||||
|
const armStart = content.indexOf('Architectural Responsibility Map');
|
||||||
|
assert.ok(armStart !== -1, 'ARM section must exist');
|
||||||
|
|
||||||
|
const sectionEnd = content.indexOf('##', armStart + 10);
|
||||||
|
const section = content.substring(armStart, sectionEnd !== -1 ? sectionEnd : armStart + 500);
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
section.includes('|') && (section.includes('Tier') || section.includes('tier')),
|
||||||
|
'Research template ARM section must include a table format with Tier column'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user