@qball-inc/the-bulwark 1.0.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.
Files changed (175) hide show
  1. package/.claude-plugin/plugin.json +43 -0
  2. package/agents/bulwark-fix-validator.md +633 -0
  3. package/agents/bulwark-implementer.md +391 -0
  4. package/agents/bulwark-issue-analyzer.md +308 -0
  5. package/agents/bulwark-standards-reviewer.md +221 -0
  6. package/agents/plan-creation-architect.md +323 -0
  7. package/agents/plan-creation-eng-lead.md +352 -0
  8. package/agents/plan-creation-po.md +300 -0
  9. package/agents/plan-creation-qa-critic.md +334 -0
  10. package/agents/product-ideation-competitive-analyzer.md +298 -0
  11. package/agents/product-ideation-idea-validator.md +268 -0
  12. package/agents/product-ideation-market-researcher.md +292 -0
  13. package/agents/product-ideation-pattern-documenter.md +308 -0
  14. package/agents/product-ideation-segment-analyzer.md +303 -0
  15. package/agents/product-ideation-strategist.md +259 -0
  16. package/agents/statusline-setup.md +97 -0
  17. package/hooks/hooks.json +59 -0
  18. package/package.json +45 -0
  19. package/scripts/hooks/cleanup-stale.sh +13 -0
  20. package/scripts/hooks/enforce-quality.sh +166 -0
  21. package/scripts/hooks/implementer-quality.sh +256 -0
  22. package/scripts/hooks/inject-protocol.sh +52 -0
  23. package/scripts/hooks/suggest-pipeline.sh +175 -0
  24. package/scripts/hooks/track-pipeline-start.sh +37 -0
  25. package/scripts/hooks/track-pipeline-stop.sh +52 -0
  26. package/scripts/init-rules.sh +35 -0
  27. package/scripts/init.sh +151 -0
  28. package/skills/anthropic-validator/SKILL.md +607 -0
  29. package/skills/anthropic-validator/references/agents-checklist.md +131 -0
  30. package/skills/anthropic-validator/references/commands-checklist.md +102 -0
  31. package/skills/anthropic-validator/references/hooks-checklist.md +151 -0
  32. package/skills/anthropic-validator/references/mcp-checklist.md +136 -0
  33. package/skills/anthropic-validator/references/plugins-checklist.md +148 -0
  34. package/skills/anthropic-validator/references/skills-checklist.md +85 -0
  35. package/skills/assertion-patterns/SKILL.md +296 -0
  36. package/skills/bug-magnet-data/SKILL.md +284 -0
  37. package/skills/bug-magnet-data/context/cli-args.md +91 -0
  38. package/skills/bug-magnet-data/context/db-query.md +104 -0
  39. package/skills/bug-magnet-data/context/file-contents.md +103 -0
  40. package/skills/bug-magnet-data/context/http-body.md +91 -0
  41. package/skills/bug-magnet-data/context/process-spawn.md +123 -0
  42. package/skills/bug-magnet-data/data/booleans/boundaries.yaml +143 -0
  43. package/skills/bug-magnet-data/data/collections/arrays.yaml +114 -0
  44. package/skills/bug-magnet-data/data/collections/objects.yaml +123 -0
  45. package/skills/bug-magnet-data/data/concurrency/race-conditions.yaml +118 -0
  46. package/skills/bug-magnet-data/data/concurrency/state-machines.yaml +115 -0
  47. package/skills/bug-magnet-data/data/dates/boundaries.yaml +137 -0
  48. package/skills/bug-magnet-data/data/dates/invalid.yaml +132 -0
  49. package/skills/bug-magnet-data/data/dates/timezone.yaml +118 -0
  50. package/skills/bug-magnet-data/data/encoding/charset.yaml +79 -0
  51. package/skills/bug-magnet-data/data/encoding/normalization.yaml +105 -0
  52. package/skills/bug-magnet-data/data/formats/email.yaml +154 -0
  53. package/skills/bug-magnet-data/data/formats/json.yaml +187 -0
  54. package/skills/bug-magnet-data/data/formats/url.yaml +165 -0
  55. package/skills/bug-magnet-data/data/language-specific/javascript.yaml +182 -0
  56. package/skills/bug-magnet-data/data/language-specific/python.yaml +174 -0
  57. package/skills/bug-magnet-data/data/language-specific/rust.yaml +148 -0
  58. package/skills/bug-magnet-data/data/numbers/boundaries.yaml +161 -0
  59. package/skills/bug-magnet-data/data/numbers/precision.yaml +89 -0
  60. package/skills/bug-magnet-data/data/numbers/special.yaml +69 -0
  61. package/skills/bug-magnet-data/data/strings/boundaries.yaml +109 -0
  62. package/skills/bug-magnet-data/data/strings/injection.yaml +208 -0
  63. package/skills/bug-magnet-data/data/strings/special-chars.yaml +190 -0
  64. package/skills/bug-magnet-data/data/strings/unicode.yaml +139 -0
  65. package/skills/bug-magnet-data/references/external-lists.md +115 -0
  66. package/skills/bulwark-brainstorm/SKILL.md +563 -0
  67. package/skills/bulwark-brainstorm/references/at-teammate-prompts.md +60 -0
  68. package/skills/bulwark-brainstorm/references/role-critical-analyst.md +78 -0
  69. package/skills/bulwark-brainstorm/references/role-development-lead.md +66 -0
  70. package/skills/bulwark-brainstorm/references/role-product-delivery-lead.md +79 -0
  71. package/skills/bulwark-brainstorm/references/role-product-manager.md +62 -0
  72. package/skills/bulwark-brainstorm/references/role-project-sme.md +59 -0
  73. package/skills/bulwark-brainstorm/references/role-technical-architect.md +66 -0
  74. package/skills/bulwark-research/SKILL.md +298 -0
  75. package/skills/bulwark-research/references/viewpoint-contrarian.md +63 -0
  76. package/skills/bulwark-research/references/viewpoint-direct-investigation.md +62 -0
  77. package/skills/bulwark-research/references/viewpoint-first-principles.md +65 -0
  78. package/skills/bulwark-research/references/viewpoint-practitioner.md +62 -0
  79. package/skills/bulwark-research/references/viewpoint-prior-art.md +66 -0
  80. package/skills/bulwark-scaffold/SKILL.md +330 -0
  81. package/skills/bulwark-statusline/SKILL.md +161 -0
  82. package/skills/bulwark-statusline/scripts/statusline.sh +144 -0
  83. package/skills/bulwark-verify/SKILL.md +519 -0
  84. package/skills/code-review/SKILL.md +428 -0
  85. package/skills/code-review/examples/anti-patterns/linting.ts +181 -0
  86. package/skills/code-review/examples/anti-patterns/security.ts +91 -0
  87. package/skills/code-review/examples/anti-patterns/standards.ts +195 -0
  88. package/skills/code-review/examples/anti-patterns/type-safety.ts +108 -0
  89. package/skills/code-review/examples/recommended/linting.ts +195 -0
  90. package/skills/code-review/examples/recommended/security.ts +154 -0
  91. package/skills/code-review/examples/recommended/standards.ts +231 -0
  92. package/skills/code-review/examples/recommended/type-safety.ts +181 -0
  93. package/skills/code-review/frameworks/angular.md +218 -0
  94. package/skills/code-review/frameworks/django.md +235 -0
  95. package/skills/code-review/frameworks/express.md +207 -0
  96. package/skills/code-review/frameworks/flask.md +298 -0
  97. package/skills/code-review/frameworks/generic.md +146 -0
  98. package/skills/code-review/frameworks/react.md +152 -0
  99. package/skills/code-review/frameworks/vue.md +244 -0
  100. package/skills/code-review/references/linting-patterns.md +221 -0
  101. package/skills/code-review/references/security-patterns.md +125 -0
  102. package/skills/code-review/references/standards-patterns.md +246 -0
  103. package/skills/code-review/references/type-safety-patterns.md +130 -0
  104. package/skills/component-patterns/SKILL.md +131 -0
  105. package/skills/component-patterns/references/pattern-cli-command.md +118 -0
  106. package/skills/component-patterns/references/pattern-database.md +166 -0
  107. package/skills/component-patterns/references/pattern-external-api.md +139 -0
  108. package/skills/component-patterns/references/pattern-file-parser.md +168 -0
  109. package/skills/component-patterns/references/pattern-http-server.md +162 -0
  110. package/skills/component-patterns/references/pattern-process-spawner.md +133 -0
  111. package/skills/continuous-feedback/SKILL.md +327 -0
  112. package/skills/continuous-feedback/references/collect-instructions.md +81 -0
  113. package/skills/continuous-feedback/references/specialize-code-review.md +82 -0
  114. package/skills/continuous-feedback/references/specialize-general.md +98 -0
  115. package/skills/continuous-feedback/references/specialize-test-audit.md +81 -0
  116. package/skills/create-skill/SKILL.md +359 -0
  117. package/skills/create-skill/references/agent-conventions.md +194 -0
  118. package/skills/create-skill/references/agent-template.md +195 -0
  119. package/skills/create-skill/references/content-guidance.md +291 -0
  120. package/skills/create-skill/references/decision-framework.md +124 -0
  121. package/skills/create-skill/references/template-pipeline.md +217 -0
  122. package/skills/create-skill/references/template-reference-heavy.md +111 -0
  123. package/skills/create-skill/references/template-research.md +210 -0
  124. package/skills/create-skill/references/template-script-driven.md +172 -0
  125. package/skills/create-skill/references/template-simple.md +80 -0
  126. package/skills/create-subagent/SKILL.md +353 -0
  127. package/skills/create-subagent/references/agent-conventions.md +268 -0
  128. package/skills/create-subagent/references/content-guidance.md +232 -0
  129. package/skills/create-subagent/references/decision-framework.md +134 -0
  130. package/skills/create-subagent/references/template-single-agent.md +192 -0
  131. package/skills/fix-bug/SKILL.md +241 -0
  132. package/skills/governance-protocol/SKILL.md +116 -0
  133. package/skills/init/SKILL.md +341 -0
  134. package/skills/issue-debugging/SKILL.md +385 -0
  135. package/skills/issue-debugging/references/anti-patterns.md +245 -0
  136. package/skills/issue-debugging/references/debug-report-schema.md +227 -0
  137. package/skills/mock-detection/SKILL.md +511 -0
  138. package/skills/mock-detection/references/false-positive-prevention.md +402 -0
  139. package/skills/mock-detection/references/stub-patterns.md +236 -0
  140. package/skills/pipeline-templates/SKILL.md +215 -0
  141. package/skills/pipeline-templates/references/code-change-workflow.md +277 -0
  142. package/skills/pipeline-templates/references/code-review.md +336 -0
  143. package/skills/pipeline-templates/references/fix-validation.md +421 -0
  144. package/skills/pipeline-templates/references/new-feature.md +335 -0
  145. package/skills/pipeline-templates/references/research-brainstorm.md +161 -0
  146. package/skills/pipeline-templates/references/research-planning.md +257 -0
  147. package/skills/pipeline-templates/references/test-audit.md +389 -0
  148. package/skills/pipeline-templates/references/test-execution-fix.md +238 -0
  149. package/skills/plan-creation/SKILL.md +497 -0
  150. package/skills/product-ideation/SKILL.md +372 -0
  151. package/skills/product-ideation/references/analysis-frameworks.md +161 -0
  152. package/skills/session-handoff/SKILL.md +139 -0
  153. package/skills/session-handoff/references/examples.md +223 -0
  154. package/skills/setup-lsp/SKILL.md +312 -0
  155. package/skills/setup-lsp/references/server-registry.md +85 -0
  156. package/skills/setup-lsp/references/troubleshooting.md +135 -0
  157. package/skills/subagent-output-templating/SKILL.md +415 -0
  158. package/skills/subagent-output-templating/references/examples.md +440 -0
  159. package/skills/subagent-prompting/SKILL.md +364 -0
  160. package/skills/subagent-prompting/references/examples.md +342 -0
  161. package/skills/test-audit/SKILL.md +531 -0
  162. package/skills/test-audit/references/known-limitations.md +41 -0
  163. package/skills/test-audit/references/priority-classification.md +30 -0
  164. package/skills/test-audit/references/prompts/deep-mode-detection.md +83 -0
  165. package/skills/test-audit/references/prompts/synthesis.md +57 -0
  166. package/skills/test-audit/references/rewrite-instructions.md +46 -0
  167. package/skills/test-audit/references/schemas/audit-output.yaml +100 -0
  168. package/skills/test-audit/references/schemas/diagnostic-output.yaml +49 -0
  169. package/skills/test-audit/scripts/data-flow-analyzer.ts +509 -0
  170. package/skills/test-audit/scripts/integration-mock-detector.ts +462 -0
  171. package/skills/test-audit/scripts/package.json +20 -0
  172. package/skills/test-audit/scripts/skip-detector.ts +211 -0
  173. package/skills/test-audit/scripts/verification-counter.ts +295 -0
  174. package/skills/test-classification/SKILL.md +310 -0
  175. package/skills/test-fixture-creation/SKILL.md +295 -0
