CLI/MCP: Listing Readiness sözleşmesini konuş - #133
semihbugrasezer wants to merge 1 commit into
Conversation
- analyze/optimize output schemas now require scoringVersion, scoreType, overallScore, evaluatedAt, evidence and limitations; seoScore is marked deprecated and kept only as a compatibility alias - weak points require ruleId, explanation and a source, and the formatter renders each finding as "reason -> fix" with a link to its Etsy source - score line reads "Listing Readiness: N/100 - rubric <version>" - README and the seerxo-etsy-seo skill say what the score is and is not Verified: 104/104 tests, node --check clean, package validation passed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017onzZmmB9gTutoAaCgPz9u
| assert.ok(text.includes('Listing Readiness')); | ||
| assert.ok(!text.includes('SEO Score')); | ||
| assert.ok(text.includes('etsy-guidance-2026-04-27')); | ||
| assert.ok(text.includes('https://www.etsy.com/seller-handbook/article/382774281517')); |
There was a problem hiding this comment.
3 issues found across 5 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/mcp/tools.js">
<violation number="1" location="src/mcp/tools.js:89">
P1: When the backend returns the canonical readiness fields without the legacy alias, MCP clients reject the response because `seoScore` is still required. Remove `seoScore` from `required`; `deprecated` does not make a required property optional.</violation>
</file>
<file name="src/formatters/listing.js">
<violation number="1" location="src/formatters/listing.js:17">
P3: When neither `overallScore` nor `seoScore` is present, `score` falls back to the string `'n/a'`, but the line unconditionally appends `/100`, so it renders `Listing Readiness: n/a/100`. Only append `/100` when the score is numeric.</violation>
</file>
<file name="tests/listing-tools.test.js">
<violation number="1" location="tests/listing-tools.test.js:188">
P2: Assert the complete rendered `[source](...)` fragment instead of searching for the URL as an arbitrary substring. This assertion can pass when the Etsy URL appears inside another URL or unrelated text without verifying the link target.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| }, | ||
| }, | ||
| required: ['seoScore', 'subScores', 'weakPoints', 'missingKeywords', 'tagUtilization'], | ||
| required: ['scoringVersion', 'scoreType', 'overallScore', 'evaluatedAt', 'evidence', 'limitations', 'seoScore', 'subScores', 'weakPoints', 'missingKeywords', 'tagUtilization'], |
There was a problem hiding this comment.
P1: When the backend returns the canonical readiness fields without the legacy alias, MCP clients reject the response because seoScore is still required. Remove seoScore from required; deprecated does not make a required property optional.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/mcp/tools.js, line 89:
<comment>When the backend returns the canonical readiness fields without the legacy alias, MCP clients reject the response because `seoScore` is still required. Remove `seoScore` from `required`; `deprecated` does not make a required property optional.</comment>
<file context>
@@ -66,15 +86,15 @@ const AUDIT_OUTPUT_SCHEMA = {
},
},
- required: ['seoScore', 'subScores', 'weakPoints', 'missingKeywords', 'tagUtilization'],
+ required: ['scoringVersion', 'scoreType', 'overallScore', 'evaluatedAt', 'evidence', 'limitations', 'seoScore', 'subScores', 'weakPoints', 'missingKeywords', 'tagUtilization'],
};
</file context>
| required: ['scoringVersion', 'scoreType', 'overallScore', 'evaluatedAt', 'evidence', 'limitations', 'seoScore', 'subScores', 'weakPoints', 'missingKeywords', 'tagUtilization'], | |
| required: ['scoringVersion', 'scoreType', 'overallScore', 'evaluatedAt', 'evidence', 'limitations', 'subScores', 'weakPoints', 'missingKeywords', 'tagUtilization'], |
| assert.ok(text.includes('Listing Readiness')); | ||
| assert.ok(!text.includes('SEO Score')); | ||
| assert.ok(text.includes('etsy-guidance-2026-04-27')); | ||
| assert.ok(text.includes('https://www.etsy.com/seller-handbook/article/382774281517')); |
There was a problem hiding this comment.
P2: Assert the complete rendered [source](...) fragment instead of searching for the URL as an arbitrary substring. This assertion can pass when the Etsy URL appears inside another URL or unrelated text without verifying the link target.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At tests/listing-tools.test.js, line 188:
<comment>Assert the complete rendered `[source](...)` fragment instead of searching for the URL as an arbitrary substring. This assertion can pass when the Etsy URL appears inside another URL or unrelated text without verifying the link target.</comment>
<file context>
@@ -164,6 +182,11 @@ describe('formatters', () => {
+ assert.ok(text.includes('Listing Readiness'));
+ assert.ok(!text.includes('SEO Score'));
+ assert.ok(text.includes('etsy-guidance-2026-04-27'));
+ assert.ok(text.includes('https://www.etsy.com/seller-handbook/article/382774281517'));
+ assert.ok(text.includes('does not predict search rank'));
assert.ok(text.includes('[high] (tags) Exactly 13 tags — fix: Use all 13 tag slots.'));
</file context>
| assert.ok(text.includes('https://www.etsy.com/seller-handbook/article/382774281517')); | |
| assert.ok(text.includes('[source](https://www.etsy.com/seller-handbook/article/382774281517)')); |
| `# Listing Audit\n\n` + | ||
| `**SEO Score: ${data.seoScore}/100** — title ${s.title}, tags ${s.tags}, description ${s.description}, completeness ${s.completeness}\n\n` + | ||
| `# Listing Readiness\n\n` + | ||
| `**Listing Readiness: ${score}/100**${data.scoringVersion ? ` · rubric ${data.scoringVersion}` : ''} — title ${s.title}, tags ${s.tags}, description ${s.description}, completeness ${s.completeness}\n\n` + |
There was a problem hiding this comment.
P3: When neither overallScore nor seoScore is present, score falls back to the string 'n/a', but the line unconditionally appends /100, so it renders Listing Readiness: n/a/100. Only append /100 when the score is numeric.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/formatters/listing.js, line 17:
<comment>When neither `overallScore` nor `seoScore` is present, `score` falls back to the string `'n/a'`, but the line unconditionally appends `/100`, so it renders `Listing Readiness: n/a/100`. Only append `/100` when the score is numeric.</comment>
<file context>
@@ -1,21 +1,24 @@
- `# Listing Audit\n\n` +
- `**SEO Score: ${data.seoScore}/100** — title ${s.title}, tags ${s.tags}, description ${s.description}, completeness ${s.completeness}\n\n` +
+ `# Listing Readiness\n\n` +
+ `**Listing Readiness: ${score}/100**${data.scoringVersion ? ` · rubric ${data.scoringVersion}` : ''} — title ${s.title}, tags ${s.tags}, description ${s.description}, completeness ${s.completeness}\n\n` +
`## Weak points\n${weakPoints || 'None — this listing passes every check.'}\n\n` +
`## Missing keywords\n${(data.missingKeywords || []).join(', ') || 'none'}\n\n` +
</file context>
| `**Listing Readiness: ${score}/100**${data.scoringVersion ? ` · rubric ${data.scoringVersion}` : ''} — title ${s.title}, tags ${s.tags}, description ${s.description}, completeness ${s.completeness}\n\n` + | |
| `**Listing Readiness: ${typeof score === 'number' ? `${score}/100` : score}**${data.scoringVersion ? ` · rubric ${data.scoringVersion}` : ''} — title ${s.title}, tags ${s.tags}, description ${s.description}, completeness ${s.completeness}\n\n` + |
Ne değişti
analyze/optimizeoutput şemaları artıkscoringVersion,scoreType,overallScore,evaluatedAt,evidence,limitationszorunlu tutuyor;seoScoresadecedeprecateduyumluluk alias'ı.ruleId,explanationvesourceistiyor; formatter her bulguyureason → fixolarak, Etsy kaynağına link vererek basıyor.**Listing Readiness: N/100** · rubric <version>.skills/seerxo-etsy-seo/SKILL.mdskorun ne olduğunu ve ne olmadığını söylüyor.Doğrulama
npm test→ 104/104 passnpm run lint(node --checkzinciri) → temiznpm run build→ package validation passedBağımlılık
semihbugrasezer/seerxo-backend#105 önce merge olmalı — bu şema onun çıktısını doğruluyor (
scoringVersionconst olaraketsy-guidance-2026-04-27'e pinli).Summary by cubic
Switches CLI/MCP
analyzeandoptimizeoutputs from a legacy SEO score to a versioned Listing Readiness contract with sourced findings and explicit limitations.seoScorestays as a deprecated compatibility alias; no behavior changes for consumers that ignored it.scoringVersion,scoreType,overallScore,evaluatedAt,evidence, andlimitations.ruleId,explanation, andsource; the formatter renders each finding asreason → fixwith a link to its Etsy source.Listing Readiness: N/100 · rubric <version>, and README and skill docs state what the score does and does not predict.optimizenow rejects rewrites that lower the deterministic readiness score.semihbugrasezer/seerxo-backend#105, which must merge before this schema's pinnedscoringVersionoutput is validated.Written for commit ef478ec. Summary will update on new commits.