You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A comprehensive vulnerability hunt (4 parallel scanners + an adversarial work-review).
9 confirmed fixes + a plural false-negative caught at the commit-gate:
- resolveWorker: the never-down sensitive gate could be breached by a mis-cased / typo'd
floor (indexOf -1 -> Math.max(-1,0)=0 collapsed a sensitive task to the cheapest tier);
now case-normalized + fail-safe (an unrecognized floor returns null, never the floor).
- Non-English sensitive prompts lost the deterministic flag (English-only keywords): the
Step-2 HARD GATE now names the model the sensitive-gate authority for non-English, and
the conductor injects a generic non-Latin-script nudge.
- mode + per-domain disableRouting were documented but dead; now wired (the sensitive
HARD GATE overrides mode).
- grade matcher over-matched (token->tokenizer) then under-matched: fixed via a stem (*)
vs whole-word convention, with the common plurals (tokens/secrets/passwords/sessions/
payments/deadlocks/mutexes) listed so a plural no longer escapes the never-down flag.
- modelTiers pin doc cheap -> low; project config now anchors at the git root (not cwd);
strict validateRanking (rejects array/{}/missing-key/non-array/all-empty/complete-truthy);
verify.mjs uses the shared stripJsonc; grade() degrades on null input.
110 tests, verify PASS.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: .claude-plugin/plugin.json
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
{
2
2
"name": "coaltipple",
3
-
"version": "1.0.10",
3
+
"version": "1.0.11",
4
4
"description": "CoalTipple — model/effort router for Claude Code. Delegates a task you CAN do but is large+cheap DOWN to a lower tier to save tokens; escalates a task beyond the current tier UP for quality. Two-knob routing (tier × effort, effort-before-tier), introspection-first model classification, a validity-gated ranking Lock that never routes on broken state, and git-optional damage control. Advise-only Phoenix-pure hook; the model performs the routing.",
Copy file name to clipboardExpand all lines: CHANGELOG.md
+20Lines changed: 20 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,6 +2,26 @@
2
2
3
3
All notable changes to CoalTipple are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow SemVer (the canonical version lives in `.claude-plugin/plugin.json`).
4
4
5
+
## [1.0.11] - 2026-06-18
6
+
7
+
A comprehensive vulnerability hunt (4 parallel scanners + an adversarial work-review pass) — safety-gate, routing-correctness, config-honesty, and worldwide-language fixes.
8
+
9
+
### Fixed
10
+
11
+
-**The never-down sensitive gate could be breached by a mis-cased / typo'd floor.**`resolveWorker` (classify.mjs) matched `floorTier` case-sensitively, so `'Heavy'` or a typo fell through `indexOf → -1 → Math.max(-1,0) = 0` and collapsed a SENSITIVE task to the *cheapest* tier under a limit-hit. Now case-normalized + fail-safe: an unrecognized floor returns `null` (hand back), never the floor.
12
+
-**Non-English sensitive prompts lost the deterministic safety flag.** The keyword grader + the conductor hint match English literals only, so a Thai/CJK/Arabic prompt meaning "scan for bugs" / "constant-time compare" fired no flag — the "keyword is the gate" backstop silently vanished. The Step-2 HARD GATE now states the model is the sensitive-gate authority for non-English (grade by MEANING), and the conductor injects a generic non-English nudge on non-Latin script. (The model layer has been multilingual since 1.0.9; this closes the *deterministic* backstop.)
13
+
-**`mode` and per-domain `disableRouting` were documented but dead.**`mode:"off"` still routed; `disableRouting:["coding"]` did nothing. Both are now wired (SKILL + conductor): `mode` constrains direction (`auto`/`delegation`/`escalation`/`off`, the sensitive HARD GATE overriding it), and per-domain disable is honored.
14
+
-**The grade keyword matcher over-matched, then a fix under-matched.** A missing trailing word-boundary let `token`→"tokenizer", `crypto`→"cryptocurrency" wrongly grade sensitive. Fixed with a stem (`*`) vs whole-word convention — and the common plurals (`tokens`/`secrets`/`passwords`/`sessions`/`payments`/`deadlocks`/`mutexes`) are now listed so a plural no longer escapes the never-down flag.
15
+
-**The `modelTiers` pin doc named a non-existent tier.** The `--help`/schema text said `cheap` (silently dropped by `applyPins`); the real cheapest tier is `low`.
16
+
-**Project config could be read from the wrong directory.**`config-load.mjs` resolved from `process.cwd()` while the conductor + configure used the git root — a subdir cwd read a different file. All three now anchor at the git root (git stays optional).
17
+
-**`validateRanking` blessed broken rankings.** An array, `{}`, a missing key, or `complete` merely truthy passed the Lock, letting `resolveWorker` return `null` for every tier (routing dead while the Lock read green). Now strict: every tier present + an array, `complete === true`, ≥1 non-empty.
18
+
-**`verify.mjs` used a third, divergent JSONC parser** instead of the shared `stripJsonc` — the gate now validates with the same parser runtime uses.
19
+
-**`grade()` threw on null input** (`{files:null}`, etc.); a boundary authority now degrades instead of crashing.
20
+
21
+
### Added
22
+
23
+
- Regression tests across every fix — the case-insensitive/fail-safe floor, the non-English nudge, `mode:"off"`, the stem/whole-word + plural matching (A/B both directions), strict `validateRanking`, the git-root config anchor, and null-input degradation. 110 tests.
24
+
5
25
## [1.0.10] - 2026-06-18
6
26
7
27
Keyword/config-precision hardenings, caught by the 3-sub review pass.
// The contract is model-facing English (the model reads it fine); the language
73
107
// LEVER is a directive telling the model what language to PRODUCE for the user —
74
108
// the same approach CoalMine's conductor uses. cfg.language drives it, so the
@@ -86,6 +120,7 @@ function contract(cfg) {
86
120
'- DELEGATE-DOWN a task you can do but is large + cheap, to a lower tier — ONLY with a compact task-contract (goal+constraints+interface+done) AND verify the returned output on merge. Skip it for small tasks (spawn overhead beats the saving).',
87
121
'- ESCALATE-UP a task beyond the current tier for quality. Workers are leaves by policy (routing stays depth-0): give each a bounded task-contract so it RETURNS rather than spawning its own workers; a worker that fails RETURNS its result and the MAIN re-routes.',
88
122
'- Grade by the deterministic rubric, not a model self-assessment. Opus is scarce: cheapest lever first - raise effort, then a stronger same-tier version (e.g. Opus 4.6 -> 4.8), before escalating the tier.',
123
+
'- mode (.coaltipple.json, default auto): auto = route both directions per grade; delegation = delegate-down only (escalate-up suppressed, a budget-saving mode); escalation = escalate-up only (delegate-down suppressed, a quality mode); off = routing off, do it yourself. The sensitive HARD GATE overrides mode (sensitive is still never-down and may always escalate up).',
89
124
'- Honor qualityBar (.coaltipple.json, 0-100, default 60): a result must clear it or climb the model ladder — start at the grade floor, verify vs the contract done-criteria by domain-appropriate means (code: tests/build; text: completeness; research: sourced claims), climb one rung if short, jump to the top tier if far below or out of attempts. 0 = anything passes (cheapest); 100 = climb until best.',
90
125
langLine(cfg),
91
126
'- Consent + token spend: honor .coaltipple.json; never silently fan out costly work.',
consthint=h ? ` Complexity hint: grade ${h.grade} (${h.why}) -> start tier "${h.tier}"; fold into the grade, then the result must clear qualityBar or routing climbs the ladder.` : '';
112
-
process.stdout.write(`[CoalTipple] Route BEFORE acting on this prompt: apply the coaltipple routing contract (SKILL.md) -- grade the task, then delegate-down (large + cheap), escalate-up (beyond this tier), or keep-on-self, per the rubric. Routing actuates on Claude Code only.${hint}`);
157
+
// The English HOT-keyword hint cannot fire on a non-English prompt; add ONE generic
158
+
// deterministic nudge so the sensitive-gate backstop is not silently lost there.
159
+
// Complements (never replaces) the English hint above.
160
+
constnonEnglish=hasNonLatinScript(prompt) ? ' Non-English prompt -- grade by MEANING and apply the sensitive-gate by intent; the English keyword flags will not fire.' : '';
161
+
process.stdout.write(`[CoalTipple] Route BEFORE acting on this prompt: apply the coaltipple routing contract (SKILL.md) -- grade the task, then delegate-down (large + cheap), escalate-up (beyond this tier), or keep-on-self, per the rubric. Routing actuates on Claude Code only.${hint}${nonEnglish}`);
113
162
return;
114
163
}
115
164
// SessionStart (and any non-prompt event) -> inject the routing contract.
Copy file name to clipboardExpand all lines: plugin/.claude-plugin/plugin.json
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
{
2
2
"name": "coaltipple",
3
-
"version": "1.0.10",
3
+
"version": "1.0.11",
4
4
"description": "CoalTipple — model/effort router for Claude Code. Delegates a task you CAN do but is large+cheap DOWN to a lower tier to save tokens; escalates a task beyond the current tier UP for quality. Two-knob routing (tier × effort, effort-before-tier), introspection-first model classification, a validity-gated ranking Lock that never routes on broken state, and git-optional damage control. Advise-only Phoenix-pure hook; the model performs the routing.",
0 commit comments