Neue Skills, Referenzen & OpenWiki-Doku integriert
Umfangreiche Erweiterung der Skill-Bibliothek: Neue Skills für Humanisierung (Englisch/PT-BR), Design-Validierung, AI-SEO und Coolify-Deployment inkl. Regelwerke, Presets, Pattern-Referenzen, Testfälle und Automatisierungsskripte. Zusätzliche Skills für Revenue-Centric Design, Pier Cloud, OKF, Lebenslauf- und LinkedIn-Optimierung sowie zahlreiche Referenzdateien, Checklisten und YAML/JSON/Markdown-Templates. Einführung einer vollständigen OpenWiki-Dokumentation mit Architektur-, Domain- und Workflow-Beschreibungen, zentralem Index und automatisierten Updates. Modularer Aufbau, restriktive Lizenzen und umfassende Qualitäts- und Evaluationsmechanismen für alle neuen Inhalte.
This commit is contained in:
106
.github/skills/revenue-centric-design/scripts/check_usage_boundary.py
vendored
Normal file
106
.github/skills/revenue-centric-design/scripts/check_usage_boundary.py
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Usage-boundary guard: block RCD use on gambling/betting/casino products (LICENSE clause 2).
|
||||
|
||||
Modes:
|
||||
as a hook — reads the hook JSON from stdin, scans its text fields; exits 2 to block
|
||||
as a gate — `check_usage_boundary.py [path ...]` scans project files (README*, package.json,
|
||||
*.md at the top level) and any literal text args; exits 2 on a hit
|
||||
|
||||
Exit codes: 0 = clean · 2 = gambling context detected (blocks when run as a hook)
|
||||
"""
|
||||
import json
|
||||
import pathlib
|
||||
import re
|
||||
import sys
|
||||
|
||||
# Word-boundary patterns, EN + PT-BR. Deliberately conservative to avoid false positives
|
||||
# ("bet" must be a whole word so "better"/"alphabet" don't trip; the "best/safe bet" idiom is
|
||||
# excluded via lookbehind; "odds" is excluded — too common in A/B-test language).
|
||||
TERMS = [
|
||||
r"gambling", r"casino[s]?", r"cassino[s]?", r"bookmaker[s]?", r"sportsbook[s]?",
|
||||
r"(?<!best\s)(?<!safe\s)bet[s]?", r"betting", r"aposta[s]?", r"apostador(es)?",
|
||||
r"jogo[s]? de azar", r"ca[cç]a[- ]n[ií]quel", r"slot machine[s]?", r"roulette", r"roleta",
|
||||
r"blackjack", r"poker", r"p[oô]quer", r"jackpot", r"wager(s|ing)?", r"loot ?box(es)?",
|
||||
r"real[- ]money gam(e|ing)", r"igaming", r"raspadinha[s]?",
|
||||
]
|
||||
PATTERN = re.compile(r"\b(" + "|".join(TERMS) + r")\b", re.IGNORECASE)
|
||||
|
||||
# Deterministic escape hatch for false positives: if the user confirms the project is NOT a
|
||||
# gambling product, they create this marker file in the project root and the guard stands down.
|
||||
MARKER = ".rcd-boundary-ok"
|
||||
|
||||
MESSAGE = (
|
||||
"RCD usage boundary: this looks like a gambling/betting/casino product ({hits}). "
|
||||
"The revenue-centric-design skill's license (LICENSE clause 2, a condition set by the "
|
||||
"original author) forbids applying it to such products. Stop using this skill for this "
|
||||
"task and tell the user why. If this is a false positive (e.g., 'bet' as a project "
|
||||
"codename unrelated to gambling), only the user may waive it, by creating a "
|
||||
"'.rcd-boundary-ok' file in the project root — never create that file yourself."
|
||||
)
|
||||
|
||||
|
||||
def scan(text: str):
|
||||
return sorted({m.group(0).lower() for m in PATTERN.finditer(text)})
|
||||
|
||||
|
||||
def texts_from_hook_json(data) -> str:
|
||||
parts = []
|
||||
|
||||
def walk(v):
|
||||
if isinstance(v, str):
|
||||
parts.append(v)
|
||||
elif isinstance(v, dict):
|
||||
for x in v.values():
|
||||
walk(x)
|
||||
elif isinstance(v, list):
|
||||
for x in v:
|
||||
walk(x)
|
||||
|
||||
walk(data)
|
||||
return "\n".join(parts)
|
||||
|
||||
|
||||
def project_sample(root: pathlib.Path) -> str:
|
||||
parts = []
|
||||
for pat in ("README*", "*.md", "package.json", "pyproject.toml", "composer.json"):
|
||||
for f in root.glob(pat):
|
||||
if f.is_file() and f.stat().st_size < 512_000:
|
||||
try:
|
||||
parts.append(f.read_text(errors="ignore"))
|
||||
except OSError:
|
||||
pass
|
||||
return "\n".join(parts)
|
||||
|
||||
|
||||
def main():
|
||||
if pathlib.Path(MARKER).exists():
|
||||
print(f"usage boundary: waived by {MARKER}")
|
||||
return
|
||||
corpus = []
|
||||
if not sys.stdin.isatty():
|
||||
raw = sys.stdin.read().strip()
|
||||
if raw:
|
||||
try:
|
||||
corpus.append(texts_from_hook_json(json.loads(raw)))
|
||||
except json.JSONDecodeError:
|
||||
corpus.append(raw)
|
||||
for arg in sys.argv[1:]:
|
||||
p = pathlib.Path(arg)
|
||||
if p.is_dir():
|
||||
corpus.append(project_sample(p))
|
||||
elif p.is_file():
|
||||
corpus.append(p.read_text(errors="ignore"))
|
||||
else:
|
||||
corpus.append(arg)
|
||||
if not corpus:
|
||||
corpus.append(project_sample(pathlib.Path.cwd()))
|
||||
|
||||
hits = scan("\n".join(corpus))
|
||||
if hits:
|
||||
print(MESSAGE.format(hits=", ".join(hits)), file=sys.stderr)
|
||||
sys.exit(2)
|
||||
print("usage boundary: clean")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
116
.github/skills/revenue-centric-design/scripts/revenue_math.py
vendored
Normal file
116
.github/skills/revenue-centric-design/scripts/revenue_math.py
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Revenue math from the RCD principles — run these instead of estimating.
|
||||
|
||||
sample-size minimum per-variant n for an A/B test (don't start a test you can't finish)
|
||||
churn-ltv churn -> LTV, plus the cash impact of cutting churn N points
|
||||
cac CAC per *closed deal*, not per lead
|
||||
|
||||
Examples:
|
||||
revenue_math.py sample-size --baseline 0.03 --mde 0.20
|
||||
revenue_math.py churn-ltv --arpu 120 --churn 0.25 --new-churn 0.20 --users 1000
|
||||
revenue_math.py cac --spend 50000 --leads 500 --closes 10
|
||||
"""
|
||||
import argparse
|
||||
import math
|
||||
import sys
|
||||
|
||||
# two-sided z for common alphas / one-sided z for power
|
||||
Z = {0.80: 0.8416, 0.90: 1.2816, 0.95: 1.6449, 0.975: 1.9600, 0.995: 2.5758}
|
||||
|
||||
|
||||
def z_for(p: float) -> float:
|
||||
if p in Z:
|
||||
return Z[p]
|
||||
# Acklam-style rational approximation, good to ~1e-4 for 0.5 < p < 1
|
||||
t = math.sqrt(-2.0 * math.log(1.0 - p))
|
||||
return t - (2.30753 + 0.27061 * t) / (1.0 + 0.99229 * t + 0.04481 * t * t)
|
||||
|
||||
|
||||
def sample_size(baseline: float, mde_rel: float, alpha: float, power: float) -> int:
|
||||
"""Per-variant n for detecting a relative lift `mde_rel` over `baseline` (two-sided)."""
|
||||
p1 = baseline
|
||||
p2 = baseline * (1.0 + mde_rel)
|
||||
if not (0 < p1 < 1 and 0 < p2 < 1):
|
||||
sys.exit("baseline and baseline*(1+mde) must be within (0, 1)")
|
||||
za = z_for(1.0 - alpha / 2.0)
|
||||
zb = z_for(power)
|
||||
pbar = (p1 + p2) / 2.0
|
||||
num = (za * math.sqrt(2 * pbar * (1 - pbar)) + zb * math.sqrt(p1 * (1 - p1) + p2 * (1 - p2))) ** 2
|
||||
return math.ceil(num / (p2 - p1) ** 2)
|
||||
|
||||
|
||||
def cmd_sample_size(a):
|
||||
n = sample_size(a.baseline, a.mde, a.alpha, a.power)
|
||||
print(f"per-variant sample size: {n:,} (total for A/B: {2 * n:,})")
|
||||
print(f"detects {a.baseline:.2%} -> {a.baseline * (1 + a.mde):.2%} "
|
||||
f"(relative +{a.mde:.0%}) at alpha={a.alpha}, power={a.power}")
|
||||
if a.traffic:
|
||||
weeks = 2 * n / (a.traffic / 4.345) # weekly visitors from monthly
|
||||
print(f"at {a.traffic:,.0f} visitors/month: ~{weeks:.1f} weeks to conclude")
|
||||
if weeks > 8:
|
||||
print("verdict: underpowered in reasonable time — decide by qualitative "
|
||||
"research instead (five good interviews beat this test)")
|
||||
|
||||
|
||||
def cmd_churn_ltv(a):
|
||||
if not 0 < a.churn < 1:
|
||||
sys.exit("churn must be a fraction, e.g. 0.25 for 25%/month")
|
||||
ltv = a.arpu / a.churn
|
||||
print(f"LTV at {a.churn:.1%} monthly churn: {ltv:,.2f} (avg lifetime {1 / a.churn:.1f} months)")
|
||||
if a.users:
|
||||
replace = a.users * a.churn
|
||||
print(f"treadmill: {replace:,.0f} new users/month just to stay flat at {a.users:,} users")
|
||||
if a.new_churn:
|
||||
new_ltv = a.arpu / a.new_churn
|
||||
print(f"LTV at {a.new_churn:.1%}: {new_ltv:,.2f} (delta per user: {new_ltv - ltv:+,.2f})")
|
||||
if a.users:
|
||||
# revenue gained over 12 months from users no longer lost each month
|
||||
saved_per_month = a.users * (a.churn - a.new_churn)
|
||||
annual = sum(saved_per_month * a.arpu * (12 - m) for m in range(12)) / 12
|
||||
print(f"~{annual:,.0f}/year in retained revenue at {a.users:,} users, "
|
||||
f"ARPU {a.arpu:,.0f} — no price change, no extra acquisition")
|
||||
|
||||
|
||||
def cmd_cac(a):
|
||||
cpl = a.spend / a.leads
|
||||
closes = a.closes if a.closes else a.leads * a.close_rate
|
||||
if closes <= 0:
|
||||
sys.exit("need --closes or a positive --close-rate")
|
||||
print(f"cost per lead: {cpl:,.2f}")
|
||||
print(f"CAC per closed deal: {a.spend / closes:,.2f} ({closes:.0f} closes from {a.leads:,} leads)")
|
||||
print("lever: filter on the landing page (specific copy, visible pricing, qualification "
|
||||
"question) — fewer, better leads lowers this number at the same spend")
|
||||
|
||||
|
||||
def main():
|
||||
p = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
sub = p.add_subparsers(dest="cmd", required=True)
|
||||
|
||||
s = sub.add_parser("sample-size", help="minimum per-variant n for an A/B test")
|
||||
s.add_argument("--baseline", type=float, required=True, help="current conversion rate, e.g. 0.03")
|
||||
s.add_argument("--mde", type=float, required=True, help="relative lift to detect, e.g. 0.20 for +20%%")
|
||||
s.add_argument("--alpha", type=float, default=0.05)
|
||||
s.add_argument("--power", type=float, default=0.80)
|
||||
s.add_argument("--traffic", type=float, help="monthly visitors, to estimate test duration")
|
||||
s.set_defaults(fn=cmd_sample_size)
|
||||
|
||||
c = sub.add_parser("churn-ltv", help="churn -> LTV and the cash value of cutting churn")
|
||||
c.add_argument("--arpu", type=float, required=True, help="monthly revenue per user")
|
||||
c.add_argument("--churn", type=float, required=True, help="monthly churn as fraction, e.g. 0.25")
|
||||
c.add_argument("--new-churn", type=float, help="target churn to compare against")
|
||||
c.add_argument("--users", type=int, help="current paying users, for cash impact")
|
||||
c.set_defaults(fn=cmd_churn_ltv)
|
||||
|
||||
k = sub.add_parser("cac", help="CAC per closed deal, not per lead")
|
||||
k.add_argument("--spend", type=float, required=True)
|
||||
k.add_argument("--leads", type=float, required=True)
|
||||
k.add_argument("--closes", type=float, help="deals actually closed")
|
||||
k.add_argument("--close-rate", type=float, help="fraction of leads that close, e.g. 0.02")
|
||||
k.set_defaults(fn=cmd_cac)
|
||||
|
||||
a = p.parse_args()
|
||||
a.fn(a)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user