devsquad 3.6.0__py3-none-any.whl
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.
- devsquad-3.6.0.dist-info/METADATA +944 -0
- devsquad-3.6.0.dist-info/RECORD +95 -0
- devsquad-3.6.0.dist-info/WHEEL +5 -0
- devsquad-3.6.0.dist-info/entry_points.txt +2 -0
- devsquad-3.6.0.dist-info/licenses/LICENSE +21 -0
- devsquad-3.6.0.dist-info/top_level.txt +2 -0
- scripts/__init__.py +0 -0
- scripts/ai_semantic_matcher.py +512 -0
- scripts/alert_manager.py +505 -0
- scripts/api/__init__.py +43 -0
- scripts/api/models.py +386 -0
- scripts/api/routes/__init__.py +20 -0
- scripts/api/routes/dispatch.py +348 -0
- scripts/api/routes/lifecycle.py +330 -0
- scripts/api/routes/metrics_gates.py +347 -0
- scripts/api_server.py +318 -0
- scripts/auth.py +451 -0
- scripts/cli/__init__.py +1 -0
- scripts/cli/cli_visual.py +642 -0
- scripts/cli.py +1094 -0
- scripts/collaboration/__init__.py +212 -0
- scripts/collaboration/_version.py +1 -0
- scripts/collaboration/agent_briefing.py +656 -0
- scripts/collaboration/ai_semantic_matcher.py +260 -0
- scripts/collaboration/anchor_checker.py +281 -0
- scripts/collaboration/anti_rationalization.py +470 -0
- scripts/collaboration/async_integration_example.py +255 -0
- scripts/collaboration/batch_scheduler.py +149 -0
- scripts/collaboration/checkpoint_manager.py +561 -0
- scripts/collaboration/ci_feedback_adapter.py +351 -0
- scripts/collaboration/code_map_generator.py +247 -0
- scripts/collaboration/concern_pack_loader.py +352 -0
- scripts/collaboration/confidence_score.py +496 -0
- scripts/collaboration/config_loader.py +188 -0
- scripts/collaboration/consensus.py +244 -0
- scripts/collaboration/context_compressor.py +533 -0
- scripts/collaboration/coordinator.py +668 -0
- scripts/collaboration/dispatcher.py +1636 -0
- scripts/collaboration/dual_layer_context.py +128 -0
- scripts/collaboration/enhanced_worker.py +539 -0
- scripts/collaboration/feature_usage_tracker.py +206 -0
- scripts/collaboration/five_axis_consensus.py +334 -0
- scripts/collaboration/input_validator.py +401 -0
- scripts/collaboration/integration_example.py +287 -0
- scripts/collaboration/intent_workflow_mapper.py +350 -0
- scripts/collaboration/language_parsers.py +269 -0
- scripts/collaboration/lifecycle_protocol.py +1446 -0
- scripts/collaboration/llm_backend.py +453 -0
- scripts/collaboration/llm_cache.py +448 -0
- scripts/collaboration/llm_cache_async.py +347 -0
- scripts/collaboration/llm_retry.py +387 -0
- scripts/collaboration/llm_retry_async.py +389 -0
- scripts/collaboration/mce_adapter.py +597 -0
- scripts/collaboration/memory_bridge.py +1607 -0
- scripts/collaboration/models.py +537 -0
- scripts/collaboration/null_providers.py +297 -0
- scripts/collaboration/operation_classifier.py +289 -0
- scripts/collaboration/output_slicer.py +225 -0
- scripts/collaboration/performance_monitor.py +462 -0
- scripts/collaboration/permission_guard.py +865 -0
- scripts/collaboration/prompt_assembler.py +756 -0
- scripts/collaboration/prompt_variant_generator.py +483 -0
- scripts/collaboration/protocols.py +267 -0
- scripts/collaboration/report_formatter.py +352 -0
- scripts/collaboration/retrospective.py +279 -0
- scripts/collaboration/role_matcher.py +92 -0
- scripts/collaboration/role_template_market.py +352 -0
- scripts/collaboration/rule_collector.py +678 -0
- scripts/collaboration/scratchpad.py +346 -0
- scripts/collaboration/skill_registry.py +151 -0
- scripts/collaboration/skillifier.py +878 -0
- scripts/collaboration/standardized_role_template.py +317 -0
- scripts/collaboration/task_completion_checker.py +237 -0
- scripts/collaboration/test_quality_guard.py +695 -0
- scripts/collaboration/unified_gate_engine.py +598 -0
- scripts/collaboration/usage_tracker.py +309 -0
- scripts/collaboration/user_friendly_error.py +176 -0
- scripts/collaboration/verification_gate.py +312 -0
- scripts/collaboration/warmup_manager.py +635 -0
- scripts/collaboration/worker.py +513 -0
- scripts/collaboration/workflow_engine.py +684 -0
- scripts/dashboard.py +1088 -0
- scripts/generate_benchmark_report.py +786 -0
- scripts/history_manager.py +604 -0
- scripts/mcp_server.py +289 -0
- skills/__init__.py +32 -0
- skills/dispatch/handler.py +52 -0
- skills/intent/handler.py +59 -0
- skills/registry.py +67 -0
- skills/retrospective/__init__.py +0 -0
- skills/retrospective/handler.py +125 -0
- skills/review/handler.py +356 -0
- skills/security/handler.py +454 -0
- skills/test/__init__.py +0 -0
- skills/test/handler.py +78 -0
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
AntiRationalizationEngine - Per-role "excuse -> rebuttal" table system
|
|
5
|
+
|
|
6
|
+
Prevents Workers from skipping critical steps by injecting pre-written
|
|
7
|
+
anti-rationalization pairs into role prompts.
|
|
8
|
+
|
|
9
|
+
Design borrowed from Agent Skills (addyosmani/agent-skills):
|
|
10
|
+
- Each role has domain-specific rationalizations (AI excuses)
|
|
11
|
+
- Universal rationalizations apply to all roles
|
|
12
|
+
- Format: table of (excuse, reality) pairs injected as markdown
|
|
13
|
+
|
|
14
|
+
Integration point: Called by PromptAssembler._build_instruction()
|
|
15
|
+
to inject anti-rationalization content into each Worker's system prompt.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import logging
|
|
19
|
+
from dataclasses import dataclass
|
|
20
|
+
from typing import Any, Callable, Dict, List, Optional
|
|
21
|
+
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class RationalizationRow:
|
|
27
|
+
"""Single excuse-reality pair for anti-rationalization."""
|
|
28
|
+
excuse: str
|
|
29
|
+
reality: str
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class AntiRationalizationEngine:
|
|
33
|
+
"""
|
|
34
|
+
Stores and retrieves anti-rationalization tables per role.
|
|
35
|
+
|
|
36
|
+
Universal table applies to ALL roles. Role-specific tables
|
|
37
|
+
are merged on top. Total: 8 universal + 42 role-specific = 50 entries.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
_UNIVERSAL_TABLE: List[RationalizationRow] = [
|
|
41
|
+
RationalizationRow(
|
|
42
|
+
excuse="This is a small change, no need for full process",
|
|
43
|
+
reality="Small changes compound. Skip quality steps now, pay debt later",
|
|
44
|
+
),
|
|
45
|
+
RationalizationRow(
|
|
46
|
+
excuse="I'll clean this up later",
|
|
47
|
+
reality="Later never comes. Clean now or file explicit tech debt",
|
|
48
|
+
),
|
|
49
|
+
RationalizationRow(
|
|
50
|
+
excuse="The user didn't ask for this specifically",
|
|
51
|
+
reality="Professional quality is implicit. Deliver excellence always",
|
|
52
|
+
),
|
|
53
|
+
RationalizationRow(
|
|
54
|
+
excuse="This is already good enough",
|
|
55
|
+
reality="'Good enough' is the enemy of great. Iterate until excellent",
|
|
56
|
+
),
|
|
57
|
+
RationalizationRow(
|
|
58
|
+
excuse="Nobody will notice this detail",
|
|
59
|
+
reality="Details compound. 10 unnoticed issues = degraded experience",
|
|
60
|
+
),
|
|
61
|
+
RationalizationRow(
|
|
62
|
+
excuse="This is just a quick fix",
|
|
63
|
+
reality="Quick fixes become permanent code. Do it right or track as debt",
|
|
64
|
+
),
|
|
65
|
+
RationalizationRow(
|
|
66
|
+
excuse="The existing code already does this poorly",
|
|
67
|
+
reality="Two wrongs don't make a right. Fix properly or document the gap",
|
|
68
|
+
),
|
|
69
|
+
RationalizationRow(
|
|
70
|
+
excuse="Refactoring can wait until later",
|
|
71
|
+
reality="If you don't refactor now while you understand it, you never will",
|
|
72
|
+
),
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
_ROLE_SPECIFIC_TABLES: Dict[str, List[RationalizationRow]] = {
|
|
76
|
+
"architect": [
|
|
77
|
+
RationalizationRow(
|
|
78
|
+
excuse="This architecture is good enough",
|
|
79
|
+
reality=(
|
|
80
|
+
"'Good enough' without peer review hides technical debt "
|
|
81
|
+
"that compounds exponentially"
|
|
82
|
+
),
|
|
83
|
+
),
|
|
84
|
+
RationalizationRow(
|
|
85
|
+
excuse="I'll optimize performance later",
|
|
86
|
+
reality=(
|
|
87
|
+
"Architecture decisions lock in performance characteristics. "
|
|
88
|
+
"Optimize now or document explicit trade-off"
|
|
89
|
+
),
|
|
90
|
+
),
|
|
91
|
+
RationalizationRow(
|
|
92
|
+
excuse="Over-engineering shows thoroughness",
|
|
93
|
+
reality=(
|
|
94
|
+
"YAGNI (You Aren't Gonna Need It). Solve the actual problem, "
|
|
95
|
+
"not hypothetical futures"
|
|
96
|
+
),
|
|
97
|
+
),
|
|
98
|
+
RationalizationRow(
|
|
99
|
+
excuse="The current design handles our needs",
|
|
100
|
+
reality=(
|
|
101
|
+
"Design for the next 2x scale, not just today's load. "
|
|
102
|
+
"Future-you will thank present-you"
|
|
103
|
+
),
|
|
104
|
+
),
|
|
105
|
+
RationalizationRow(
|
|
106
|
+
excuse="This pattern is standard in the industry",
|
|
107
|
+
reality=(
|
|
108
|
+
"Standard doesn't mean optimal. Evaluate if this pattern fits "
|
|
109
|
+
"our specific constraints"
|
|
110
|
+
),
|
|
111
|
+
),
|
|
112
|
+
RationalizationRow(
|
|
113
|
+
excuse="Adding abstraction improves flexibility",
|
|
114
|
+
reality=(
|
|
115
|
+
"Every abstraction adds complexity. Don't generalize until "
|
|
116
|
+
"the third use case demands it"
|
|
117
|
+
),
|
|
118
|
+
),
|
|
119
|
+
],
|
|
120
|
+
"product-manager": [
|
|
121
|
+
RationalizationRow(
|
|
122
|
+
excuse="Requirements are clear enough from context",
|
|
123
|
+
reality=(
|
|
124
|
+
"Ambiguous requirements cause 70% of project failures. "
|
|
125
|
+
"Write explicit acceptance criteria"
|
|
126
|
+
),
|
|
127
|
+
),
|
|
128
|
+
RationalizationRow(
|
|
129
|
+
excuse="User will tell us if we got it wrong",
|
|
130
|
+
reality=(
|
|
131
|
+
"Late discovery costs 100x early validation. "
|
|
132
|
+
"Clarify assumptions upfront"
|
|
133
|
+
),
|
|
134
|
+
),
|
|
135
|
+
RationalizationRow(
|
|
136
|
+
excuse="We can iterate on the spec",
|
|
137
|
+
reality=(
|
|
138
|
+
"Iteration without a baseline wastes effort. "
|
|
139
|
+
"Establish the baseline first"
|
|
140
|
+
),
|
|
141
|
+
),
|
|
142
|
+
RationalizationRow(
|
|
143
|
+
excuse="Edge cases can be handled later",
|
|
144
|
+
reality=(
|
|
145
|
+
"Edge cases are where production systems fail. "
|
|
146
|
+
"Define them in acceptance criteria"
|
|
147
|
+
),
|
|
148
|
+
),
|
|
149
|
+
RationalizationRow(
|
|
150
|
+
excuse="The competitor does it this way",
|
|
151
|
+
reality=(
|
|
152
|
+
"Competitor decisions reflect their constraints, not ours. "
|
|
153
|
+
"Evaluate independently"
|
|
154
|
+
),
|
|
155
|
+
),
|
|
156
|
+
],
|
|
157
|
+
"security": [
|
|
158
|
+
RationalizationRow(
|
|
159
|
+
excuse="This is an internal tool, security doesn't matter",
|
|
160
|
+
reality=(
|
|
161
|
+
"Internal tools get compromised. Attackers target the weakest link. "
|
|
162
|
+
"Security habits apply everywhere"
|
|
163
|
+
),
|
|
164
|
+
),
|
|
165
|
+
RationalizationRow(
|
|
166
|
+
excuse="We'll add security later",
|
|
167
|
+
reality=(
|
|
168
|
+
"Security retrofitting is 10x harder than building it in. "
|
|
169
|
+
"Add it now"
|
|
170
|
+
),
|
|
171
|
+
),
|
|
172
|
+
RationalizationRow(
|
|
173
|
+
excuse="No one would try to exploit this",
|
|
174
|
+
reality=(
|
|
175
|
+
"Automated scanners find everything. "
|
|
176
|
+
"Security by obscurity is not security"
|
|
177
|
+
),
|
|
178
|
+
),
|
|
179
|
+
RationalizationRow(
|
|
180
|
+
excuse="The framework handles security",
|
|
181
|
+
reality=(
|
|
182
|
+
"Frameworks provide tools, not guarantees. "
|
|
183
|
+
"You must use them correctly"
|
|
184
|
+
),
|
|
185
|
+
),
|
|
186
|
+
RationalizationRow(
|
|
187
|
+
excuse="It's just a prototype",
|
|
188
|
+
reality=(
|
|
189
|
+
"Prototypes become production code. "
|
|
190
|
+
"Security habits from day one prevent 'test debt'"
|
|
191
|
+
),
|
|
192
|
+
),
|
|
193
|
+
RationalizationRow(
|
|
194
|
+
excuse="Authentication is out of scope",
|
|
195
|
+
reality=(
|
|
196
|
+
"Auth is the foundation of security. "
|
|
197
|
+
"Define auth requirements even if implementation is deferred"
|
|
198
|
+
),
|
|
199
|
+
),
|
|
200
|
+
],
|
|
201
|
+
"tester": [
|
|
202
|
+
RationalizationRow(
|
|
203
|
+
excuse="I'll write tests after the code works",
|
|
204
|
+
reality="You won't. Post-hoc tests test implementation, not behavior",
|
|
205
|
+
),
|
|
206
|
+
RationalizationRow(
|
|
207
|
+
excuse="This is too simple to test",
|
|
208
|
+
reality="Simple code gets complicated. Tests document expected behavior",
|
|
209
|
+
),
|
|
210
|
+
RationalizationRow(
|
|
211
|
+
excuse="Tests slow me down",
|
|
212
|
+
reality="Tests slow you NOW. They speed every future change",
|
|
213
|
+
),
|
|
214
|
+
RationalizationRow(
|
|
215
|
+
excuse="I tested it manually",
|
|
216
|
+
reality=(
|
|
217
|
+
"Manual testing doesn't persist. Tomorrow's change breaks it silently"
|
|
218
|
+
),
|
|
219
|
+
),
|
|
220
|
+
RationalizationRow(
|
|
221
|
+
excuse="The code is self-explanatory",
|
|
222
|
+
reality="Tests ARE the specification. They define what code SHOULD do",
|
|
223
|
+
),
|
|
224
|
+
RationalizationRow(
|
|
225
|
+
excuse="It's just a prototype",
|
|
226
|
+
reality=(
|
|
227
|
+
"Prototypes become production. Tests from day one prevent crisis"
|
|
228
|
+
),
|
|
229
|
+
),
|
|
230
|
+
RationalizationRow(
|
|
231
|
+
excuse="Mocking is too much overhead",
|
|
232
|
+
reality=(
|
|
233
|
+
"Without mocks you test framework behavior, not your logic. "
|
|
234
|
+
"Use the simplest double that proves your point"
|
|
235
|
+
),
|
|
236
|
+
),
|
|
237
|
+
],
|
|
238
|
+
"solo-coder": [
|
|
239
|
+
RationalizationRow(
|
|
240
|
+
excuse="It works, that's good enough",
|
|
241
|
+
reality=(
|
|
242
|
+
"Working but unreadable/insecure/architecturally wrong code "
|
|
243
|
+
"creates compound technical debt"
|
|
244
|
+
),
|
|
245
|
+
),
|
|
246
|
+
RationalizationRow(
|
|
247
|
+
excuse="I wrote it, so I know it's correct",
|
|
248
|
+
reality=(
|
|
249
|
+
"Authors are blind to their own assumptions. "
|
|
250
|
+
"Every change benefits from another perspective"
|
|
251
|
+
),
|
|
252
|
+
),
|
|
253
|
+
RationalizationRow(
|
|
254
|
+
excuse="AI-generated code is probably fine",
|
|
255
|
+
reality=(
|
|
256
|
+
"AI code needs MORE scrutiny, not less. "
|
|
257
|
+
"It's confident and plausible, even when wrong. "
|
|
258
|
+
"This is the most dangerous rationalization in multi-AI systems"
|
|
259
|
+
),
|
|
260
|
+
),
|
|
261
|
+
RationalizationRow(
|
|
262
|
+
excuse="The tests pass, so it's good",
|
|
263
|
+
reality=(
|
|
264
|
+
"Tests are necessary but insufficient. "
|
|
265
|
+
"They don't catch architecture, security, or readability issues"
|
|
266
|
+
),
|
|
267
|
+
),
|
|
268
|
+
RationalizationRow(
|
|
269
|
+
excuse="We'll clean it up later",
|
|
270
|
+
reality=(
|
|
271
|
+
"Later never comes. The review IS the quality gate — use it now"
|
|
272
|
+
),
|
|
273
|
+
),
|
|
274
|
+
RationalizationRow(
|
|
275
|
+
excuse="Fewer lines is simpler",
|
|
276
|
+
reality=(
|
|
277
|
+
"A 1-line nested ternary is NOT simpler than 5-line if/else. "
|
|
278
|
+
"Simplicity = comprehension speed, not line count"
|
|
279
|
+
),
|
|
280
|
+
),
|
|
281
|
+
RationalizationRow(
|
|
282
|
+
excuse="This follows established patterns",
|
|
283
|
+
reality=(
|
|
284
|
+
"Following patterns blindly leads to over-engineering. "
|
|
285
|
+
"Evaluate whether each pattern serves THIS specific need"
|
|
286
|
+
),
|
|
287
|
+
),
|
|
288
|
+
],
|
|
289
|
+
"devops": [
|
|
290
|
+
RationalizationRow(
|
|
291
|
+
excuse="CI is too slow, let's skip it",
|
|
292
|
+
reality=(
|
|
293
|
+
"Optimize pipeline, don't skip it. 5-min pipeline prevents hours debugging"
|
|
294
|
+
),
|
|
295
|
+
),
|
|
296
|
+
RationalizationRow(
|
|
297
|
+
excuse="This change is trivial, no need for full pipeline",
|
|
298
|
+
reality=(
|
|
299
|
+
"Trivial changes break builds. CI catches what humans miss, consistently"
|
|
300
|
+
),
|
|
301
|
+
),
|
|
302
|
+
RationalizationRow(
|
|
303
|
+
excuse="We'll add CI later",
|
|
304
|
+
reality=(
|
|
305
|
+
"Projects without CI accumulate broken states. Day one setup"
|
|
306
|
+
),
|
|
307
|
+
),
|
|
308
|
+
RationalizationRow(
|
|
309
|
+
excuse="The test is flaky, just re-run",
|
|
310
|
+
reality=(
|
|
311
|
+
"Flaky tests mask real bugs and waste everyone's time. "
|
|
312
|
+
"Fix the flakiness"
|
|
313
|
+
),
|
|
314
|
+
),
|
|
315
|
+
RationalizationRow(
|
|
316
|
+
excuse="Manual testing is enough",
|
|
317
|
+
reality=(
|
|
318
|
+
"Manual testing doesn't scale and isn't repeatable. Automate what you can"
|
|
319
|
+
),
|
|
320
|
+
),
|
|
321
|
+
],
|
|
322
|
+
"ui-designer": [
|
|
323
|
+
RationalizationRow(
|
|
324
|
+
excuse="It looks fine on my screen",
|
|
325
|
+
reality=(
|
|
326
|
+
"Test on real devices, screen readers, and slow networks. "
|
|
327
|
+
"'Fine on my screen' excludes most users"
|
|
328
|
+
),
|
|
329
|
+
),
|
|
330
|
+
RationalizationRow(
|
|
331
|
+
excuse="Accessibility can wait",
|
|
332
|
+
reality=(
|
|
333
|
+
"Retrofitting accessibility is 10x harder than building it in. "
|
|
334
|
+
"WCAG 2.1 AA from day one"
|
|
335
|
+
),
|
|
336
|
+
),
|
|
337
|
+
RationalizationRow(
|
|
338
|
+
excuse="Users won't notice this detail",
|
|
339
|
+
reality=(
|
|
340
|
+
"Details compound. 10 'unnoticeable' issues = unusable product"
|
|
341
|
+
),
|
|
342
|
+
),
|
|
343
|
+
RationalizationRow(
|
|
344
|
+
excuse="The design matches the mockup",
|
|
345
|
+
reality=(
|
|
346
|
+
"Mockups don't show edge cases, error states, or loading scenarios. "
|
|
347
|
+
"Design for all states"
|
|
348
|
+
),
|
|
349
|
+
),
|
|
350
|
+
RationalizationRow(
|
|
351
|
+
excuse="This animation enhances UX",
|
|
352
|
+
reality=(
|
|
353
|
+
"Unnecessary animations distract and hurt performance. "
|
|
354
|
+
"Every animation must serve a functional purpose"
|
|
355
|
+
),
|
|
356
|
+
),
|
|
357
|
+
],
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
def __init__(self, max_entries_per_role: int = 0):
|
|
361
|
+
"""
|
|
362
|
+
Initialize engine.
|
|
363
|
+
|
|
364
|
+
Args:
|
|
365
|
+
max_entries_per_role: Max entries to include per role (0 = all).
|
|
366
|
+
Useful for token budget control.
|
|
367
|
+
"""
|
|
368
|
+
self._max_entries = max_entries_per_role
|
|
369
|
+
self._cache: Dict[str, str] = {}
|
|
370
|
+
self._MAX_CACHE_SIZE = 64
|
|
371
|
+
|
|
372
|
+
def get_table(self, role_id: str) -> List[RationalizationRow]:
|
|
373
|
+
"""
|
|
374
|
+
Get combined universal + role-specific anti-rationalization table.
|
|
375
|
+
|
|
376
|
+
Args:
|
|
377
|
+
role_id: Role identifier (e.g., 'architect', 'solo-coder')
|
|
378
|
+
|
|
379
|
+
Returns:
|
|
380
|
+
Combined list of RationalizationRow entries
|
|
381
|
+
"""
|
|
382
|
+
specific = self._ROLE_SPECIFIC_TABLES.get(role_id, [])
|
|
383
|
+
combined = self._UNIVERSAL_TABLE + specific
|
|
384
|
+
if self._max_entries > 0:
|
|
385
|
+
return combined[: self._max_entries]
|
|
386
|
+
return combined
|
|
387
|
+
|
|
388
|
+
def get_table_size(self, role_id: str) -> int:
|
|
389
|
+
"""Return number of entries for a given role."""
|
|
390
|
+
return len(self.get_table(role_id))
|
|
391
|
+
|
|
392
|
+
def format_for_prompt(self, role_id: str) -> str:
|
|
393
|
+
"""
|
|
394
|
+
Format anti-rationalization table as markdown for prompt injection.
|
|
395
|
+
|
|
396
|
+
Args:
|
|
397
|
+
role_id: Role identifier
|
|
398
|
+
|
|
399
|
+
Returns:
|
|
400
|
+
Formatted markdown string ready for prompt injection,
|
|
401
|
+
or empty string if no entries found
|
|
402
|
+
"""
|
|
403
|
+
cache_key = f"{role_id}_{self._max_entries}"
|
|
404
|
+
if cache_key in self._cache:
|
|
405
|
+
return self._cache[cache_key]
|
|
406
|
+
|
|
407
|
+
rows = self.get_table(role_id)
|
|
408
|
+
if not rows:
|
|
409
|
+
return ""
|
|
410
|
+
|
|
411
|
+
lines = [
|
|
412
|
+
"\n## Quality Guardrails\n",
|
|
413
|
+
(
|
|
414
|
+
"The following thoughts are **incorrect** and must be ignored. "
|
|
415
|
+
"If you catch yourself thinking any left-column thought, "
|
|
416
|
+
"stop and follow the right-column guidance instead.\n"
|
|
417
|
+
),
|
|
418
|
+
"| Excuse (DO NOT think this) | Reality (follow this instead) |",
|
|
419
|
+
"|---|---|",
|
|
420
|
+
]
|
|
421
|
+
for row in rows:
|
|
422
|
+
escaped_excuse = row.excuse.replace("|", "\\|")
|
|
423
|
+
escaped_reality = row.reality.replace("|", "\\|")
|
|
424
|
+
lines.append(f"| {escaped_excuse} | {escaped_reality} |")
|
|
425
|
+
|
|
426
|
+
lines.append("\n**Rule**: Quality guardrails are non-negotiable.\n")
|
|
427
|
+
result = "\n".join(lines)
|
|
428
|
+
if len(self._cache) >= self._MAX_CACHE_SIZE:
|
|
429
|
+
oldest_key = next(iter(self._cache))
|
|
430
|
+
del self._cache[oldest_key]
|
|
431
|
+
self._cache[cache_key] = result
|
|
432
|
+
return result
|
|
433
|
+
|
|
434
|
+
def has_role(self, role_id: str) -> bool:
|
|
435
|
+
"""Check if a role has any specific entries."""
|
|
436
|
+
return role_id in self._ROLE_SPECIFIC_TABLES
|
|
437
|
+
|
|
438
|
+
def list_all_roles(self) -> List[str]:
|
|
439
|
+
"""Return all roles with specific tables."""
|
|
440
|
+
return sorted(self._ROLE_SPECIFIC_TABLES.keys())
|
|
441
|
+
|
|
442
|
+
@property
|
|
443
|
+
def universal_count(self) -> int:
|
|
444
|
+
"""Number of universal entries."""
|
|
445
|
+
return len(self._UNIVERSAL_TABLE)
|
|
446
|
+
|
|
447
|
+
@property
|
|
448
|
+
def total_entries(self) -> int:
|
|
449
|
+
"""Total entries across all roles (union of universal + max specific)."""
|
|
450
|
+
max_specific = max(
|
|
451
|
+
len(v) for v in self._ROLE_SPECIFIC_TABLES.values()
|
|
452
|
+
) if self._ROLE_SPECIFIC_TABLES else 0
|
|
453
|
+
return len(self._UNIVERSAL_TABLE) + max_specific
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
def get_shared_engine(max_entries_per_role: int = 0) -> AntiRationalizationEngine:
|
|
457
|
+
"""
|
|
458
|
+
Get or create shared singleton instance.
|
|
459
|
+
|
|
460
|
+
Args:
|
|
461
|
+
max_entries_per_role: Max entries per role (0 = all)
|
|
462
|
+
|
|
463
|
+
Returns:
|
|
464
|
+
Shared AntiRationalizationEngine instance
|
|
465
|
+
"""
|
|
466
|
+
if not hasattr(get_shared_engine, "_instance"):
|
|
467
|
+
get_shared_engine._instance = AntiRationalizationEngine(
|
|
468
|
+
max_entries_per_role=max_entries_per_role
|
|
469
|
+
)
|
|
470
|
+
return get_shared_engine._instance
|