一键导入
strangler-pattern-guide
Use as reference guide for strangler pattern implementation. Provides patterns and best practices for legacy migrations.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use as reference guide for strangler pattern implementation. Provides patterns and best practices for legacy migrations.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Convene a tiered LLM council to deliberate on engineering decisions, architecture choices, refactor strategies, PR reviews, prioritization calls, or any problem with meaningful trade-offs. Integrates with gstack's role-driven workflow and Claude Code subagents. Trigger on: "council this", "what should we do", "which approach", "help me decide", "weigh the options", any architectural/technical decision with long-term consequences, or any gstack phase (plan → review → ship) where a cross-role deliberation would improve the outcome. Prefer this over single-model answers when stakes of getting it wrong are non-trivial. All council sessions are logged to Obsidian as Congressional Records.
Apply NASA's Power of 10 safety rules as a pre-execution planning contract for any engineering task. Use this skill before writing or modifying code whenever a task has been defined (via gstack, /council ruling, or direct issue). The skill researches the codebase, drafts a P10-compliant implementation plan (full task or named stage), saves it to Obsidian, and provides a decision overview. The saved draft becomes the foundation the execution agent reads before touching any file. Trigger on: "plan this with p10", "p10 draft", "bridge to execution", "safe implementation plan", any task following a /council ruling, or any gstack /plan phase where correctness and safety are non-trivial. This is the bridge between planning and elite execution — always invoke it before implementing complex, stateful, or safety-critical logic.
The final voice before release. Convenes three equal-seated luminaries — Garry Tan, Richard Feynman, Andrej Karpathy — to judge release readiness. Each seat returns an independent SHIP / CONDITIONAL / BLOCK verdict; any seat can veto a release by naming a release-critical defect. Trigger on "/cabinet", "convene the cabinet", "cabinet this", or any release/tag/v-number gate (e.g. "ready for v1.0.0?") after the build/review/ship stack has run. This is the last gate before a tagged release — it does not replace /review, /plan-eng-review, or /ship; it ratifies them.
Use as reference guide for strangler pattern implementation. Provides patterns and best practices for legacy migrations.
Drag Reduction System — ambient PreToolUse tripwire that fires deterministically on boundary violations. Not a slash command. Hooks into every tool call automatically.
Adversarial stress test of an approved P10 plan. Fires after Opus approval, before any file is touched. One Sonnet agent with one job — find how this plan fails.
| name | strangler-pattern-guide |
| description | Use as reference guide for strangler pattern implementation. Provides patterns and best practices for legacy migrations. |
| version | 1.0.0 |
| metadata | {"mcpmarket-version":"1.0.0"} |
Purpose: Strategic guide for implementing the strangler pattern to migrate controllers from express-web-api to actions.api.
Related Documents:
Use strangler pattern for:
Skip strangler pattern for:
// Express-Web-API Controller - Generic pattern
public async Task<HttpResponseMessage> YourControllerMethod([FromBody] YourRequestModel requestModel)
{
var tenant = Features.ResolveTenant(Request.Headers);
if (await FeatureResolverSingleton.GetIsFeatureEnabledAsync(Features.YourFeatureFlag, tenant))
return CreateResponseMessage(await strangledService.Value.YourMethod(requestModel));
return CreateResponseMessage(legacyService.Value.YourMethod(requestModel, EyeShareToken));
}
Real Implementation Example (WorkflowController):
// Express-Web-API Controller - Real example from WorkflowController
public async Task<HttpResponseMessage> StartWorkflowExecution([FromBody] EyeShareWorkflowDesignerModel workflowDesigner)
{
var tenant = Features.ResolveTenant(Request.Headers);
if (await FeatureResolverSingleton.GetIsFeatureEnabledAsync(Features.WorkflowStrangle, tenant))
return CreateResponseMessage(await strangledService.Value.StartWorkflowExecution(workflowDesigner));
return CreateResponseMessage(legacyService.Value.StartWorkflowExecution(workflowDesigner, EyeShareToken));
}
// Generic pattern for any controller
public class YourController : ApiBaseController
{
private Lazy<YourLegacyService> legacyService;
private Lazy<YourStrangledService> strangledService; // Handles actions.api communication
public YourController()
{
legacyService = new Lazy<YourLegacyService>(() => {
var token = TokenManager.GetTokenInfo();
return new YourLegacyService(token, new DalService(token));
});
strangledService = new Lazy<YourStrangledService>(() => new YourStrangledService(ControllerContext));
}
}
Real Implementation Example (WorkflowController):
public class WorkflowController : ApiBaseController
{
private Lazy<EyeShareWorkflowService> legacyService;
private Lazy<WorkflowService> strangledService; // Handles actions.api communication
public WorkflowController()
{
legacyService = new Lazy<EyeShareWorkflowService>(() => {
var token = TokenManager.GetTokenInfo();
return new EyeShareWorkflowService(token, new DalService(token));
});
strangledService = new Lazy<WorkflowService>(() => new WorkflowService(ControllerContext));
}
}
// Actions.API - Generic pattern (no strangler terminology)
app.MapPost("/api/YourController/yourMethod",
async (YourRequest request, IMediator mediator) =>
{
var result = await mediator.Send(request);
return Results.Ok(result);
}).RequireAuthorization();
// Generic request/response models
public record YourRequest : IRequest<YourResponse>
{
public YourDataModel Data { get; init; }
}
public class YourRequestHandler : IRequestHandler<YourRequest, YourResponse>
{
public async Task<YourResponse> Handle(YourRequest request, CancellationToken cancellationToken)
{
return await _service.YourMethodAsync(request.Data);
}
}
Real Implementation Example (WorkflowController):
// Actions.API - No strangler terminology
app.MapPost("/api/Workflow/startExecution",
async (StartWorkflowExecutionRequest request, IMediator mediator) =>
{
var result = await mediator.Send(request);
return Results.Ok(result);
}).RequireAuthorization();
public record StartWorkflowExecutionRequest : IRequest<WorkflowExecutionResponse>
{
public EyeShareWorkflowDesignerModel WorkflowDesigner { get; init; }
}
public class StartWorkflowExecutionHandler : IRequestHandler<StartWorkflowExecutionRequest, WorkflowExecutionResponse>
{
public async Task<WorkflowExecutionResponse> Handle(StartWorkflowExecutionRequest request, CancellationToken cancellationToken)
{
return await _service.StartWorkflowExecutionAsync(request.WorkflowDesigner);
}
}
The express-web-api uses a specific authentication flow that differs from standard OAuth2:
# Authenticate to express-web-api
$authResponse = Invoke-RestMethod -Uri "http://localhost:52928/api/Auth/token" -Method Post -Body @{
grant_type = "password"
client_id = "<YOUR_CLIENT_ID>"
username = "<YOUR_USERNAME>"
password = "<YOUR_PASSWORD>"
} -ContentType "application/x-www-form-urlencoded"
# Extract token - IMPORTANT: uses 'token' field, not 'access_token'
$token = $authResponse.token
# Use in API calls
$headers = @{
'Authorization' = "Bearer $token"
'Content-Type' = 'application/json'
}
# Test endpoint
$response = Invoke-RestMethod -Uri "http://localhost:52928/Api/{controller}/{method}" -Method Get -Headers $headers
Key Authentication Details:
http://localhost:52928/api/Auth/tokenapplication/x-www-form-urlencodedtoken (not access_token)Bearer {token}✅ Feature flag routing works between legacy and new systems ✅ Response behavior identical to captured baseline ✅ All tests pass in actions.api integration suite ✅ No regressions in existing functionality ✅ Performance maintains or exceeds baseline ✅ Rollback capability tested and verified
For Implementation:
For Validation:
For Process:
Before generating a migration plan, query /vault/signal to load active governance verdicts.
Three branches — handle all three before writing the plan:
| Endpoint result | Meaning | Plan stamp |
|---|---|---|
| ECONNREFUSED (port closed) | Server not running — cold start | cold-start |
200 + [] (empty array) | Server up, no active signals | cold-start |
| 200 + non-empty array | Active signals loaded | loop-informed |
Cold-start — proceed with plan generation. Do NOT claim loop influence. Stamp the plan header:
session_verdicts: []
loop_informed: false
Loop-informed — the plan MUST cite every consumed verdict ID as structured output in the plan header:
session_verdicts: ["adr-0005-ordercontroller-auth-extraction"]
loop_informed: true
After plan generation, run checkProvenance(citedIds, sessionIds):
ok: true — provenance verified; continue to tiered vetook: false — cited IDs not in session response; plan is rejected (do not write to vault)Tiered veto (active — runs after provenance passes):
Call the score_confidence MCP tool (POST to the MCP server) with { records, now } where records is the full array returned by /vault/signal and now is today's date in YYYY-MM-DD format. This is a deterministic tool call — not prose reasoning.
| Tier | Condition | Action |
|---|---|---|
HIGH | ≥2 distinct in-date records, all patterns known, Jaccard≥0.5 | Proceed — write plan to vault automatically |
LOW | Any clause fails (novel pattern, expired record, count < 2, Jaccard < 0.5) | HALT — do not write plan; surface disqualifiers to user and request a ruling via /council |
When tier is LOW, output the disqualifiers verbatim:
TIERED VETO — LOW confidence. Plan write halted.
Disqualifiers:
- <disqualifier 1>
- <disqualifier 2>
Run /council to issue a fresh ruling before retrying.
When tier is HIGH, stamp the plan header with confidence_tier: HIGH before vault write.