mirror of
https://github.com/garrytan/gstack.git
synced 2026-08-31 02:10:51 +02:00
feat(review): simplification specialist — advisory over-engineering lens with ponytail's tag vocabulary
New 8th Review Army specialist (DIFF_LINES > 100, --simplification force flag) hunting unrequested STRUCTURE only: delete/stdlib/native/speculative/shrink closed tags, one-line findings, lines_removable field. speculative: replaces ponytail's yagni: tag — we import the lens, not the posture; coverage stays sacred (Completeness Gaps owns it, suppressions inlined, shrink needs >=5 lines). Advisory carve-out in the merge step: advisory findings are excluded from quality_score and the findings-count header, render with an [ADVISORY] label, and are ASK-only in Fix-First. Zero-findings case prints the lens-scoped 'Simplification: lean already — nothing to cut.' from the PARENT (the specialist keeps the exact NO FINDINGS contract); with findings, the parent prints 'net: -N lines possible' summed from lines_removable. Tests: static pins for the carve-out + early-out contract (gen-skill-docs), two periodic e2e cases with planted fixtures — activation (over-build traps: hand-rolled Intl, one-impl abstract, dead config) and false-flag precision (a lean ETHOS 'choose A' diff must yield NO FINDINGS). Inspired by dietrichgebert/ponytail's /ponytail-review. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
848973007c
commit
cbb4d35792
+28
@@ -0,0 +1,28 @@
|
||||
// Lean-and-complete fixture: the false-flag precision case for the
|
||||
// simplification specialist. This is an ETHOS "choose A" diff — small,
|
||||
// covers the error path and edge cases, carries its own check. There is
|
||||
// nothing here to cut; a correct simplification pass returns NO FINDINGS.
|
||||
|
||||
function parsePort(value) {
|
||||
if (value === null || value === undefined || value === '') {
|
||||
throw new Error(`parsePort: missing value`);
|
||||
}
|
||||
const port = Number(value);
|
||||
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
||||
throw new Error(`parsePort: expected integer in 1-65535, got ${JSON.stringify(value)}`);
|
||||
}
|
||||
return port;
|
||||
}
|
||||
|
||||
// Self-check: the smallest thing that fails if the logic breaks.
|
||||
function testParsePort() {
|
||||
const assert = require('node:assert');
|
||||
assert.strictEqual(parsePort('8080'), 8080);
|
||||
assert.strictEqual(parsePort(443), 443);
|
||||
assert.throws(() => parsePort(''), /missing value/);
|
||||
assert.throws(() => parsePort('0'), /1-65535/);
|
||||
assert.throws(() => parsePort('65536'), /1-65535/);
|
||||
assert.throws(() => parsePort('abc'), /1-65535/);
|
||||
}
|
||||
|
||||
module.exports = { parsePort, testParsePort };
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
// Planted over-engineering fixture for the simplification specialist.
|
||||
// Three deliberate invitations: a hand-rolled date formatter the platform
|
||||
// ships (native:), an abstract layer with exactly one implementation
|
||||
// (speculative:), and a config block nothing reads (delete:).
|
||||
|
||||
// INVITATION 1 (native:): Intl.DateTimeFormat does all of this in one line.
|
||||
class DateFormatter {
|
||||
constructor(locale) {
|
||||
this.locale = locale || 'en-US';
|
||||
this.monthNames = [
|
||||
'January', 'February', 'March', 'April', 'May', 'June',
|
||||
'July', 'August', 'September', 'October', 'November', 'December',
|
||||
];
|
||||
}
|
||||
|
||||
pad(n) {
|
||||
return n < 10 ? '0' + n : String(n);
|
||||
}
|
||||
|
||||
formatLong(date) {
|
||||
const month = this.monthNames[date.getMonth()];
|
||||
return `${month} ${date.getDate()}, ${date.getFullYear()}`;
|
||||
}
|
||||
|
||||
formatShort(date) {
|
||||
return `${this.pad(date.getMonth() + 1)}/${this.pad(date.getDate())}/${date.getFullYear()}`;
|
||||
}
|
||||
|
||||
formatTime(date) {
|
||||
const hours = date.getHours() % 12 || 12;
|
||||
const suffix = date.getHours() >= 12 ? 'PM' : 'AM';
|
||||
return `${hours}:${this.pad(date.getMinutes())} ${suffix}`;
|
||||
}
|
||||
}
|
||||
|
||||
// INVITATION 2 (speculative:): abstract base with a single implementation.
|
||||
class AbstractItemStore {
|
||||
save(item) {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
load(id) {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
}
|
||||
|
||||
class MemoryItemStore extends AbstractItemStore {
|
||||
constructor() {
|
||||
super();
|
||||
this.items = new Map();
|
||||
}
|
||||
save(item) {
|
||||
this.items.set(item.id, item);
|
||||
return item;
|
||||
}
|
||||
load(id) {
|
||||
return this.items.get(id) || null;
|
||||
}
|
||||
}
|
||||
|
||||
// INVITATION 3 (delete:): configuration nothing in this file (or repo) reads.
|
||||
const FORMATTER_CONFIG = {
|
||||
enableLegacyMode: false,
|
||||
cacheSize: 128,
|
||||
strictParsing: true,
|
||||
fallbackLocale: 'en-GB',
|
||||
};
|
||||
|
||||
module.exports = { DateFormatter, MemoryItemStore, FORMATTER_CONFIG };
|
||||
Reference in New Issue
Block a user