@@ -0,0 +1,166 @@
1
+ # Pattern 5: Database Verification
2
+
3
+ ## Strategy
4
+
5
+ Setup test database, execute operations, verify state changes, teardown.
6
+
7
+ ---
8
+
9
+ ## Template (Node/Jest)
10
+
11
+ ```javascript
12
+ const { setupTestDb, teardownTestDb } = require('./test-utils');
13
+ const { saveRecord, findRecord, deleteRecord } = require('{component_path}');
14
+
15
+ describe('{component_name} Database Operations', () => {
16
+ let db;
17
+
18
+ beforeAll(async () => {
19
+ db = await setupTestDb();
20
+ });
21
+
22
+ afterAll(async () => {
23
+ await teardownTestDb(db);
24
+ });
25
+
26
+ beforeEach(async () => {
27
+ await db.clear(); // Clean state between tests
28
+ });
29
+
30
+ test('save creates record in database', async () => {
31
+ const data = { id: 1, value: 'test' };
32
+ await saveRecord(db, data);
33
+
34
+ const found = await db.findOne({ id: 1 });
35
+ expect(found).toBeDefined();
36
+ expect(found.value).toBe('test');
37
+ });
38
+
39
+ test('find retrieves existing record', async () => {
40
+ await db.insert({ id: 2, value: 'existing' });
41
+
42
+ const result = await findRecord(db, 2);
43
+ expect(result.value).toBe('existing');
44
+ });
45
+
46
+ test('delete removes record from database', async () => {
47
+ await db.insert({ id: 3, value: 'to-delete' });
48
+
49
+ await deleteRecord(db, 3);
50
+
51
+ const found = await db.findOne({ id: 3 });
52
+ expect(found).toBeNull();
53
+ });
54
+ });
55
+ ```
56
+
57
+ ---
58
+
59
+ ## Template (Python/pytest)
60
+
61
+ ```python
62
+ import pytest
63
+ from {module} import save_record, find_record, delete_record
64
+
65
+ @pytest.fixture
66
+ def test_db():
67
+ db = setup_test_database()
68
+ yield db
69
+ teardown_test_database(db)
70
+
71
+ @pytest.fixture(autouse=True)
72
+ def clean_db(test_db):
73
+ yield
74
+ test_db.clear()
75
+
76
+ def test_save_creates_record(test_db):
77
+ save_record(test_db, {'id': 1, 'value': 'test'})
78
+
79
+ found = test_db.find_one({'id': 1})
80
+ assert found is not None
81
+ assert found['value'] == 'test'
82
+
83
+ def test_find_retrieves_record(test_db):
84
+ test_db.insert({'id': 2, 'value': 'existing'})
85
+
86
+ result = find_record(test_db, 2)
87
+ assert result['value'] == 'existing'
88
+
89
+ def test_delete_removes_record(test_db):
90
+ test_db.insert({'id': 3, 'value': 'to-delete'})
91
+
92
+ delete_record(test_db, 3)
93
+
94
+ found = test_db.find_one({'id': 3})
95
+ assert found is None
96
+ ```
97
+
98
+ ---
99
+
100
+ ## Template (Bash - SQLite)
101
+
102
+ ```bash
103
+ #!/bin/bash
104
+ # Database Verification: {component_name}
105
+ set -e
106
+
107
+ echo "=== Database Verification: {component_name} ==="
108
+
109
+ TEST_DB=$(mktemp --suffix=.db)
110
+
111
+ cleanup() {
112
+ rm -f "$TEST_DB"
113
+ }
114
+ trap cleanup EXIT
115
+
116
+ # Initialize test database
117
+ sqlite3 "$TEST_DB" "CREATE TABLE {table} (id INTEGER PRIMARY KEY, value TEXT);"
118
+
119
+ # Test 1: Insert
120
+ echo -n "Test 1: Insert record... "
121
+ {insert_command} "$TEST_DB"
122
+ COUNT=$(sqlite3 "$TEST_DB" "SELECT COUNT(*) FROM {table};")
123
+ if [ "$COUNT" -gt 0 ]; then
124
+ echo "PASS ($COUNT records)"
125
+ else
126
+ echo "FAIL (no records inserted)"
127
+ exit 1
128
+ fi
129
+
130
+ # Test 2: Query
131
+ echo -n "Test 2: Query record... "
132
+ VALUE=$(sqlite3 "$TEST_DB" "SELECT value FROM {table} WHERE id=1;")
133
+ if [ "$VALUE" = "{expected_value}" ]; then
134
+ echo "PASS"
135
+ else
136
+ echo "FAIL (expected: {expected_value}, got: $VALUE)"
137
+ exit 1
138
+ fi
139
+
140
+ # Test 3: Delete
141
+ echo -n "Test 3: Delete record... "
142
+ {delete_command} "$TEST_DB"
143
+ COUNT=$(sqlite3 "$TEST_DB" "SELECT COUNT(*) FROM {table};")
144
+ if [ "$COUNT" -eq 0 ]; then
145
+ echo "PASS (deleted)"
146
+ else
147
+ echo "FAIL ($COUNT records remain)"
148
+ exit 1
149
+ fi
150
+
151
+ echo "=== All tests passed ==="
152
+ ```
153
+
154
+ ---
155
+
156
+ ## Placeholders
157
+
158
+ | Placeholder | Description |
159
+ |-------------|-------------|
160
+ | `{component_name}` | Name of the database component |
161
+ | `{component_path}` | Import path to the database module |
162
+ | `{module}` | Python module name |
163
+ | `{table}` | Database table name |
164
+ | `{insert_command}` | Command to insert records |
165
+ | `{delete_command}` | Command to delete records |
166
+ | `{expected_value}` | Expected value after operations |
@@ -0,0 +1,139 @@
1
+ # Pattern 6: External API Verification
2
+
3
+ ## Strategy
4
+
5
+ Use MSW (Mock Service Worker) to intercept at network level - not module level.
6
+ This allows real HTTP calls while controlling external responses.
7
+
8
+ ---
9
+
10
+ ## Template (Node/Jest with MSW)
11
+
12
+ ```javascript
13
+ import { setupServer } from 'msw/node';
14
+ import { rest } from 'msw';
15
+ import { fetchUserData, postOrder } from '{component_path}';
16
+
17
+ // Setup MSW server with handlers
18
+ const server = setupServer(
19
+ rest.get('https://api.example.com/users/:id', (req, res, ctx) => {
20
+ return res(ctx.json({
21
+ id: req.params.id,
22
+ name: 'Test User',
23
+ email: 'test@example.com'
24
+ }));
25
+ }),
26
+ rest.post('https://api.example.com/orders', async (req, res, ctx) => {
27
+ const body = await req.json();
28
+ return res(ctx.json({
29
+ orderId: 'ORD-123',
30
+ items: body.items,
31
+ status: 'created'
32
+ }));
33
+ })
34
+ );
35
+
36
+ beforeAll(() => server.listen());
37
+ afterEach(() => server.resetHandlers());
38
+ afterAll(() => server.close());
39
+
40
+ describe('{component_name} External API', () => {
41
+ test('fetches user data from API', async () => {
42
+ // Real fetch call - intercepted by MSW at network level
43
+ const user = await fetchUserData(1);
44
+
45
+ expect(user.name).toBe('Test User');
46
+ expect(user.email).toBe('test@example.com');
47
+ });
48
+
49
+ test('posts order to API', async () => {
50
+ const order = await postOrder({ items: [{ sku: 'ABC', qty: 2 }] });
51
+
52
+ expect(order.orderId).toBe('ORD-123');
53
+ expect(order.status).toBe('created');
54
+ });
55
+
56
+ test('handles API errors gracefully', async () => {
57
+ // Override handler for this test
58
+ server.use(
59
+ rest.get('https://api.example.com/users/:id', (req, res, ctx) => {
60
+ return res(ctx.status(500), ctx.json({ error: 'Server error' }));
61
+ })
62
+ );
63
+
64
+ await expect(fetchUserData(1)).rejects.toThrow('API error');
65
+ });
66
+ });
67
+ ```
68
+
69
+ ---
70
+
71
+ ## Template (Python/pytest with responses)
72
+
73
+ ```python
74
+ import pytest
75
+ import responses
76
+ from {module} import fetch_user_data, post_order
77
+
78
+ @responses.activate
79
+ def test_fetches_user_data():
80
+ responses.add(
81
+ responses.GET,
82
+ 'https://api.example.com/users/1',
83
+ json={'id': 1, 'name': 'Test User', 'email': 'test@example.com'},
84
+ status=200
85
+ )
86
+
87
+ user = fetch_user_data(1)
88
+
89
+ assert user['name'] == 'Test User'
90
+ assert user['email'] == 'test@example.com'
91
+
92
+ @responses.activate
93
+ def test_posts_order():
94
+ responses.add(
95
+ responses.POST,
96
+ 'https://api.example.com/orders',
97
+ json={'orderId': 'ORD-123', 'status': 'created'},
98
+ status=201
99
+ )
100
+
101
+ order = post_order({'items': [{'sku': 'ABC', 'qty': 2}]})
102
+
103
+ assert order['orderId'] == 'ORD-123'
104
+ assert order['status'] == 'created'
105
+
106
+ @responses.activate
107
+ def test_handles_api_errors():
108
+ responses.add(
109
+ responses.GET,
110
+ 'https://api.example.com/users/1',
111
+ json={'error': 'Server error'},
112
+ status=500
113
+ )
114
+
115
+ with pytest.raises(Exception) as exc:
116
+ fetch_user_data(1)
117
+ assert 'API error' in str(exc.value)
118
+ ```
119
+
120
+ ---
121
+
122
+ ## Key Difference from jest.mock
123
+
124
+ | Approach | What Happens | Real HTTP? |
125
+ |----------|--------------|------------|
126
+ | `jest.mock('node-fetch')` | Replaces module entirely | No |
127
+ | MSW / responses | Intercepts at network layer | Yes (intercepted before leaving machine) |
128
+
129
+ MSW allows real `fetch()` calls to execute, testing the actual HTTP code path while still controlling external responses.
130
+
131
+ ---
132
+
133
+ ## Placeholders
134
+
135
+ | Placeholder | Description |
136
+ |-------------|-------------|
137
+ | `{component_name}` | Name of the API client component |
138
+ | `{component_path}` | Import path to the API module |
139
+ | `{module}` | Python module name |
@@ -0,0 +1,168 @@
1
+ # Pattern 3: File Parser Verification
2
+
3
+ ## Strategy
4
+
5
+ Create test input file, run parser, verify parsed output structure and values.
6
+
7
+ ---
8
+
9
+ ## Template (Bash)
10
+
11
+ ```bash
12
+ #!/bin/bash
13
+ # File Parser Verification: {component_name}
14
+ set -e
15
+
16
+ echo "=== File Parser Verification: {component_name} ==="
17
+
18
+ # Create test input
19
+ TEST_FILE=$(mktemp --suffix=.{ext})
20
+ cat > "$TEST_FILE" << 'EOF'
21
+ {test_input_content}
22
+ EOF
23
+
24
+ # Cleanup trap
25
+ cleanup() {
26
+ rm -f "$TEST_FILE"
27
+ }
28
+ trap cleanup EXIT
29
+
30
+ # Test 1: Parse succeeds
31
+ echo -n "Test 1: Parse succeeds... "
32
+ OUTPUT=$({parser_command} "$TEST_FILE" 2>&1)
33
+ if [ $? -eq 0 ]; then
34
+ echo "PASS"
35
+ else
36
+ echo "FAIL"
37
+ exit 1
38
+ fi
39
+
40
+ # Test 2: Output structure valid
41
+ echo -n "Test 2: Output structure... "
42
+ if echo "$OUTPUT" | jq -e '{json_structure_check}' > /dev/null 2>&1; then
43
+ echo "PASS"
44
+ else
45
+ echo "FAIL"
46
+ echo "Output was: $OUTPUT"
47
+ exit 1
48
+ fi
49
+
50
+ # Test 3: Values correct
51
+ echo -n "Test 3: Values correct... "
52
+ VALUE=$(echo "$OUTPUT" | jq -r '{value_path}')
53
+ if [ "$VALUE" = "{expected_value}" ]; then
54
+ echo "PASS"
55
+ else
56
+ echo "FAIL (expected: {expected_value}, got: $VALUE)"
57
+ exit 1
58
+ fi
59
+
60
+ # Test 4: Invalid input handling
61
+ echo -n "Test 4: Invalid input handling... "
62
+ if ! {parser_command} "/nonexistent/file.{ext}" 2>&1; then
63
+ echo "PASS (error returned)"
64
+ else
65
+ echo "FAIL (should have errored)"
66
+ exit 1
67
+ fi
68
+
69
+ echo "=== All tests passed ==="
70
+ ```
71
+
72
+ ---
73
+
74
+ ## Template (Node/Jest)
75
+
76
+ ```javascript
77
+ const fs = require('fs');
78
+ const path = require('path');
79
+ const os = require('os');
80
+ const { parse } = require('{component_path}');
81
+
82
+ describe('{component_name} Parser', () => {
83
+ let testFile;
84
+
85
+ beforeAll(() => {
86
+ testFile = path.join(os.tmpdir(), 'test-input.{ext}');
87
+ fs.writeFileSync(testFile, `{test_input_content}`);
88
+ });
89
+
90
+ afterAll(() => {
91
+ fs.unlinkSync(testFile);
92
+ });
93
+
94
+ test('parses valid input', () => {
95
+ const result = parse(testFile);
96
+ expect(result).toBeDefined();
97
+ });
98
+
99
+ test('output has expected structure', () => {
100
+ const result = parse(testFile);
101
+ expect(result).toHaveProperty('{expected_field}');
102
+ });
103
+
104
+ test('values are correct', () => {
105
+ const result = parse(testFile);
106
+ expect(result.{field}).toBe('{expected_value}');
107
+ });
108
+
109
+ test('handles invalid input', () => {
110
+ expect(() => parse('/nonexistent/file.{ext}')).toThrow();
111
+ });
112
+ });
113
+ ```
114
+
115
+ ---
116
+
117
+ ## Template (Python/pytest)
118
+
119
+ ```python
120
+ import pytest
121
+ import tempfile
122
+ import os
123
+ from {module} import {parser_function}
124
+
125
+ @pytest.fixture
126
+ def test_file():
127
+ fd, path = tempfile.mkstemp(suffix='.{ext}')
128
+ with os.fdopen(fd, 'w') as f:
129
+ f.write('''{test_input_content}''')
130
+ yield path
131
+ os.unlink(path)
132
+
133
+ def test_parse_succeeds(test_file):
134
+ result = {parser_function}(test_file)
135
+ assert result is not None
136
+
137
+ def test_output_structure(test_file):
138
+ result = {parser_function}(test_file)
139
+ assert '{expected_field}' in result
140
+
141
+ def test_values_correct(test_file):
142
+ result = {parser_function}(test_file)
143
+ assert result['{field}'] == '{expected_value}'
144
+
145
+ def test_handles_invalid_input():
146
+ with pytest.raises({ExpectedException}):
147
+ {parser_function}('/nonexistent/file.{ext}')
148
+ ```
149
+
150
+ ---
151
+
152
+ ## Placeholders
153
+
154
+ | Placeholder | Description |
155
+ |-------------|-------------|
156
+ | `{component_name}` | Name of the parser component |
157
+ | `{component_path}` | Import path to the parser module |
158
+ | `{module}` | Python module name |
159
+ | `{parser_function}` | Name of the parse function |
160
+ | `{parser_command}` | CLI command to run parser |
161
+ | `{ext}` | File extension (e.g., json, yaml, csv) |
162
+ | `{test_input_content}` | Sample input content |
163
+ | `{expected_field}` | Field expected in parsed result |
164
+ | `{field}` | Specific field to check value |
165
+ | `{expected_value}` | Expected value of field |
166
+ | `{json_structure_check}` | jq expression for structure check |
167
+ | `{value_path}` | jq path to specific value |
168
+ | `{ExpectedException}` | Python exception class for errors |
@@ -0,0 +1,162 @@
1
+ # Pattern 2: HTTP Server Verification
2
+
3
+ ## Strategy
4
+
5
+ Start server, wait for ready, make HTTP requests, verify responses, cleanup.
6
+
7
+ ---
8
+
9
+ ## Template (Bash)
10
+
11
+ ```bash
12
+ #!/bin/bash
13
+ # HTTP Server Verification: {component_name}
14
+ set -e
15
+
16
+ echo "=== HTTP Server Verification: {component_name} ==="
17
+
18
+ # Start server in background
19
+ {start_command} &
20
+ SERVER_PID=$!
21
+ echo "Started server (PID: $SERVER_PID)"
22
+
23
+ # Cleanup trap
24
+ cleanup() {
25
+ echo "Cleaning up..."
26
+ kill $SERVER_PID 2>/dev/null || true
27
+ wait $SERVER_PID 2>/dev/null || true
28
+ }
29
+ trap cleanup EXIT
30
+
31
+ # Wait for server to be ready
32
+ echo -n "Waiting for server... "
33
+ for i in {1..30}; do
34
+ if curl -s http://localhost:{port}/health > /dev/null 2>&1; then
35
+ echo "ready"
36
+ break
37
+ fi
38
+ sleep 0.5
39
+ done
40
+
41
+ # Test 1: Health endpoint
42
+ echo -n "Test 1: Health endpoint... "
43
+ HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:{port}/health)
44
+ if [ "$HTTP_CODE" = "200" ]; then
45
+ echo "PASS (HTTP 200)"
46
+ else
47
+ echo "FAIL (HTTP $HTTP_CODE)"
48
+ exit 1
49
+ fi
50
+
51
+ # Test 2: API endpoint response
52
+ echo -n "Test 2: API response... "
53
+ RESPONSE=$(curl -s http://localhost:{port}{endpoint})
54
+ if echo "$RESPONSE" | jq -e '{json_validation}' > /dev/null 2>&1; then
55
+ echo "PASS (valid response)"
56
+ else
57
+ echo "FAIL (invalid response)"
58
+ echo "Response was: $RESPONSE"
59
+ exit 1
60
+ fi
61
+
62
+ # Test 3: 404 handling
63
+ echo -n "Test 3: 404 handling... "
64
+ HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:{port}/nonexistent)
65
+ if [ "$HTTP_CODE" = "404" ]; then
66
+ echo "PASS (HTTP 404)"
67
+ else
68
+ echo "FAIL (HTTP $HTTP_CODE, expected 404)"
69
+ exit 1
70
+ fi
71
+
72
+ echo "=== All tests passed ==="
73
+ ```
74
+
75
+ ---
76
+
77
+ ## Template (Node/Jest with Supertest)
78
+
79
+ ```javascript
80
+ const request = require('supertest');
81
+ const { createServer } = require('{component_path}');
82
+
83
+ describe('{component_name} HTTP Server', () => {
84
+ let server;
85
+
86
+ beforeAll(async () => {
87
+ server = await createServer();
88
+ });
89
+
90
+ afterAll(async () => {
91
+ await server.close();
92
+ });
93
+
94
+ test('health endpoint returns 200', async () => {
95
+ const response = await request(server).get('/health');
96
+ expect(response.status).toBe(200);
97
+ });
98
+
99
+ test('API endpoint returns valid data', async () => {
100
+ const response = await request(server).get('{endpoint}');
101
+ expect(response.status).toBe(200);
102
+ expect(response.body).toHaveProperty('{expected_field}');
103
+ });
104
+
105
+ test('handles 404 gracefully', async () => {
106
+ const response = await request(server).get('/nonexistent');
107
+ expect(response.status).toBe(404);
108
+ });
109
+ });
110
+ ```
111
+
112
+ ---
113
+
114
+ ## Template (Python/pytest)
115
+
116
+ ```python
117
+ import pytest
118
+ import requests
119
+ import subprocess
120
+ import time
121
+
122
+ @pytest.fixture(scope='module')
123
+ def server():
124
+ proc = subprocess.Popen(['{start_command}'])
125
+ # Wait for server to start
126
+ for _ in range(30):
127
+ try:
128
+ requests.get('http://localhost:{port}/health')
129
+ break
130
+ except requests.ConnectionError:
131
+ time.sleep(0.5)
132
+ yield 'http://localhost:{port}'
133
+ proc.terminate()
134
+ proc.wait()
135
+
136
+ def test_health_endpoint(server):
137
+ response = requests.get(f'{server}/health')
138
+ assert response.status_code == 200
139
+
140
+ def test_api_endpoint(server):
141
+ response = requests.get(f'{server}{endpoint}')
142
+ assert response.status_code == 200
143
+ assert '{expected_field}' in response.json()
144
+
145
+ def test_404_handling(server):
146
+ response = requests.get(f'{server}/nonexistent')
147
+ assert response.status_code == 404
148
+ ```
149
+
150
+ ---
151
+
152
+ ## Placeholders
153
+
154
+ | Placeholder | Description |
155
+ |-------------|-------------|
156
+ | `{component_name}` | Name of the HTTP server component |
157
+ | `{component_path}` | Import path to the server module |
158
+ | `{start_command}` | Command to start the server |
159
+ | `{port}` | Port the server listens on |
160
+ | `{endpoint}` | API endpoint to test |
161
+ | `{expected_field}` | Field expected in JSON response |
162
+ | `{json_validation}` | jq expression for JSON validation |