google-agents-cli-scaffold
Project scaffolding, deployment configuration, and CI/CD setup for Google ADK agents.
fail-fast-no-hedging
Eliminate component hedging anti-patterns that mask infrastructure failures. Build systems that fail loudly when broken instead of limping along in degraded states. Critical for production reliability and operational visibility.
Full skill instructions
Hedging is treating required infrastructure as optional through defensive try/except blocks that mask failures as normal operation.
The Critical Question: Is this component required for the system to work correctly, or is it a genuine optional enhancement?
When required infrastructure fails, the system MUST fail loudly. When optional features fail, logging and continuing may be appropriate.
When analyzing a codebase, conclude with this structured list of all hedging issues found:
## Hedging Anti-Patterns Found in [directory/module name]
**N files with component hedging violations:**
1. **filename.py** (SEVERITY)
- Location: `function_name()` lines X-Y
- Issue: Brief description of what's wrong
- Hedging: Explanation of how it's treating required infrastructure as optional
- Impact: What happens in production when infrastructure fails
2. **filename.py** (SEVERITY)
- Location: `function_name()` lines X-Y
- Issue: Brief description of what's wrong
- Hedging: Explanation of how it's treating required infrastructure as optional
- Impact: What happens in production when infrastructure fails
Example (from lt_memory/ audit):
## Hedging Anti-Patterns Found in lt_memory/
**3 files with component hedging violations:**
1. **db_access.py** (HIGH SEVERITY)
- Location: `get_or_create_entity()` lines 916-933
- Issue: Returns `None` when database INSERT...RETURNING fails, masking query failure as "entity not found"
- Hedging: Docstring declares return type as `Entity`, implementation silently returns `None` on infrastructure failure
- Impact: Caller cannot distinguish between "entity doesn't exist" (legitimate) vs "database query failed" (infrastructure down)
2. **extraction.py** (HIGH SEVERITY)
- Location: `_parse_extraction_response()` lines 396-397 and 430
- Issue: Returns `[]` (empty list) when JSON parsing fails, instead of raising as docstring declares
- Hedging: Docstring says "Raises: ValueError" but code returns `[]` on parse failures
- Impact: Caller sees empty list and treats it as "no memories extracted" when actually LLM returned invalid JSON
This format makes all issues immediately scannable before remediation work begins.
When analyzing a new codebase:
Identify Infrastructure Dependencies
Apply Three Diagnostic Tests
Look for These Red Flags
except Exception: return [] # Infrastructure failure → empty data
except Exception: return False # Connection error → "not allowed"
except Exception: return None # Database down → "not found"
Based on systematic removal of 40+ hedging anti-patterns across production systems, these specific patterns emerge repeatedly:
Pattern: Catching database/service failures and raising ValidationError (400) instead of letting them propagate as 500s.
# REAL EXAMPLE: CNS API Layer
def execute_action(self, action: str, data: Dict) -> Dict:
try:
session_manager = get_shared_session_manager()
lt_db = LTMemoryDB(session_manager)
except Exception as e:
# Database down converted to "your input is invalid"!
if "connection" in str(e) or "database" in str(e):
raise ValidationError(f"Database connection failed: {e}")
Impact: Users see "Bad Request" when database is down. Monitoring doesn't alert (watches 500s, not 400s). Operators think users are sending bad data while infrastructure burns.
Fix: Remove business-layer exception translation. Let infrastructure exceptions bubble to API boundary where proper HTTP status translation happens.
Pattern: Setting self.component_available = False during init, then checking it hundreds of times throughout the codebase.
# REAL EXAMPLE: ValkeyClient with 200+ defensive checks
class ValkeyClient:
def __init__(self):
try:
self._init_connections()
self.valkey_available = True
except Exception:
self.valkey_available = False
def get(self, key: str) -> Optional[Any]:
if not self.valkey_available: # One of 200+ checks!
return None
return self.valkey.get(key)
Impact:
Fix: Remove availability tracking entirely. If component is required, fail at initialization. The "graceful degradation" never actually helps - it just delays the inevitable failure.
Pattern: Returning {"success": True, "value": None} when infrastructure fails.
# REAL EXAMPLE: Calendar configuration endpoint
def get_calendar_config(self, user_id: str) -> Dict:
try:
config = credential_service.get_credential(user_id, "calendar_url")
return {"success": True, "calendar_url": config}
except Exception:
# Vault down? Claim success anyway!
return {"success": True, "calendar_url": None, "message": "Not configured"}
Impact: Client cannot distinguish "user hasn't configured calendar" from "credential service is down". UI shows "not configured" while Vault burns.
Pattern: Critical scheduled jobs return False on registration failure instead of raising.
# REAL EXAMPLE: Token renewal that fails silently
def register_jobs(self) -> bool:
try:
scheduler = get_scheduler()
success = scheduler.register_job(
job_id="vault-token-renewer",
func=self.renew_token,
trigger="interval",
days=7
)
return success # False if registration failed
except Exception:
return False # Import error? Scheduler down? Who knows!
Impact: Token renewal silently fails to register. System runs fine for 32 days, then authentication mysteriously breaks when token expires. No errors logged at startup.
Pattern: Deferring initialization with lazy loading, making required components appear optional.
# REAL EXAMPLE: Email service that's actually required
class Service:
def __init__(self):
self._email_service = None # Lazy loaded
def send_welcome_email(self, user_id: str):
if hasattr(self, '_email_service') and self._email_service:
self._email_service.send(...) # Silently skip if not loaded!
Impact: Required functionality (welcome emails) silently skipped when service fails to initialize. Users don't get onboarding emails, no errors logged.
Pattern: Base class catches exceptions, subclass adds another layer, framework adds third layer.
# REAL EXAMPLE: Working memory trinket system
# Layer 1: Base trinket class
class BaseTrinket:
def handle_update_request(self):
try:
return self._generate_content()
except Exception:
return None # Mask all errors
# Layer 2: Event handler
def _handle_update_trinket(self, event):
try:
content = trinket.handle_update_request()
except Exception as e:
logger.warning(f"Trinket failed: {e}") # Second mask
# Layer 3: Individual trinket
class ReminderTrinket(BaseTrinket):
def _generate_content(self):
try:
reminders = self.get_reminders()
except Exception:
return [] # Third mask!
Impact: Database failure → returns [] → caught and returns None → caught and logged as warning. Original DatabaseError completely lost. Operators see "Trinket failed: 'NoneType' has no attribute 'format'" instead of "Database connection lost".
Pattern: JSON decode errors returning None instead of raising.
# REAL EXAMPLE: Database JSON columns
def fetch_as_dict(self, query: str) -> Optional[Dict]:
result = self.execute(query)
if result and result[0]:
try:
return json.loads(result[0])
except json.JSONDecodeError:
logger.warning("Failed to parse JSON")
return None # Corrupted data = no data!
Impact: Data corruption indistinguishable from NULL values. Corrupted user preferences silently become "no preferences". Data quality issues invisible until user complaints.
Pattern: Checking for attributes that are never set anywhere in the codebase.
# REAL EXAMPLE: Cache updater that doesn't exist
def _update_cache_if_pooled(self) -> None:
if hasattr(self, '_cache_updater') and self._cache_updater:
# This attribute is NEVER set anywhere!
try:
self._cache_updater(self.user_id, self._message_cache)
except Exception:
logger.warning("Cache update failed")
Impact: Dead code creating false architectural impressions. Future developers think "cache updates must be optional" when they're actually handled elsewhere entirely.
Pattern: Continuing after required sub-operations fail.
# REAL EXAMPLE: User creation with broken setup
def create_user(email: str) -> str:
user_id = db.insert_user(email)
try:
initialize_user_preferences(user_id)
create_welcome_reminders(user_id)
send_welcome_email(user_id)
except Exception as e:
logger.error(f"User setup failed: {e}")
# Continue - user exists but broken!
return user_id # "Success!"
Impact: Users created in broken state. Can log in but missing preferences, reminders, welcome email. Support tickets: "Features don't work for some users."
Pattern: Security-motivated hedging that creates operational blindness.
# REAL EXAMPLE: Rate limiter "failing closed"
def is_allowed(self, identifier: str) -> Tuple[bool, int]:
try:
count = valkey.increment(f"rate:{identifier}")
return count <= self.limit, 0
except Exception:
# "Fail closed for security" - but identical to rate limited!
return False, self.window_seconds
Impact: Valkey outage = all users rate limited. Support flooded with "I can't log in" while ops thinks "high traffic day". Security theater creating availability problems.
<fail_fast> def operation([PARAMS]) -> [RETURN_TYPE]: result = [REQUIRED_INFRASTRUCTURE].query() # Raises on infrastructure failure return result # Only returns actual data or legitimate empty state </fail_fast>
<diagnostic> Can caller distinguish between "[NO_DATA]" and "[INFRASTRUCTURE_DOWN]"? </diagnostic> </pattern>Examples of [SAFE_DEFAULT]: [], None, False, 0, {}
Examples of [REQUIRED_INFRASTRUCTURE]: database, cache, auth_service, message_queue
@property
def component(self):
if self._component is None:
self._component = initialize_component()
return self._component
def operation(self):
if hasattr(self, '_component') and self._component: # Defensive checks
return self._component.do_work()
return [DEGRADED_RESULT]
</anti_pattern>
<fail_fast> class Service: def init(self): self.component = initialize_component() # Fail at startup if broken
def operation(self):
return self.component.do_work() # No defensive checks needed
</fail_fast>
<diagnostic> Is the component truly optional, or are we just afraid of startup failures? </diagnostic> </pattern>try:
initialize_related([resource_id]) # Required setup
except Exception:
logger.error("Setup failed")
# Continue - resource exists but broken
return resource_id # Partial success returned as complete
</anti_pattern>
<fail_fast> def create_resource([PARAMS]) -> [ID_TYPE]: resource_id = database.insert([DATA]) initialize_related([resource_id]) # Fails → transaction rolls back return resource_id # Only returns if fully initialized </fail_fast>
<diagnostic> Are we creating broken/incomplete entities that will fail later? </diagnostic> </pattern>def get_config([PARAMS]) -> Dict: try: return config_service.fetch([KEY]) except Exception: return {"success": True, "value": None} # Claim success on failure! </anti_pattern>
<fail_fast> def get_metric([PARAMS]) -> [NUMERIC_TYPE]: result = metrics_service.query([PARAMS]) # Raises on service failure return result.value # Zero only when metric genuinely is zero
def get_config([PARAMS]) -> Dict: config = config_service.fetch([KEY]) # Raises on service failure return {"success": True, "value": config} </fail_fast>
<diagnostic> Does the "safe" default hide infrastructure problems from operators? </diagnostic> </pattern>if result:
return [RESOURCE_TYPE](**result)
# This fallback will NEVER execute in correct operation
# INSERT...RETURNING should always return a result
# If it doesn't, infrastructure is broken
fetch_query = "SELECT * FROM [TABLE] WHERE ..."
existing = database.query(fetch_query)
return [RESOURCE_TYPE](**existing) if existing else None
</anti_pattern>
<fail_fast> def get_or_create_resource([PARAMS]) -> [RESOURCE_TYPE]: result = database.insert_returning([DATA])
if not result:
raise RuntimeError(
f"INSERT...RETURNING failed - database operation broken, "
f"not a recoverable race condition"
)
return [RESOURCE_TYPE](**result)
</fail_fast>
<diagnostic> Critical Question: "Will this fallback code realistically execute when the system is operating correctly?" - YES → Legitimate defensive programming (real race conditions) - NO → Hedging that masks the real error </diagnostic> </pattern>For each try/except block, perform this systematic analysis:
FAILURE SCENARIO ANALYSIS
=========================
1. What operations are in the try block?
- Database calls?
- External API calls?
- Cache/session operations?
2. What can fail, and why?
- Network timeout
- Service unavailable
- Invalid data format
- Resource exhausted
3. Are these failures EXPECTED or UNEXPECTED?
- Expected: Retry logic, validation errors, race conditions
- Unexpected: Infrastructure down, OOM, disk full
4. What does the except block do?
- Return safe default (None, [], False, 0)?
- Log and re-raise?
- Convert to different exception?
- Continue with degraded state?
5. Can the caller handle this error?
- Yes: Specific exception type (UserNotFoundError)
- No: Infrastructure failure (DatabaseError, ConnectionError)
For each try/except block, ask:
Is this infrastructure required?
What type of operation?
What's the failure mode?
What does the catch block do?
HIGH Severity
MEDIUM Severity
LOW Severity
# GOOD: Database layer translates SQLAlchemy exceptions to domain exceptions
def get_user(user_id: str) -> User:
try:
return session.query(User).filter_by(id=user_id).one()
except NoResultFound:
raise UserNotFoundError(f"User {user_id} not found")
except SQLAlchemyError as e:
raise DatabaseError(f"Database query failed: {e}")
# GOOD: API endpoint translates domain exceptions to HTTP status codes
@router.post("/actions")
def actions_endpoint(request_data: ActionRequest):
try:
response = handler.handle_request(request_data)
return response.to_dict()
except ValidationError as e:
return JSONResponse(status_code=400, ...) # Client error
except Exception as e:
logger.error(f"Actions endpoint error: {e}", exc_info=True)
return JSONResponse(status_code=500, ...) # Infrastructure error
# BAD: Business logic converting infrastructure failures to client errors
def execute_action(self, action: str) -> Dict:
try:
session_manager = get_session_manager()
lt_db = LTMemoryDB(session_manager)
except Exception as e:
# WRONG: Makes infrastructure failure (500) look like client error (400)
raise ValidationError(f"Database connection failed: {e}")
Why: Infrastructure exception handling belongs at architectural boundaries (API endpoints), not in business logic. Converting DatabaseError → ValidationError makes 500s appear as 400s.
# GOOD: Retry on transient failures with backoff
def fetch_with_retry(url: str, attempts: int = 3) -> Response:
for attempt in range(attempts):
try:
return requests.get(url, timeout=5)
except requests.Timeout:
if attempt == attempts - 1:
raise # Final attempt failed
logger.warning(f"Attempt {attempt+1} timed out, retrying...")
time.sleep(2 ** attempt) # Exponential backoff
Why: Transient network failures are expected and retrying can succeed. Each retry is logged for visibility.
# GOOD: Add context that's not obvious from code
def process_batch(batch_id: str, items: List[Item]):
try:
for i, item in enumerate(items):
process_item(item)
except ProcessingError as e:
# Stack trace shows WHERE but not WHICH batch/item
logger.error(
f"Batch {batch_id} failed at item {i+1}/{len(items)} "
f"(item_id={item.id}): {e}"
)
raise ProcessingError(f"Batch {batch_id} processing failed") from e
Why: Adds business context (batch ID, item position) that's not in the stack trace but crucial for debugging.
# GOOD: Optional features can fail gracefully
def save_with_cache(data: Dict) -> None:
# Critical: Save to database
db.save(data) # Must succeed, raises on failure
# Optional: Update cache
try:
cache.set(data['id'], data)
except CacheError as e:
logger.warning(f"Cache update failed (non-critical): {e}")
# Continue - cache miss is acceptable
Why: Cache failure shouldn't break the operation. Log because we're suppressing the error.
Write test for infrastructure failure propagation
def test_propagates_database_failure():
with mock.patch('db.query', side_effect=DatabaseError):
with pytest.raises(DatabaseError):
service.get_data()
Remove defensive try/except
Update docstring/types if needed
Run test to verify failure propagates
Add monitoring for the new exception type
def test_infrastructure_failure_propagates():
"""Verify infrastructure failure raises, doesn't return safe default."""
service = AuthService()
with mock.patch('valkey.get', side_effect=ConnectionError("Valkey unreachable")):
with pytest.raises(ConnectionError):
service.validate_session("test-token")
# NOT: assert service.validate_session(...) is None
def test_user_with_no_tokens_returns_empty_list():
"""Verify empty result is legitimate, not masked error."""
service = AuthService()
# User exists but has no tokens
result = service.list_tokens(user_id="test-user")
assert result == [] # Legitimately empty
assert not isinstance(result, type(None)) # Not None from error
Before Fail-Fast Refactoring (Valkey Down)
User Experience:
- "Too many requests" errors (rate limiter returns False)
- "Invalid session" errors (session validation returns None)
- "Resource locked" timeouts (locks return False)
Operator Experience:
- No monitoring alerts
- Users complaining about "weird behavior"
- 2 hours to diagnose: "Oh, Valkey has been down since 3pm"
After Fail-Fast Refactoring (Valkey Down)
User Experience:
- "Service temporarily unavailable" (clear 500 errors)
Operator Experience:
- PagerDuty alert: "VALKEY_CONNECTION_ERROR" at 3:01pm
- Clear stack trace pointing to infrastructure
- Fixed in 5 minutes
When reviewing code, these patterns indicate likely hedging:
component_available, is_enabled, has_feature{"success": True, "value": None} when operations failtry: blocks wrapping infrastructure calls with except Exception:bool for success AND resultsOptional[T] return types for operations that should always succeedif hasattr() and self.thing and self.thing.ready:[] in except blocksFalse instead of raisingif self.required_dependency: before every operationNone when service creation failsCan you distinguish between legitimate empty states and infrastructure failures?
DatabaseError when down, returns [] when no data[] for both casesWill this fallback code run during normal operation?
Does the implementation match documented behavior?
Goal: Systems that crash obviously when broken are easier to operate than systems that limp along mysteriously.
Remember:
After removing 40+ hedging patterns across multiple systems, key insights emerge:
component_available flags spread like a virusFalse when infrastructure downNone when they should expect exceptionsProject scaffolding, deployment configuration, and CI/CD setup for Google ADK agents.
Set up tracing, logging, and monitoring for deployed ADK agents across Cloud Trace, BigQuery, and third-party platforms.
Enterprise Azure infrastructure architect generating Bicep or Terraform from workload descriptions.
Plan and configure production-ready Azure Kubernetes Service clusters with Day-0 and Day-1 best practices.
Raw mechanical interfaces fusing Swiss typographic print with military terminal aesthetics. Rigid grids, extreme type scale contrast, utilitarian color, analog degradation effects. For data-heavy dashboards, portfolios, or editorial sites that need to feel like declassified blueprints.
Web search, scraping, extraction, crawling, and monitoring via ScrapeGraph AI CLI.
Skill for working with Firebase Hosting (Classic). Use this when you want to deploy static web apps, Single Page Apps (SPAs), or simple microservices. Do NOT use for Firebase App Hosting.
Deploy and manage web apps with Firebase App Hosting. Use this skill when deploying Next.js/Angular apps with backends.
Deploy applications and websites to Vercel. Use when the user requests deployment actions like "deploy my app", "deploy and give me the link", "push this live", or "create a preview deployment".
Build SEO-optimized pages at scale using templates, data, and proven playbook patterns.
Design and build isolated, reusable Convex backend components with clear boundaries and app-facing wrappers.
Deploy and manage projects on Vercel using token-based authentication. Use when working with Vercel CLI using access tokens rather than interactive login — e.g. "deploy to vercel", "set up vercel", "add environment variables to vercel".
Opus.ai: Revolutionize Your Web Experience
Build a no-code AI app in minutes.
An IDE for code migration from legacy to modern frameworks through coding agents.
Automate CGI animation in live-action scenes
Branded artistic QR-code concepts
Launch a website in seconds with AI.
Streamline Your Coding Experience with AI Code Helper
Convert any screenshot or design to clean code.