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
When NPM_DIST_TAG is unset and the version-based check triggers (1.0.0-beta.1 with no dist-tag env var), legacyPackageDraftFromEvidence is called with an empty npmDistTag and defaults to "beta" in the release notes text. This hardcoded fallback may be factually incorrect — the actual publish command may use a different dist-tag (e.g. alpha, rc, next). The two functions use different defaults: isLegacyPackageOnlyRelease treats an empty dist-tag as a non-trigger (only version-based), while legacyPackageDraftFromEvidence masks the absence with "beta".
Consider passing the resolved dist-tag from outside both functions, or at minimum using displayVersion(version) in the bullet to reflect the actual prerelease identifier instead of the hardcoded "beta" fallback.
// Avoid hardcoding 'beta': if no dist-tag is known, omit the dist-tag phrase or
// surface the actual prerelease identifier from the version string.
const distTag = String(npmDistTag || "").trim();
const distTagLabel = distTag || parseSemver(cleanVersion(version))?.prerelease || "prerelease";
The regex in validateLegacyPackageNotes hardcodes the marker strings "doc-agent-release-notes-json" and "doc-agent: source-id=" that are already defined as the constant RELEASE_NOTES_MARKER (line 38) and used verbatim in ensureSourceHint. If either string is ever renamed or updated, this validation regex will silently stop catching them, allowing policy-violating notes to pass through.
Consider building the regex from the constant to stay in sync:
if (/doc-agent:\s*source-id=|doc-agent-release-notes-json/.test(text)) {
fail("Legacy package release notes must not include Doc Agent source hints or docs payloads.");
}
After:
const legacyForbiddenPattern = new RegExp(`${RELEASE_NOTES_MARKER}|doc-agent:\\s*source-id=`);
if (legacyForbiddenPattern.test(text)) {
fail("Legacy package release notes must not include Doc Agent source hints or docs payloads.");
}
In legacyPackageDraftFromEvidence, version is used raw (from evidence?.target_version) in the release note bullet, while targetPackageVersion applies cleanVersion. This means if target_version carries a v prefix (e.g. "v2.0.13-beta.1"), the display line will be:
Published MemOS Local Plugin v2.0.13-beta.1 as a package prerelease ...
- Package version: 2.0.12 -> 2.0.13-beta.1
The v prefix is inconsistently applied within the same notes block. Consider using displayVersion(version) for consistent formatting in the first bullet, and documenting that the version arrow line deliberately omits it.
💡 Suggested Change
Before:
const version = evidence?.target_version || "";
const targetPackageVersion = cleanVersion(version);
The pre-release branch unconditionally calls incrementPatchVersion(previousReleasedVersion), which itself calls fail() if previousReleasedVersion happens to be a pre-release version (see incrementPatchVersion lines 163-166). While previousReleasedVersion is unlikely to be a pre-release in normal flow, the function's documented contract is that it won't auto-increment pre-release inputs. If a pre-release tag ever becomes the "previous released version", this path will throw an unexpected error. An explicit guard or comment explaining why previousReleasedVersion is guaranteed stable here would improve safety and maintainability.
The pattern terms inject and rank are very generic English words that can easily appear in unrelated commit messages (e.g., "inject dependency", "rank ordering", "inject mock"). This may cause false-positive matches, incorrectly classifying unrelated commits under the "Recall relevance and host input handling" topic. Consider narrowing the pattern with word-boundary anchors (\b) or more specific phrases to reduce misclassification risk.
When the input matches the revert capture pattern (first .replace()), the resulting $1 text is then passed through the second .replace() which tries to strip a Conventional Commit prefix again. If the reverted commit subject itself has a prefix like feat(plugin): ..., it will be stripped correctly. However, if the revert pattern fails to match (e.g. revert message uses single quotes or no quotes), the text falls through with the full revert "..." intact, and the second rule won't match it either since it checks for revert at the start but won't capture the inner subject. This means revert subjects that don't exactly match the double-quote convention will silently produce a raw revert string in the output. The category check on line 900 (/^fix|^revert/i.test(source)) still works correctly because it tests source (the raw input), not cleaned — but the displayed text may be ugly.
After fallbackSubjectText strips the Conventional Commit prefix (e.g. fix(plugin): ), cleaned may still contain a PR reference like stabilize sandbox widget (#9999) if the \s+\(#\d+\) trailing pattern doesn't match due to extra trailing spaces or punctuation variation. More critically, the category is determined from source (which still has the original prefix like fix(plugin):), while the text body uses cleaned. These two derived from the same source variable diverging is intentional and correct, but a brief comment clarifying this intent would help future maintainers avoid accidentally changing source to cleaned for the category check.
The allowGeneric: true flag has no effect here because "fix(plugin): improve recall relevance and host input handling (#2196)" matches the static FALLBACK_TOPIC_RULES rule for /recall|retrieval|host input|.../i, so the generic code path (where prefix stripping actually happens) is never reached. The test name claims to verify "without raw commit prefixes", but it only confirms the static rule lookup — not stripping. This means a regression in the generic CC-prefix stripping logic would not be caught by this test.
Consider using a commit message that does not match any static rule to actually exercise the generic path, or add a parallel allowGeneric: false assertion to document that this test deliberately targets the rule-based path.
The text_en field is not asserted to contain the cleaned text. Since the generic fallback constructs text_en symmetrically with text_cn (line 902 of production code: `**${PRODUCT_TITLE.en} update**: ${cleaned}`), the assertion assert.match(topic.text_en, /fix\(plugin\)/) only verifies the prefix is absent, but never confirms that the cleaned text stabilize sandbox widget is actually present in text_en. A future regression where text_en is set to an empty fallback string would silently pass this test.
Add assert.match(topic.text_en, /stabilize sandbox widget/) to mirror the text_cn assertion.
MLittleprince
changed the title
ci: keep local plugin beta releases package-only
ci: keep local plugin standalone publishing compatible with MemOS releases
Aug 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
area:coreMOS 编排层 / 框架底座 / 跨模块问题status:readyReady for implementation; waiting for assignee or AI dispatch | 可进入实现,等待认领或派发
4 participants
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Validation