From 9bbba3c288c8a950b9a6ffd6a0ef99db38edbd3a Mon Sep 17 00:00:00 2001 From: JSONbored <49853598+JSONbored@users.noreply.github.com> Date: Tue, 2 Jun 2026 01:04:03 -0700 Subject: [PATCH 1/3] chore(release): 0.4.0 Prepare the MCP package for v0.4.0, add release-aware MCP changelog generation, add the release-due issue workflow, and modernize the MCP release dependency stack. Validation: npm run build:mcp; npm run test:mcp-pack; npm run changelog:check:mcp; npm run actionlint; npm run test:release:mcp. --- .github/workflows/mcp-release-watch.yml | 52 + apps/gittensory-ui/package.json | 2 +- apps/gittensory-ui/public/openapi.json | 7245 +++++++++-------- package-lock.json | 293 +- package.json | 9 +- packages/gittensory-mcp/CHANGELOG.md | 35 +- packages/gittensory-mcp/bin/gittensory-mcp.js | 2 +- packages/gittensory-mcp/package.json | 6 +- scripts/check-changelog.mjs | 40 +- scripts/check-mcp-release-due.mjs | 153 + scripts/generate-mcp-changelog.mjs | 180 + scripts/mcp-release-core.d.mts | 43 + scripts/mcp-release-core.mjs | 331 + scripts/smoke-production.mjs | 10 +- src/api/routes.ts | 2 +- src/mcp/server.ts | 5 +- src/openapi/schemas.ts | 148 +- src/openapi/spec.ts | 12 +- src/services/mcp-compatibility.ts | 7 +- test/integration/api.test.ts | 30 +- test/unit/mcp-cli.test.ts | 34 +- test/unit/mcp-compatibility.test.ts | 15 +- test/unit/mcp-release.test.ts | 84 + test/unit/mcp-server-telemetry.test.ts | 4 +- test/unit/product-usage-mcp-adoption.test.ts | 2 +- 25 files changed, 4751 insertions(+), 3993 deletions(-) create mode 100644 .github/workflows/mcp-release-watch.yml create mode 100644 scripts/check-mcp-release-due.mjs create mode 100644 scripts/generate-mcp-changelog.mjs create mode 100644 scripts/mcp-release-core.d.mts create mode 100644 scripts/mcp-release-core.mjs create mode 100644 test/unit/mcp-release.test.ts diff --git a/.github/workflows/mcp-release-watch.yml b/.github/workflows/mcp-release-watch.yml new file mode 100644 index 0000000000..57fde8c8d8 --- /dev/null +++ b/.github/workflows/mcp-release-watch.yml @@ -0,0 +1,52 @@ +name: MCP Release Watch + +on: + workflow_dispatch: + schedule: + - cron: "15 16 * * *" + +permissions: + contents: read + issues: write + +concurrency: + group: mcp-release-watch-${{ github.ref }} + cancel-in-progress: false + +jobs: + release-watch: + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - name: Checkout + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Setup Node + uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5 + with: + node-version: 24 + + - name: Check MCP release status + env: + GITHUB_TOKEN: ${{ github.token }} + run: node scripts/check-mcp-release-due.mjs --json --output mcp-release-due.json --upsert-issue + + - name: Summarize MCP release status + run: | + node <<'NODE' + const fs = require("node:fs"); + const report = JSON.parse(fs.readFileSync("mcp-release-due.json", "utf8")); + const lines = [ + "## MCP Release Watch", + "", + `- Due: \`${report.due}\``, + `- Proposed version: \`${report.proposedVersion}\``, + `- Latest tag: \`${report.latestTag ?? "none"}\``, + `- npm latest: \`${report.publishedVersion ?? "unknown"}\``, + `- MCP-related commits: \`${report.commits.length}\``, + ]; + fs.appendFileSync(process.env.GITHUB_STEP_SUMMARY, `${lines.join("\n")}\n`); + NODE diff --git a/apps/gittensory-ui/package.json b/apps/gittensory-ui/package.json index b998c21467..ee0e2ba42f 100644 --- a/apps/gittensory-ui/package.json +++ b/apps/gittensory-ui/package.json @@ -69,7 +69,7 @@ "tw-animate-css": "^1.3.4", "vaul": "^1.1.2", "vite-tsconfig-paths": "^6.0.2", - "zod": "^3.24.2" + "zod": "^4.4.3" }, "devDependencies": { "@eslint/js": "^9.32.0", diff --git a/apps/gittensory-ui/public/openapi.json b/apps/gittensory-ui/public/openapi.json index 867e3ced1d..f2750e4c5b 100644 --- a/apps/gittensory-ui/public/openapi.json +++ b/apps/gittensory-ui/public/openapi.json @@ -146,59 +146,6 @@ "generatedAt" ] }, - "RegistryRepo": { - "type": "object", - "properties": { - "repo": { - "type": "string" - }, - "emissionShare": { - "type": "number" - }, - "issueDiscoveryShare": { - "type": "number" - }, - "labelMultipliers": { - "type": "object", - "additionalProperties": { - "type": "number" - } - }, - "trustedLabelPipeline": { - "type": "boolean", - "nullable": true - }, - "maintainerCut": { - "type": "number" - }, - "defaultLabelMultiplier": { - "type": "number", - "nullable": true - }, - "fixedBaseScore": { - "type": "number", - "nullable": true - }, - "eligibilityMode": { - "type": "string", - "nullable": true - }, - "raw": { - "type": "object", - "additionalProperties": { - "nullable": true - } - } - }, - "required": [ - "repo", - "emissionShare", - "issueDiscoveryShare", - "labelMultipliers", - "maintainerCut", - "raw" - ] - }, "RegistrySnapshot": { "type": "object", "properties": { @@ -260,6 +207,59 @@ "repositories" ] }, + "RegistryRepo": { + "type": "object", + "properties": { + "repo": { + "type": "string" + }, + "emissionShare": { + "type": "number" + }, + "issueDiscoveryShare": { + "type": "number" + }, + "labelMultipliers": { + "type": "object", + "additionalProperties": { + "type": "number" + } + }, + "trustedLabelPipeline": { + "type": "boolean", + "nullable": true + }, + "maintainerCut": { + "type": "number" + }, + "defaultLabelMultiplier": { + "type": "number", + "nullable": true + }, + "fixedBaseScore": { + "type": "number", + "nullable": true + }, + "eligibilityMode": { + "type": "string", + "nullable": true + }, + "raw": { + "type": "object", + "additionalProperties": { + "nullable": true + } + } + }, + "required": [ + "repo", + "emissionShare", + "issueDiscoveryShare", + "labelMultipliers", + "maintainerCut", + "raw" + ] + }, "Repository": { "type": "object", "properties": { @@ -313,40 +313,6 @@ "isPrivate" ] }, - "Finding": { - "type": "object", - "properties": { - "code": { - "type": "string" - }, - "title": { - "type": "string" - }, - "severity": { - "type": "string", - "enum": [ - "info", - "warning", - "critical" - ] - }, - "detail": { - "type": "string" - }, - "action": { - "type": "string" - }, - "publicText": { - "type": "string" - } - }, - "required": [ - "code", - "title", - "severity", - "detail" - ] - }, "Advisory": { "type": "object", "properties": { @@ -421,6 +387,40 @@ "generatedAt" ] }, + "Finding": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "title": { + "type": "string" + }, + "severity": { + "type": "string", + "enum": [ + "info", + "warning", + "critical" + ] + }, + "detail": { + "type": "string" + }, + "action": { + "type": "string" + }, + "publicText": { + "type": "string" + } + }, + "required": [ + "code", + "title", + "severity", + "detail" + ] + }, "WorkboardItem": { "type": "object", "properties": { @@ -560,68 +560,6 @@ "findings" ] }, - "CollisionItem": { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "issue", - "pull_request" - ] - }, - "number": { - "type": "number" - }, - "title": { - "type": "string" - }, - "authorLogin": { - "type": "string", - "nullable": true - }, - "htmlUrl": { - "type": "string", - "nullable": true - } - }, - "required": [ - "type", - "number", - "title" - ] - }, - "CollisionCluster": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "risk": { - "type": "string", - "enum": [ - "low", - "medium", - "high" - ] - }, - "reason": { - "type": "string" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CollisionItem" - } - } - }, - "required": [ - "id", - "risk", - "reason", - "items" - ] - }, "CollisionReport": { "type": "object", "properties": { @@ -664,44 +602,66 @@ "clusters" ] }, - "LaneAdvice": { + "CollisionCluster": { "type": "object", "properties": { - "lane": { + "id": { + "type": "string" + }, + "risk": { "type": "string", "enum": [ - "direct_pr", - "issue_discovery", - "split", - "inactive", - "unknown" + "low", + "medium", + "high" ] }, - "repoFullName": { + "reason": { "type": "string" }, - "issueDiscoveryShare": { - "type": "number" - }, - "directPrShare": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CollisionItem" + } + } + }, + "required": [ + "id", + "risk", + "reason", + "items" + ] + }, + "CollisionItem": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "issue", + "pull_request" + ] + }, + "number": { "type": "number" }, - "summary": { + "title": { "type": "string" }, - "contributorGuidance": { - "type": "string" + "authorLogin": { + "type": "string", + "nullable": true }, - "maintainerGuidance": { - "type": "string" + "htmlUrl": { + "type": "string", + "nullable": true } }, "required": [ - "lane", - "repoFullName", - "summary", - "contributorGuidance", - "maintainerGuidance" + "type", + "number", + "title" ] }, "ConfigQuality": { @@ -765,6 +725,46 @@ "findings" ] }, + "LaneAdvice": { + "type": "object", + "properties": { + "lane": { + "type": "string", + "enum": [ + "direct_pr", + "issue_discovery", + "split", + "inactive", + "unknown" + ] + }, + "repoFullName": { + "type": "string" + }, + "issueDiscoveryShare": { + "type": "number" + }, + "directPrShare": { + "type": "number" + }, + "summary": { + "type": "string" + }, + "contributorGuidance": { + "type": "string" + }, + "maintainerGuidance": { + "type": "string" + } + }, + "required": [ + "lane", + "repoFullName", + "summary", + "contributorGuidance", + "maintainerGuidance" + ] + }, "LabelAudit": { "type": "object", "properties": { @@ -1901,129 +1901,246 @@ "summary" ] }, - "DecisionPackFreshness": { - "type": "string", - "enum": [ - "fresh", - "stale", - "rebuilding", - "missing" - ] - }, - "ContributorOpenPrNextStepPacket": { + "ContributorDecisionPack": { "type": "object", "properties": { - "repoFullName": { + "status": { + "type": "string", + "enum": [ + "ready" + ] + }, + "source": { + "type": "string", + "enum": [ + "computed", + "snapshot" + ] + }, + "login": { "type": "string" }, - "number": { + "generatedAt": { + "type": "string" + }, + "snapshotAgeSeconds": { "type": "number" }, - "title": { - "type": "string" + "stale": { + "type": "boolean" }, - "classification": { - "type": "string", - "enum": [ - "approved", - "blocked", - "stale", - "needs_author", - "failing_checks", - "missing_tests", - "duplicate_prone", - "reviewable", - "should_close_or_withdraw", - "maintainer_lane", - "draft" - ] + "freshness": { + "$ref": "#/components/schemas/DecisionPackFreshness" }, - "summary": { + "rebuildEnqueued": { + "type": "boolean" + }, + "scoringModelSnapshotId": { "type": "string" }, - "reasons": { + "profile": { + "type": "object", + "additionalProperties": { + "nullable": true + } + }, + "outcomeHistory": { + "$ref": "#/components/schemas/ContributorOutcomeHistory" + }, + "roleContexts": { "type": "array", "items": { - "type": "string" + "$ref": "#/components/schemas/RoleContext" } }, - "nextSteps": { + "opportunities": { "type": "array", "items": { - "type": "string" + "$ref": "#/components/schemas/ContributorOpportunity" } - } - }, - "required": [ - "repoFullName", - "number", - "title", - "classification", - "summary", - "reasons", - "nextSteps" - ] - }, - "ContributorOpenPrMonitor": { - "type": "object", - "properties": { - "login": { - "type": "string" - }, - "generatedAt": { - "type": "string" }, - "openPrCount": { - "type": "number" + "repoDecisions": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "nullable": true + } + } }, - "registeredRepoCount": { - "type": "number" + "topActions": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "nullable": true + } + } }, "cleanupFirst": { - "type": "boolean" + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "nullable": true + } + } }, - "summary": { - "type": "string" + "pursueRepos": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "nullable": true + } + } }, - "guidance": { + "avoidRepos": { "type": "array", "items": { - "type": "string" + "type": "object", + "additionalProperties": { + "nullable": true + } } }, - "pendingScenarios": { + "maintainerLaneRepos": { "type": "array", "items": { "type": "object", - "properties": { - "repoFullName": { - "type": "string" - }, - "detection": { - "type": "object", - "properties": { - "source": { - "type": "string", - "enum": [ - "github_observed", - "user_supplied" - ] - }, - "pendingMergedPrCount": { - "type": "number" - }, - "pendingClosedPrCount": { - "type": "number" - }, - "approvedPrCount": { - "type": "number" - }, - "expectedOpenPrCountAfterMerge": { - "type": "number" - }, - "scenarioNotes": { - "type": "array", - "items": { + "additionalProperties": { + "nullable": true + } + } + }, + "scoreBlockers": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "nullable": true + } + } + }, + "evidenceGraph": { + "type": "object", + "additionalProperties": { + "nullable": true + } + }, + "dataQuality": { + "type": "object", + "additionalProperties": { + "nullable": true + } + }, + "summary": { + "type": "string" + }, + "nextActions": { + "type": "array", + "items": { + "type": "string" + } + }, + "openPrMonitor": { + "$ref": "#/components/schemas/ContributorOpenPrMonitor" + } + }, + "required": [ + "status", + "source", + "login", + "generatedAt", + "stale", + "freshness", + "rebuildEnqueued", + "scoringModelSnapshotId", + "profile", + "outcomeHistory", + "roleContexts", + "opportunities", + "repoDecisions", + "topActions", + "cleanupFirst", + "pursueRepos", + "avoidRepos", + "maintainerLaneRepos", + "scoreBlockers", + "dataQuality", + "summary", + "nextActions" + ] + }, + "DecisionPackFreshness": { + "type": "string", + "enum": [ + "fresh", + "stale", + "rebuilding", + "missing" + ] + }, + "ContributorOpenPrMonitor": { + "type": "object", + "properties": { + "login": { + "type": "string" + }, + "generatedAt": { + "type": "string" + }, + "openPrCount": { + "type": "number" + }, + "registeredRepoCount": { + "type": "number" + }, + "cleanupFirst": { + "type": "boolean" + }, + "summary": { + "type": "string" + }, + "guidance": { + "type": "array", + "items": { + "type": "string" + } + }, + "pendingScenarios": { + "type": "array", + "items": { + "type": "object", + "properties": { + "repoFullName": { + "type": "string" + }, + "detection": { + "type": "object", + "properties": { + "source": { + "type": "string", + "enum": [ + "github_observed", + "user_supplied" + ] + }, + "pendingMergedPrCount": { + "type": "number" + }, + "pendingClosedPrCount": { + "type": "number" + }, + "approvedPrCount": { + "type": "number" + }, + "expectedOpenPrCountAfterMerge": { + "type": "number" + }, + "scenarioNotes": { + "type": "array", + "items": { "type": "string" } }, @@ -2096,33 +2213,127 @@ "pullRequests" ] }, - "ContributorDecisionPack": { + "ContributorOpenPrNextStepPacket": { "type": "object", "properties": { - "status": { + "repoFullName": { + "type": "string" + }, + "number": { + "type": "number" + }, + "title": { + "type": "string" + }, + "classification": { "type": "string", "enum": [ - "ready" + "approved", + "blocked", + "stale", + "needs_author", + "failing_checks", + "missing_tests", + "duplicate_prone", + "reviewable", + "should_close_or_withdraw", + "maintainer_lane", + "draft" ] }, - "source": { + "summary": { + "type": "string" + }, + "reasons": { + "type": "array", + "items": { + "type": "string" + } + }, + "nextSteps": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "repoFullName", + "number", + "title", + "classification", + "summary", + "reasons", + "nextSteps" + ] + }, + "DecisionPackRefreshNeeded": { + "type": "object", + "properties": { + "status": { "type": "string", "enum": [ - "computed", - "snapshot" + "needs_snapshot_refresh" ] }, "login": { "type": "string" }, + "repoFullName": { + "type": "string" + }, "generatedAt": { "type": "string" }, - "snapshotAgeSeconds": { - "type": "number" + "reason": { + "type": "string", + "enum": [ + "missing_snapshot" + ] }, - "stale": { + "freshness": { + "type": "string", + "enum": [ + "missing" + ] + }, + "rebuildEnqueued": { "type": "boolean" + } + }, + "required": [ + "status", + "login", + "generatedAt", + "reason", + "freshness", + "rebuildEnqueued" + ] + }, + "RepoDecisionResponse": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "ready" + ] + }, + "login": { + "type": "string" + }, + "repoFullName": { + "type": "string" + }, + "generatedAt": { + "type": "string" + }, + "source": { + "type": "string", + "enum": [ + "computed", + "snapshot" + ] }, "freshness": { "$ref": "#/components/schemas/DecisionPackFreshness" @@ -2130,95 +2341,110 @@ "rebuildEnqueued": { "type": "boolean" }, - "scoringModelSnapshotId": { - "type": "string" - }, - "profile": { + "decision": { "type": "object", "additionalProperties": { "nullable": true } }, - "outcomeHistory": { - "$ref": "#/components/schemas/ContributorOutcomeHistory" - }, - "roleContexts": { - "type": "array", - "items": { - "$ref": "#/components/schemas/RoleContext" + "dataQuality": { + "type": "object", + "additionalProperties": { + "nullable": true } + } + }, + "required": [ + "status", + "login", + "repoFullName", + "generatedAt", + "source", + "freshness", + "rebuildEnqueued", + "decision", + "dataQuality" + ] + }, + "RepoIntelligence": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "ready" + ] }, - "opportunities": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ContributorOpportunity" - } + "source": { + "type": "string", + "enum": [ + "computed", + "snapshot" + ] }, - "repoDecisions": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "nullable": true - } - } + "repoFullName": { + "type": "string" }, - "topActions": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { + "generatedAt": { + "type": "string" + }, + "repo": { + "allOf": [ + { + "$ref": "#/components/schemas/Repository" + }, + { "nullable": true } + ] + }, + "lane": { + "$ref": "#/components/schemas/LaneAdvice" + }, + "queueHealth": { + "type": "object", + "nullable": true, + "additionalProperties": { + "nullable": true } }, - "cleanupFirst": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "nullable": true - } + "collisions": { + "type": "object", + "additionalProperties": { + "nullable": true } }, - "pursueRepos": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "nullable": true - } + "configQuality": { + "type": "object", + "nullable": true, + "additionalProperties": { + "nullable": true } }, - "avoidRepos": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "nullable": true - } + "labelAudit": { + "type": "object", + "nullable": true, + "additionalProperties": { + "nullable": true } }, - "maintainerLaneRepos": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "nullable": true - } + "maintainerLane": { + "type": "object", + "nullable": true, + "additionalProperties": { + "nullable": true } }, - "scoreBlockers": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "nullable": true - } + "maintainerCutReadiness": { + "type": "object", + "nullable": true, + "additionalProperties": { + "nullable": true } }, - "evidenceGraph": { + "contributorIntakeHealth": { "type": "object", + "nullable": true, "additionalProperties": { "nullable": true } @@ -2229,183 +2455,179 @@ "nullable": true } }, - "summary": { - "type": "string" - }, - "nextActions": { - "type": "array", - "items": { - "type": "string" - } + "burdenForecast": { + "$ref": "#/components/schemas/BurdenForecast" }, - "openPrMonitor": { - "$ref": "#/components/schemas/ContributorOpenPrMonitor" + "burdenForecastFreshness": { + "type": "object", + "properties": { + "source": { + "type": "string", + "enum": [ + "snapshot", + "computed" + ] + }, + "generatedAt": { + "type": "string" + }, + "ageSeconds": { + "type": "number" + }, + "freshness": { + "type": "string", + "enum": [ + "fresh", + "stale" + ] + } + }, + "required": [ + "source", + "generatedAt", + "ageSeconds", + "freshness" + ] } }, "required": [ "status", "source", - "login", + "repoFullName", "generatedAt", - "stale", - "freshness", - "rebuildEnqueued", - "scoringModelSnapshotId", - "profile", - "outcomeHistory", - "roleContexts", - "opportunities", - "repoDecisions", - "topActions", - "cleanupFirst", - "pursueRepos", - "avoidRepos", - "maintainerLaneRepos", - "scoreBlockers", - "dataQuality", - "summary", - "nextActions" + "repo", + "lane", + "dataQuality" ] }, - "DecisionPackRefreshNeeded": { + "BurdenForecast": { "type": "object", "properties": { - "status": { - "type": "string", - "enum": [ - "needs_snapshot_refresh" - ] - }, - "login": { - "type": "string" - }, "repoFullName": { "type": "string" }, "generatedAt": { "type": "string" }, - "reason": { - "type": "string", - "enum": [ - "missing_snapshot" + "horizonDays": { + "anyOf": [ + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 30 + ] + } ] }, - "freshness": { + "level": { "type": "string", "enum": [ - "missing" + "low", + "medium", + "high", + "critical" ] }, - "rebuildEnqueued": { - "type": "boolean" + "forecast": { + "type": "object", + "additionalProperties": { + "type": "number" + } + }, + "findings": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Finding" + } + }, + "summary": { + "type": "string" } }, "required": [ - "status", - "login", + "repoFullName", "generatedAt", - "reason", - "freshness", - "rebuildEnqueued" + "horizonDays", + "level", + "forecast", + "findings", + "summary" ] }, - "RepoDecisionResponse": { + "RepoOutcomePatterns": { "type": "object", "properties": { - "status": { - "type": "string", - "enum": [ - "ready" - ] - }, - "login": { - "type": "string" - }, "repoFullName": { "type": "string" }, "generatedAt": { "type": "string" }, - "source": { + "lane": { "type": "string", "enum": [ - "computed", - "snapshot" + "direct_pr", + "issue_discovery", + "split", + "inactive", + "unknown" ] }, - "freshness": { - "$ref": "#/components/schemas/DecisionPackFreshness" + "primaryLanguage": { + "type": "string", + "nullable": true }, - "rebuildEnqueued": { - "type": "boolean" + "sampleSize": { + "type": "number" }, - "decision": { + "totals": { "type": "object", "additionalProperties": { - "nullable": true + "type": "number" } }, - "dataQuality": { - "type": "object", - "additionalProperties": { - "nullable": true - } - } - }, - "required": [ - "status", - "login", - "repoFullName", - "generatedAt", - "source", - "freshness", - "rebuildEnqueued", - "decision", - "dataQuality" - ] - }, - "BurdenForecast": { - "type": "object", - "properties": { - "repoFullName": { - "type": "string" + "outsideContributorMergeRate": { + "type": "number" }, - "generatedAt": { - "type": "string" + "maintainerLaneMergeRate": { + "type": "number" }, - "horizonDays": { - "anyOf": [ - { - "type": "number", - "enum": [ - 7 - ] - }, - { - "type": "number", - "enum": [ - 30 - ] + "dimensions": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "nullable": true } - ] + } }, - "level": { - "type": "string", - "enum": [ - "low", - "medium", - "high", - "critical" - ] + "successPatterns": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "nullable": true + } + } }, - "forecast": { - "type": "object", - "additionalProperties": { - "type": "number" + "riskPatterns": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "nullable": true + } } }, + "evidenceCompleteness": { + "$ref": "#/components/schemas/RepoOutcomeEvidenceCompleteness" + }, "findings": { "type": "array", "items": { @@ -2419,14 +2641,69 @@ "required": [ "repoFullName", "generatedAt", - "horizonDays", - "level", - "forecast", + "lane", + "primaryLanguage", + "sampleSize", + "totals", + "outsideContributorMergeRate", + "maintainerLaneMergeRate", + "dimensions", + "successPatterns", + "riskPatterns", + "evidenceCompleteness", "findings", "summary" ] }, - "RepoIntelligence": { + "RepoOutcomeEvidenceCompleteness": { + "type": "object", + "properties": { + "pullRequestsAnalyzed": { + "type": "number" + }, + "withFileDetail": { + "type": "number" + }, + "withReviewDetail": { + "type": "number" + }, + "withCheckDetail": { + "type": "number" + }, + "filesCompletenessRatio": { + "type": "number" + }, + "reviewsCompletenessRatio": { + "type": "number" + }, + "checksCompletenessRatio": { + "type": "number" + }, + "fullyDecidedWithDetail": { + "type": "number" + }, + "status": { + "type": "string", + "enum": [ + "complete", + "partial", + "missing" + ] + } + }, + "required": [ + "pullRequestsAnalyzed", + "withFileDetail", + "withReviewDetail", + "withCheckDetail", + "filesCompletenessRatio", + "reviewsCompletenessRatio", + "checksCompletenessRatio", + "fullyDecidedWithDetail", + "status" + ] + }, + "RepoOutcomePatternsResponse": { "type": "object", "properties": { "status": { @@ -2438,8 +2715,8 @@ "source": { "type": "string", "enum": [ - "computed", - "snapshot" + "snapshot", + "computed" ] }, "repoFullName": { @@ -2448,2088 +2725,1142 @@ "generatedAt": { "type": "string" }, - "repo": { - "allOf": [ - { - "$ref": "#/components/schemas/Repository" - }, - { - "nullable": true - } + "ageSeconds": { + "type": "number" + }, + "freshness": { + "type": "string", + "enum": [ + "fresh", + "stale" ] }, - "lane": { - "$ref": "#/components/schemas/LaneAdvice" + "patterns": { + "$ref": "#/components/schemas/RepoOutcomePatterns" }, - "queueHealth": { + "dataQuality": { "type": "object", - "nullable": true, "additionalProperties": { "nullable": true } + } + }, + "required": [ + "status", + "source", + "repoFullName", + "generatedAt", + "ageSeconds", + "freshness", + "patterns" + ] + }, + "RegistrationReadiness": { + "type": "object", + "properties": { + "repoFullName": { + "type": "string" }, - "collisions": { - "type": "object", - "additionalProperties": { - "nullable": true - } + "generatedAt": { + "type": "string" }, - "configQuality": { - "type": "object", - "nullable": true, - "additionalProperties": { - "nullable": true - } + "ready": { + "type": "boolean" }, - "labelAudit": { - "type": "object", - "nullable": true, - "additionalProperties": { - "nullable": true - } + "recommendedRegistrationMode": { + "type": "string", + "enum": [ + "direct_pr", + "issue_discovery", + "split" + ] }, - "maintainerLane": { + "issuePolicy": { + "type": "string", + "enum": [ + "issue_discovery_enabled", + "split_pr_and_issue_discovery_enabled", + "direct_pr_requires_linked_issue", + "direct_pr_no_issue_required" + ] + }, + "directPrReadiness": { + "type": "object", + "properties": { + "ready": { + "type": "boolean" + }, + "reasons": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "ready", + "reasons" + ] + }, + "issueDiscoveryReadiness": { + "type": "object", + "properties": { + "ready": { + "type": "boolean" + }, + "recommendation": { + "type": "string", + "enum": [ + "enabled", + "recommended", + "not_recommended" + ] + }, + "reasons": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "ready", + "recommendation", + "reasons" + ] + }, + "labelPolicy": { "type": "object", - "nullable": true, "additionalProperties": { "nullable": true } }, "maintainerCutReadiness": { "type": "object", - "nullable": true, "additionalProperties": { "nullable": true } }, + "testCoverageHealth": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "gate_ready", + "gate_unknown" + ] + }, + "trustedLabelPipelineReady": { + "type": "boolean" + }, + "checkRunMode": { + "type": "string", + "enum": [ + "off", + "enabled" + ] + }, + "requiredGate": { + "type": "array", + "items": { + "type": "string" + } + }, + "note": { + "type": "string" + }, + "warnings": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "status", + "trustedLabelPipelineReady", + "checkRunMode", + "requiredGate", + "note", + "warnings" + ] + }, + "queueHealth": { + "type": "object", + "properties": { + "level": { + "type": "string", + "enum": [ + "low", + "medium", + "high", + "critical" + ] + }, + "burdenScore": { + "type": "number" + }, + "reviewablePullRequests": { + "type": "number" + }, + "summary": { + "type": "string" + } + }, + "required": [ + "level", + "burdenScore", + "reviewablePullRequests", + "summary" + ] + }, "contributorIntakeHealth": { "type": "object", - "nullable": true, "additionalProperties": { "nullable": true } }, - "dataQuality": { + "docsCompleteness": { "type": "object", "additionalProperties": { "nullable": true } }, - "burdenForecast": { - "$ref": "#/components/schemas/BurdenForecast" - }, - "burdenForecastFreshness": { + "githubApp": { "type": "object", "properties": { - "source": { + "installed": { + "type": "boolean" + }, + "publicSurface": { "type": "string", "enum": [ - "snapshot", - "computed" + "off", + "comment_and_label", + "comment_only", + "label_only" ] }, - "generatedAt": { - "type": "string" - }, - "ageSeconds": { - "type": "number" + "commentMode": { + "type": "string", + "enum": [ + "off", + "detected_contributors_only", + "all_prs" + ] }, - "freshness": { + "checkRunMode": { "type": "string", "enum": [ - "fresh", - "stale" + "off", + "enabled" ] + }, + "quietByDefault": { + "type": "boolean" + }, + "behavior": { + "type": "string" + }, + "warnings": { + "type": "array", + "items": { + "type": "string" + } } }, "required": [ - "source", - "generatedAt", - "ageSeconds", - "freshness" + "installed", + "publicSurface", + "commentMode", + "checkRunMode", + "quietByDefault", + "behavior", + "warnings" ] + }, + "blockers": { + "type": "array", + "items": { + "type": "string" + } + }, + "warnings": { + "type": "array", + "items": { + "type": "string" + } + }, + "dataQuality": { + "type": "object", + "additionalProperties": { + "nullable": true + } } }, "required": [ - "status", - "source", "repoFullName", "generatedAt", - "repo", - "lane", + "ready", + "recommendedRegistrationMode", + "issuePolicy", + "directPrReadiness", + "issueDiscoveryReadiness", + "labelPolicy", + "maintainerCutReadiness", + "testCoverageHealth", + "queueHealth", + "contributorIntakeHealth", + "docsCompleteness", + "githubApp", + "blockers", + "warnings", "dataQuality" ] }, - "RepoOutcomeEvidenceCompleteness": { + "GittensorConfigRecommendation": { "type": "object", "properties": { - "pullRequestsAnalyzed": { - "type": "number" + "repoFullName": { + "type": "string" }, - "withFileDetail": { - "type": "number" + "generatedAt": { + "type": "string" }, - "withReviewDetail": { - "type": "number" + "privateOnly": { + "type": "boolean" }, - "withCheckDetail": { - "type": "number" + "current": { + "type": "object", + "nullable": true, + "additionalProperties": { + "nullable": true + } }, - "filesCompletenessRatio": { - "type": "number" + "recommended": { + "type": "object", + "additionalProperties": { + "nullable": true + } }, - "reviewsCompletenessRatio": { - "type": "number" + "tradeoffs": { + "type": "array", + "items": { + "type": "string" + } }, - "checksCompletenessRatio": { - "type": "number" + "reasons": { + "type": "array", + "items": { + "type": "string" + } }, - "fullyDecidedWithDetail": { - "type": "number" + "warnings": { + "type": "array", + "items": { + "type": "string" + } }, - "status": { - "type": "string", - "enum": [ - "complete", - "partial", - "missing" - ] + "dataQuality": { + "type": "object", + "additionalProperties": { + "nullable": true + } } }, "required": [ - "pullRequestsAnalyzed", - "withFileDetail", - "withReviewDetail", - "withCheckDetail", - "filesCompletenessRatio", - "reviewsCompletenessRatio", - "checksCompletenessRatio", - "fullyDecidedWithDetail", - "status" + "repoFullName", + "generatedAt", + "privateOnly", + "current", + "recommended", + "tradeoffs", + "reasons", + "warnings", + "dataQuality" ] }, - "RepoOutcomePatterns": { + "RepoFitRecommendation": { "type": "object", "properties": { + "login": { + "type": "string" + }, "repoFullName": { "type": "string" }, "generatedAt": { "type": "string" }, + "roleContext": { + "$ref": "#/components/schemas/RoleContext" + }, "lane": { + "$ref": "#/components/schemas/LaneAdvice" + }, + "recommendation": { "type": "string", "enum": [ - "direct_pr", - "issue_discovery", - "split", - "inactive", + "pursue", + "cleanup_first", + "maintainer_lane", + "avoid_for_now", "unknown" ] }, - "primaryLanguage": { + "confidence": { "type": "string", - "nullable": true - }, - "sampleSize": { - "type": "number" - }, - "totals": { - "type": "object", - "additionalProperties": { - "type": "number" - } - }, - "outsideContributorMergeRate": { - "type": "number" - }, - "maintainerLaneMergeRate": { - "type": "number" + "enum": [ + "high", + "medium", + "low" + ] }, - "dimensions": { + "reasons": { "type": "array", "items": { - "type": "object", - "additionalProperties": { - "nullable": true - } + "type": "string" } }, - "successPatterns": { + "risks": { "type": "array", "items": { - "type": "object", - "additionalProperties": { - "nullable": true - } + "type": "string" } }, - "riskPatterns": { + "nextActions": { "type": "array", "items": { - "type": "object", - "additionalProperties": { - "nullable": true - } + "type": "string" } }, - "evidenceCompleteness": { - "$ref": "#/components/schemas/RepoOutcomeEvidenceCompleteness" + "rewardRisk": { + "type": "object", + "additionalProperties": { + "nullable": true + } }, - "findings": { + "reasoning": { "type": "array", "items": { - "$ref": "#/components/schemas/Finding" + "type": "string" } }, - "summary": { - "type": "string" + "actionImpact": { + "type": "object", + "additionalProperties": { + "nullable": true + } } }, "required": [ + "login", "repoFullName", "generatedAt", + "roleContext", "lane", - "primaryLanguage", - "sampleSize", - "totals", - "outsideContributorMergeRate", - "maintainerLaneMergeRate", - "dimensions", - "successPatterns", - "riskPatterns", - "evidenceCompleteness", - "findings", - "summary" + "recommendation", + "confidence", + "reasons", + "risks", + "nextActions" ] }, - "RepoOutcomePatternsResponse": { + "PreflightResult": { "type": "object", "properties": { - "status": { - "type": "string", - "enum": [ - "ready" - ] - }, - "source": { - "type": "string", - "enum": [ - "snapshot", - "computed" - ] - }, "repoFullName": { "type": "string" }, "generatedAt": { "type": "string" }, - "ageSeconds": { - "type": "number" + "status": { + "type": "string", + "enum": [ + "ready", + "needs_work", + "hold" + ] }, - "freshness": { + "lane": { + "$ref": "#/components/schemas/LaneAdvice" + }, + "reviewBurden": { "type": "string", "enum": [ - "fresh", - "stale" + "low", + "medium", + "high" ] }, - "patterns": { - "$ref": "#/components/schemas/RepoOutcomePatterns" + "linkedIssues": { + "type": "array", + "items": { + "type": "number" + } }, - "dataQuality": { - "type": "object", - "additionalProperties": { - "nullable": true + "findings": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Finding" + } + }, + "collisions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CollisionCluster" } } }, "required": [ - "status", - "source", "repoFullName", "generatedAt", - "ageSeconds", - "freshness", - "patterns" + "status", + "lane", + "reviewBurden", + "linkedIssues", + "findings", + "collisions" ] }, - "RegistrationReadiness": { - "type": "object", - "properties": { - "repoFullName": { - "type": "string" - }, - "generatedAt": { - "type": "string" - }, - "ready": { - "type": "boolean" - }, - "recommendedRegistrationMode": { - "type": "string", - "enum": [ - "direct_pr", - "issue_discovery", - "split" - ] - }, - "issuePolicy": { - "type": "string", - "enum": [ - "issue_discovery_enabled", - "split_pr_and_issue_discovery_enabled", - "direct_pr_requires_linked_issue", - "direct_pr_no_issue_required" - ] + "LocalDiffPreflightResult": { + "allOf": [ + { + "$ref": "#/components/schemas/PreflightResult" }, - "directPrReadiness": { + { "type": "object", "properties": { - "ready": { - "type": "boolean" - }, - "reasons": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": [ - "ready", - "reasons" - ] - }, - "issueDiscoveryReadiness": { - "type": "object", - "properties": { - "ready": { - "type": "boolean" - }, - "recommendation": { - "type": "string", - "enum": [ - "enabled", - "recommended", - "not_recommended" + "localDiff": { + "type": "object", + "properties": { + "changedFileCount": { + "type": "number" + }, + "changedLineCount": { + "type": "number" + }, + "testFileCount": { + "type": "number" + }, + "codeFileCount": { + "type": "number" + }, + "inferredLinkedIssues": { + "type": "array", + "items": { + "type": "number" + } + }, + "summary": { + "type": "string" + } + }, + "required": [ + "changedFileCount", + "changedLineCount", + "testFileCount", + "codeFileCount", + "inferredLinkedIssues", + "summary" ] - }, - "reasons": { - "type": "array", - "items": { - "type": "string" - } } }, "required": [ - "ready", - "recommendation", - "reasons" + "localDiff" ] + } + ] + }, + "LocalBranchAnalysis": { + "type": "object", + "properties": { + "login": { + "type": "string" }, - "labelPolicy": { - "type": "object", - "additionalProperties": { - "nullable": true - } + "repoFullName": { + "type": "string" }, - "maintainerCutReadiness": { - "type": "object", - "additionalProperties": { - "nullable": true - } + "generatedAt": { + "type": "string" }, - "testCoverageHealth": { + "baseRef": { + "type": "string" + }, + "headRef": { + "type": "string" + }, + "branchName": { + "type": "string" + }, + "baseFreshness": { "type": "object", "properties": { "status": { "type": "string", "enum": [ - "gate_ready", - "gate_unknown" + "fresh", + "stale", + "possibly_stale", + "unknown" ] }, - "trustedLabelPipelineReady": { - "type": "boolean" + "baseRef": { + "type": "string" }, - "checkRunMode": { - "type": "string", - "enum": [ - "off", - "enabled" - ] + "baseSha": { + "type": "string" }, - "requiredGate": { - "type": "array", - "items": { - "type": "string" - } + "headSha": { + "type": "string" }, - "note": { + "mergeBaseSha": { "type": "string" }, - "warnings": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": [ - "status", - "trustedLabelPipelineReady", - "checkRunMode", - "requiredGate", - "note", - "warnings" - ] - }, - "queueHealth": { - "type": "object", - "properties": { - "level": { - "type": "string", - "enum": [ - "low", - "medium", - "high", - "critical" - ] + "remoteTrackingSha": { + "type": "string" }, - "burdenScore": { + "changedFileCount": { "type": "number" }, - "reviewablePullRequests": { + "testFileCount": { "type": "number" }, - "summary": { - "type": "string" - } - }, - "required": [ - "level", - "burdenScore", - "reviewablePullRequests", - "summary" - ] - }, - "contributorIntakeHealth": { - "type": "object", - "additionalProperties": { - "nullable": true - } - }, - "docsCompleteness": { - "type": "object", - "additionalProperties": { - "nullable": true - } - }, - "githubApp": { - "type": "object", - "properties": { - "installed": { - "type": "boolean" - }, - "publicSurface": { - "type": "string", - "enum": [ - "off", - "comment_and_label", - "comment_only", - "label_only" - ] - }, - "commentMode": { - "type": "string", - "enum": [ - "off", - "detected_contributors_only", - "all_prs" - ] - }, - "checkRunMode": { - "type": "string", - "enum": [ - "off", - "enabled" - ] - }, - "quietByDefault": { - "type": "boolean" - }, - "behavior": { - "type": "string" + "passedValidationCount": { + "type": "number" }, "warnings": { "type": "array", "items": { "type": "string" } + }, + "recommendation": { + "type": "string" } }, "required": [ - "installed", - "publicSurface", - "commentMode", - "checkRunMode", - "quietByDefault", - "behavior", + "status", + "changedFileCount", + "testFileCount", + "passedValidationCount", "warnings" ] }, - "blockers": { - "type": "array", - "items": { - "type": "string" - } + "lane": { + "$ref": "#/components/schemas/LaneAdvice" }, - "warnings": { - "type": "array", - "items": { - "type": "string" - } + "roleContext": { + "$ref": "#/components/schemas/RoleContext" }, - "dataQuality": { - "type": "object", - "additionalProperties": { - "nullable": true - } - } - }, - "required": [ - "repoFullName", - "generatedAt", - "ready", - "recommendedRegistrationMode", - "issuePolicy", - "directPrReadiness", - "issueDiscoveryReadiness", - "labelPolicy", - "maintainerCutReadiness", - "testCoverageHealth", - "queueHealth", - "contributorIntakeHealth", - "docsCompleteness", - "githubApp", - "blockers", - "warnings", - "dataQuality" - ] - }, - "GittensorConfigRecommendation": { - "type": "object", - "properties": { - "repoFullName": { - "type": "string" - }, - "generatedAt": { - "type": "string" - }, - "privateOnly": { - "type": "boolean" - }, - "current": { - "type": "object", - "nullable": true, - "additionalProperties": { - "nullable": true - } - }, - "recommended": { - "type": "object", - "additionalProperties": { - "nullable": true - } - }, - "tradeoffs": { - "type": "array", - "items": { - "type": "string" - } - }, - "reasons": { - "type": "array", - "items": { - "type": "string" - } - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - } - }, - "dataQuality": { - "type": "object", - "additionalProperties": { - "nullable": true - } - } - }, - "required": [ - "repoFullName", - "generatedAt", - "privateOnly", - "current", - "recommended", - "tradeoffs", - "reasons", - "warnings", - "dataQuality" - ] - }, - "RepoFitRecommendation": { - "type": "object", - "properties": { - "login": { - "type": "string" - }, - "repoFullName": { - "type": "string" - }, - "generatedAt": { - "type": "string" - }, - "roleContext": { - "$ref": "#/components/schemas/RoleContext" - }, - "lane": { - "$ref": "#/components/schemas/LaneAdvice" - }, - "recommendation": { - "type": "string", - "enum": [ - "pursue", - "cleanup_first", - "maintainer_lane", - "avoid_for_now", - "unknown" - ] - }, - "confidence": { - "type": "string", - "enum": [ - "high", - "medium", - "low" - ] - }, - "reasons": { - "type": "array", - "items": { - "type": "string" - } - }, - "risks": { - "type": "array", - "items": { - "type": "string" - } - }, - "nextActions": { - "type": "array", - "items": { - "type": "string" - } - }, - "rewardRisk": { - "type": "object", - "additionalProperties": { - "nullable": true - } - }, - "reasoning": { - "type": "array", - "items": { - "type": "string" - } - }, - "actionImpact": { - "type": "object", - "additionalProperties": { - "nullable": true - } - } - }, - "required": [ - "login", - "repoFullName", - "generatedAt", - "roleContext", - "lane", - "recommendation", - "confidence", - "reasons", - "risks", - "nextActions" - ] - }, - "PreflightResult": { - "type": "object", - "properties": { - "repoFullName": { - "type": "string" - }, - "generatedAt": { - "type": "string" - }, - "status": { - "type": "string", - "enum": [ - "ready", - "needs_work", - "hold" - ] - }, - "lane": { - "$ref": "#/components/schemas/LaneAdvice" - }, - "reviewBurden": { - "type": "string", - "enum": [ - "low", - "medium", - "high" - ] - }, - "linkedIssues": { - "type": "array", - "items": { - "type": "number" - } - }, - "findings": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Finding" - } - }, - "collisions": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CollisionCluster" - } - } - }, - "required": [ - "repoFullName", - "generatedAt", - "status", - "lane", - "reviewBurden", - "linkedIssues", - "findings", - "collisions" - ] - }, - "LocalDiffPreflightResult": { - "allOf": [ - { - "$ref": "#/components/schemas/PreflightResult" - }, - { + "preflight": { + "$ref": "#/components/schemas/LocalDiffPreflightResult" + }, + "scorePreview": { + "$ref": "#/components/schemas/ScorePreviewResult" + }, + "scenarioScorePreview": { "type": "object", "properties": { - "localDiff": { + "current": { "type": "object", "properties": { - "changedFileCount": { - "type": "number" - }, - "changedLineCount": { - "type": "number" - }, - "testFileCount": { - "type": "number" + "name": { + "type": "string", + "enum": [ + "current", + "cleanGates", + "afterPendingMerges", + "afterApprovedPrsMerge", + "afterStalePrsClose", + "linkedIssueFixed", + "bestReasonableCase" + ] }, - "codeFileCount": { - "type": "number" + "source": { + "type": "string", + "enum": [ + "current_data", + "user_supplied", + "github_observed", + "gittensory_projection" + ] }, - "inferredLinkedIssues": { + "assumptions": { "type": "array", "items": { - "type": "number" + "type": "string" } }, - "summary": { + "scoreEstimate": { + "type": "object", + "properties": { + "baseScore": { + "type": "number" + }, + "densityMultiplier": { + "type": "number" + }, + "contributionBonus": { + "type": "number" + }, + "labelMultiplier": { + "type": "number" + }, + "issueMultiplier": { + "type": "number" + }, + "credibilityMultiplier": { + "type": "number" + }, + "reviewPenaltyMultiplier": { + "type": "number" + }, + "openPrMultiplier": { + "type": "number" + }, + "estimatedMergedScore": { + "type": "number" + }, + "pendingSaturationScore": { + "type": "number" + } + }, + "required": [ + "baseScore", + "densityMultiplier", + "contributionBonus", + "labelMultiplier", + "issueMultiplier", + "credibilityMultiplier", + "reviewPenaltyMultiplier", + "openPrMultiplier", + "estimatedMergedScore", + "pendingSaturationScore" + ] + }, + "gates": { + "type": "object", + "properties": { + "baseTokenGatePassed": { + "type": "boolean" + }, + "openPrThreshold": { + "type": "number" + }, + "openPrCount": { + "type": "number" + }, + "collateralFraction": { + "type": "number" + }, + "credibilityFloor": { + "type": "number" + }, + "credibilityObserved": { + "type": "number" + } + }, + "required": [ + "baseTokenGatePassed", + "openPrThreshold", + "openPrCount", + "collateralFraction", + "credibilityFloor", + "credibilityObserved" + ] + }, + "effectiveEstimatedScore": { + "type": "number" + }, + "underlyingPotentialScore": { + "type": "number" + }, + "blockedBy": { + "type": "array", + "items": { + "type": "object", + "properties": { + "code": { + "type": "string", + "enum": [ + "repo_not_registered", + "inactive_allocation", + "base_token_gate", + "open_pr_threshold", + "credibility_floor", + "review_penalty", + "metadata_only", + "linked_issue_invalid", + "linked_issue_unvalidated", + "branch_ineligible", + "branch_eligibility_missing" + ] + }, + "severity": { + "type": "string", + "enum": [ + "blocker", + "reducer", + "context" + ] + }, + "detail": { + "type": "string" + } + }, + "required": [ + "code", + "severity", + "detail" + ] + } + }, + "linkedIssueMultiplier": { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "none", + "standard", + "maintainer" + ] + }, + "status": { + "type": "string", + "enum": [ + "not_required", + "raw", + "plausible", + "validated", + "invalid", + "unavailable" + ] + }, + "source": { + "type": "string", + "enum": [ + "none", + "user_supplied", + "official_mirror", + "github_cache", + "issue_quality", + "missing" + ] + }, + "eligible": { + "type": "boolean" + }, + "issueNumbers": { + "type": "array", + "items": { + "type": "number" + } + }, + "solvedByPullRequests": { + "type": "array", + "items": { + "type": "number" + } + }, + "baseMultiplier": { + "type": "number" + }, + "appliedMultiplier": { + "type": "number" + }, + "reason": { + "type": "string" + }, + "warnings": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "mode", + "status", + "source", + "eligible", + "issueNumbers", + "solvedByPullRequests", + "baseMultiplier", + "appliedMultiplier", + "reason", + "warnings" + ] + }, + "deltaExplanation": { "type": "string" } }, "required": [ - "changedFileCount", - "changedLineCount", - "testFileCount", - "codeFileCount", - "inferredLinkedIssues", - "summary" + "name", + "source", + "assumptions", + "scoreEstimate", + "gates", + "effectiveEstimatedScore", + "underlyingPotentialScore", + "blockedBy", + "linkedIssueMultiplier", + "deltaExplanation" ] - } - }, - "required": [ - "localDiff" - ] - } - ] - }, - "ScorePreviewResult": { - "type": "object", - "properties": { - "repoFullName": { - "type": "string" - }, - "generatedAt": { - "type": "string" - }, - "scoringModelSnapshotId": { - "type": "string" - }, - "activeModel": { - "type": "string", - "enum": [ - "current_density_model", - "pending_saturation_model", - "exponential_saturation_model", - "unknown" - ] - }, - "privateOnly": { - "type": "boolean", - "enum": [ - true - ] - }, - "laneMath": { - "type": "object", - "additionalProperties": { - "type": "number" - } - }, - "scoreEstimate": { - "type": "object", - "properties": { - "baseScore": { - "type": "number" - }, - "densityMultiplier": { - "type": "number" - }, - "contributionBonus": { - "type": "number" - }, - "labelMultiplier": { - "type": "number" - }, - "issueMultiplier": { - "type": "number" - }, - "credibilityMultiplier": { - "type": "number" - }, - "reviewPenaltyMultiplier": { - "type": "number" - }, - "openPrMultiplier": { - "type": "number" - }, - "estimatedMergedScore": { - "type": "number" - }, - "pendingSaturationScore": { - "type": "number" - } - }, - "required": [ - "baseScore", - "densityMultiplier", - "contributionBonus", - "labelMultiplier", - "issueMultiplier", - "credibilityMultiplier", - "reviewPenaltyMultiplier", - "openPrMultiplier", - "estimatedMergedScore", - "pendingSaturationScore" - ] - }, - "linkedIssueMultiplier": { - "type": "object", - "properties": { - "mode": { - "type": "string", - "enum": [ - "none", - "standard", - "maintainer" - ] - }, - "status": { - "type": "string", - "enum": [ - "not_required", - "raw", - "plausible", - "validated", - "invalid", - "unavailable" - ] - }, - "source": { - "type": "string", - "enum": [ - "none", - "user_supplied", - "official_mirror", - "github_cache", - "issue_quality", - "missing" - ] - }, - "eligible": { - "type": "boolean" - }, - "issueNumbers": { - "type": "array", - "items": { - "type": "number" - } - }, - "solvedByPullRequests": { - "type": "array", - "items": { - "type": "number" - } - }, - "baseMultiplier": { - "type": "number" - }, - "appliedMultiplier": { - "type": "number" - }, - "reason": { - "type": "string" - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": [ - "mode", - "status", - "source", - "eligible", - "issueNumbers", - "solvedByPullRequests", - "baseMultiplier", - "appliedMultiplier", - "reason", - "warnings" - ] - }, - "gates": { - "type": "object", - "properties": { - "baseTokenGatePassed": { - "type": "boolean" - }, - "openPrThreshold": { - "type": "number" - }, - "openPrCount": { - "type": "number" - }, - "collateralFraction": { - "type": "number" - }, - "credibilityFloor": { - "type": "number" - }, - "credibilityObserved": { - "type": "number" - } - }, - "required": [ - "baseTokenGatePassed", - "openPrThreshold", - "openPrCount", - "collateralFraction", - "credibilityFloor", - "credibilityObserved" - ] - }, - "branchEligibility": { - "type": "object", - "properties": { - "required": { - "type": "boolean" - }, - "status": { - "type": "string", - "enum": [ - "eligible", - "ineligible", - "unknown", - "not_required" - ] - }, - "evidence": { - "type": "string", - "enum": [ - "provided", - "missing" - ] - }, - "source": { - "type": "string", - "enum": [ - "github_metadata", - "local_metadata", - "registry", - "user_supplied", - "missing" - ] - }, - "reason": { - "type": "string" - }, - "checkedAt": { - "type": "string" - }, - "stale": { - "type": "boolean" - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": [ - "required", - "status", - "evidence", - "source", - "stale", - "warnings" - ] - }, - "effectiveEstimatedScore": { - "type": "number" - }, - "underlyingPotentialScore": { - "type": "number" - }, - "blockedBy": { - "type": "array", - "items": { - "type": "object", - "properties": { - "code": { - "type": "string", - "enum": [ - "repo_not_registered", - "inactive_allocation", - "base_token_gate", - "open_pr_threshold", - "credibility_floor", - "review_penalty", - "metadata_only", - "linked_issue_invalid", - "linked_issue_unvalidated", - "branch_ineligible", - "branch_eligibility_missing" - ] - }, - "severity": { - "type": "string", - "enum": [ - "blocker", - "reducer", - "context" - ] - }, - "detail": { - "type": "string" - } - }, - "required": [ - "code", - "severity", - "detail" - ] - } - }, - "gateDeltas": { - "type": "array", - "items": { - "type": "object", - "properties": { - "gate": { - "type": "string", - "enum": [ - "open_pr_threshold", - "credibility_floor", - "linked_issue_multiplier" - ] - }, - "current": { - "type": "string" - }, - "projected": { - "type": "string" - }, - "explanation": { - "type": "string" - } - }, - "required": [ - "gate", - "current", - "projected", - "explanation" - ] - } - }, - "scenarioPreviews": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "enum": [ - "current", - "cleanGates", - "afterPendingMerges", - "afterApprovedPrsMerge", - "afterStalePrsClose", - "linkedIssueFixed", - "bestReasonableCase" - ] - }, - "source": { - "type": "string", - "enum": [ - "current_data", - "user_supplied", - "github_observed", - "gittensory_projection" - ] - }, - "assumptions": { - "type": "array", - "items": { - "type": "string" - } - }, - "scoreEstimate": { - "type": "object", - "properties": { - "baseScore": { - "type": "number" - }, - "densityMultiplier": { - "type": "number" - }, - "contributionBonus": { - "type": "number" - }, - "labelMultiplier": { - "type": "number" - }, - "issueMultiplier": { - "type": "number" - }, - "credibilityMultiplier": { - "type": "number" - }, - "reviewPenaltyMultiplier": { - "type": "number" - }, - "openPrMultiplier": { - "type": "number" - }, - "estimatedMergedScore": { - "type": "number" - }, - "pendingSaturationScore": { - "type": "number" - } - }, - "required": [ - "baseScore", - "densityMultiplier", - "contributionBonus", - "labelMultiplier", - "issueMultiplier", - "credibilityMultiplier", - "reviewPenaltyMultiplier", - "openPrMultiplier", - "estimatedMergedScore", - "pendingSaturationScore" - ] - }, - "gates": { - "type": "object", - "properties": { - "baseTokenGatePassed": { - "type": "boolean" - }, - "openPrThreshold": { - "type": "number" - }, - "openPrCount": { - "type": "number" - }, - "collateralFraction": { - "type": "number" - }, - "credibilityFloor": { - "type": "number" - }, - "credibilityObserved": { - "type": "number" - } - }, - "required": [ - "baseTokenGatePassed", - "openPrThreshold", - "openPrCount", - "collateralFraction", - "credibilityFloor", - "credibilityObserved" - ] - }, - "effectiveEstimatedScore": { - "type": "number" - }, - "underlyingPotentialScore": { - "type": "number" - }, - "blockedBy": { - "type": "array", - "items": { - "type": "object", - "properties": { - "code": { - "type": "string", - "enum": [ - "repo_not_registered", - "inactive_allocation", - "base_token_gate", - "open_pr_threshold", - "credibility_floor", - "review_penalty", - "metadata_only", - "linked_issue_invalid", - "linked_issue_unvalidated", - "branch_ineligible", - "branch_eligibility_missing" - ] - }, - "severity": { - "type": "string", - "enum": [ - "blocker", - "reducer", - "context" - ] - }, - "detail": { - "type": "string" - } - }, - "required": [ - "code", - "severity", - "detail" - ] - } - }, - "linkedIssueMultiplier": { - "type": "object", - "properties": { - "mode": { - "type": "string", - "enum": [ - "none", - "standard", - "maintainer" - ] - }, - "status": { - "type": "string", - "enum": [ - "not_required", - "raw", - "plausible", - "validated", - "invalid", - "unavailable" - ] - }, - "source": { - "type": "string", - "enum": [ - "none", - "user_supplied", - "official_mirror", - "github_cache", - "issue_quality", - "missing" - ] - }, - "eligible": { - "type": "boolean" - }, - "issueNumbers": { - "type": "array", - "items": { - "type": "number" - } - }, - "solvedByPullRequests": { - "type": "array", - "items": { - "type": "number" - } - }, - "baseMultiplier": { - "type": "number" - }, - "appliedMultiplier": { - "type": "number" - }, - "reason": { - "type": "string" - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": [ - "mode", - "status", - "source", - "eligible", - "issueNumbers", - "solvedByPullRequests", - "baseMultiplier", - "appliedMultiplier", - "reason", - "warnings" - ] - }, - "deltaExplanation": { - "type": "string" - } - }, - "required": [ - "name", - "source", - "assumptions", - "scoreEstimate", - "gates", - "effectiveEstimatedScore", - "underlyingPotentialScore", - "blockedBy", - "linkedIssueMultiplier", - "deltaExplanation" - ] - } - }, - "scoreabilityStatus": { - "type": "string", - "enum": [ - "blocked", - "conditionally_scoreable", - "scoreable", - "hold" - ] - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - } - }, - "assumptions": { - "type": "array", - "items": { - "type": "string" - } - }, - "recommendation": { - "type": "object", - "properties": { - "level": { - "type": "string", - "enum": [ - "strong_fit", - "reasonable_fit", - "needs_work", - "hold" - ] - }, - "actions": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": [ - "level", - "actions" - ] - } - }, - "required": [ - "repoFullName", - "generatedAt", - "scoringModelSnapshotId", - "activeModel", - "privateOnly", - "laneMath", - "scoreEstimate", - "linkedIssueMultiplier", - "gates", - "branchEligibility", - "effectiveEstimatedScore", - "underlyingPotentialScore", - "blockedBy", - "gateDeltas", - "scenarioPreviews", - "scoreabilityStatus", - "warnings", - "assumptions", - "recommendation" - ] - }, - "RewardRiskAction": { - "type": "object", - "properties": { - "actionKind": { - "type": "string", - "enum": [ - "cleanup_existing_prs", - "land_existing_prs", - "close_or_withdraw_low_fit_prs", - "open_new_direct_pr", - "file_issue_discovery", - "maintainer_lane_improve_repo", - "maintainer_cut_readiness" - ] - }, - "repoFullName": { - "type": "string" - }, - "priorityScore": { - "type": "number" - }, - "laneValueScore": { - "type": "number" - }, - "scoreabilityScore": { - "type": "number" - }, - "personalFitScore": { - "type": "number" - }, - "riskPenalty": { - "type": "number" - }, - "maintainerFrictionPenalty": { - "type": "number" - }, - "actionLeverageScore": { - "type": "number" - }, - "whyThisHelps": { - "type": "array", - "items": { - "type": "string" - } - }, - "nextActions": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": [ - "actionKind", - "repoFullName", - "priorityScore", - "laneValueScore", - "scoreabilityScore", - "personalFitScore", - "riskPenalty", - "maintainerFrictionPenalty", - "actionLeverageScore", - "whyThisHelps", - "nextActions" - ] - }, - "RepoRewardRisk": { - "type": "object", - "properties": { - "login": { - "type": "string" - }, - "repoFullName": { - "type": "string" - }, - "generatedAt": { - "type": "string" - }, - "roleContext": { - "$ref": "#/components/schemas/RoleContext" - }, - "lane": { - "$ref": "#/components/schemas/LaneAdvice" - }, - "recommendation": { - "type": "string", - "enum": [ - "pursue", - "cleanup_first", - "maintainer_lane", - "avoid_for_now", - "unknown" - ] - }, - "rewardUpside": { - "type": "object", - "properties": { - "relevantLane": { - "type": "string", - "enum": [ - "direct_pr", - "issue_discovery", - "maintainer_lane", - "none" - ] - }, - "repoSlice": { - "type": "number" - }, - "directPrSlice": { - "type": "number" - }, - "issueDiscoverySlice": { - "type": "number" - }, - "maintainerCutSlice": { - "type": "number" - }, - "labelMultiplier": { - "type": "number" - }, - "issueMultiplier": { - "type": "number" - }, - "estimatedScoreIfClean": { - "type": "number" - }, - "currentEstimatedScore": { - "type": "number" - } - }, - "required": [ - "relevantLane", - "repoSlice", - "directPrSlice", - "issueDiscoverySlice", - "maintainerCutSlice", - "labelMultiplier", - "issueMultiplier", - "estimatedScoreIfClean", - "currentEstimatedScore" - ] - }, - "scoreBlockers": { - "type": "array", - "items": { - "type": "string" - } - }, - "riskBreakdown": { - "type": "object", - "properties": { - "queueBurden": { - "type": "string", - "enum": [ - "low", - "medium", - "high", - "critical" - ] - }, - "queueBurdenScore": { - "type": "number" - }, - "duplicateClusters": { - "type": "number" - }, - "highRiskDuplicateClusters": { - "type": "number" - }, - "closedPullRequestRate": { - "type": "number" - }, - "openPullRequests": { - "type": "number" - }, - "credibility": { - "type": "number" - }, - "reviewChurnRisk": { - "type": "string", - "enum": [ - "low", - "medium", - "high" - ] - } - }, - "required": [ - "queueBurden", - "queueBurdenScore", - "duplicateClusters", - "highRiskDuplicateClusters", - "closedPullRequestRate", - "openPullRequests", - "credibility", - "reviewChurnRisk" - ] - }, - "actionImpact": { - "type": "object", - "additionalProperties": { - "nullable": true - } - }, - "currentPreview": { - "type": "object", - "additionalProperties": { - "nullable": true - } - }, - "afterCleanupPreview": { - "type": "object", - "additionalProperties": { - "nullable": true - } - }, - "actions": { - "type": "array", - "items": { - "$ref": "#/components/schemas/RewardRiskAction" - } - }, - "whyThisHelps": { - "type": "array", - "items": { - "type": "string" - } - }, - "nextActions": { - "type": "array", - "items": { - "type": "string" - } - }, - "summary": { - "type": "string" - } - }, - "required": [ - "login", - "repoFullName", - "generatedAt", - "roleContext", - "lane", - "recommendation", - "rewardUpside", - "scoreBlockers", - "riskBreakdown", - "actionImpact", - "currentPreview", - "afterCleanupPreview", - "actions", - "whyThisHelps", - "nextActions", - "summary" - ] - }, - "LocalWorkspaceIntelligence": { - "type": "object", - "properties": { - "version": { - "type": "number", - "enum": [ - 2 - ] - }, - "sourceUpload": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "enum": [ - false - ] - }, - "detail": { - "type": "string" - } - }, - "required": [ - "enabled", - "detail" - ] - }, - "branch": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "baseRef": { - "type": "string" - }, - "headSha": { - "type": "string" - }, - "pendingCommitCount": { - "type": "number" - } - }, - "required": [ - "pendingCommitCount" - ] - }, - "changedFiles": { - "type": "object", - "properties": { - "total": { - "type": "number" - }, - "added": { - "type": "number" - }, - "modified": { - "type": "number" - }, - "deleted": { - "type": "number" - }, - "renamed": { - "type": "number" - }, - "binary": { - "type": "number" - }, - "paths": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": [ - "total", - "added", - "modified", - "deleted", - "renamed", - "binary", - "paths" - ] - }, - "testEvidence": { - "type": "object", - "properties": { - "level": { - "type": "string", - "enum": [ - "test_files", - "validation_commands", - "both", - "none" - ] - }, - "testFileCount": { - "type": "number" - }, - "passedValidationCount": { - "type": "number" }, - "commands": { - "type": "array", - "items": { - "type": "object", - "properties": { - "command": { + "bestReasonableCase": { + "type": "object", + "properties": { + "name": { + "type": "string", + "enum": [ + "current", + "cleanGates", + "afterPendingMerges", + "afterApprovedPrsMerge", + "afterStalePrsClose", + "linkedIssueFixed", + "bestReasonableCase" + ] + }, + "source": { + "type": "string", + "enum": [ + "current_data", + "user_supplied", + "github_observed", + "gittensory_projection" + ] + }, + "assumptions": { + "type": "array", + "items": { "type": "string" + } + }, + "scoreEstimate": { + "type": "object", + "properties": { + "baseScore": { + "type": "number" + }, + "densityMultiplier": { + "type": "number" + }, + "contributionBonus": { + "type": "number" + }, + "labelMultiplier": { + "type": "number" + }, + "issueMultiplier": { + "type": "number" + }, + "credibilityMultiplier": { + "type": "number" + }, + "reviewPenaltyMultiplier": { + "type": "number" + }, + "openPrMultiplier": { + "type": "number" + }, + "estimatedMergedScore": { + "type": "number" + }, + "pendingSaturationScore": { + "type": "number" + } }, - "status": { - "type": "string", - "enum": [ - "passed", - "failed", - "not_run" + "required": [ + "baseScore", + "densityMultiplier", + "contributionBonus", + "labelMultiplier", + "issueMultiplier", + "credibilityMultiplier", + "reviewPenaltyMultiplier", + "openPrMultiplier", + "estimatedMergedScore", + "pendingSaturationScore" + ] + }, + "gates": { + "type": "object", + "properties": { + "baseTokenGatePassed": { + "type": "boolean" + }, + "openPrThreshold": { + "type": "number" + }, + "openPrCount": { + "type": "number" + }, + "collateralFraction": { + "type": "number" + }, + "credibilityFloor": { + "type": "number" + }, + "credibilityObserved": { + "type": "number" + } + }, + "required": [ + "baseTokenGatePassed", + "openPrThreshold", + "openPrCount", + "collateralFraction", + "credibilityFloor", + "credibilityObserved" + ] + }, + "effectiveEstimatedScore": { + "type": "number" + }, + "underlyingPotentialScore": { + "type": "number" + }, + "blockedBy": { + "type": "array", + "items": { + "type": "object", + "properties": { + "code": { + "type": "string", + "enum": [ + "repo_not_registered", + "inactive_allocation", + "base_token_gate", + "open_pr_threshold", + "credibility_floor", + "review_penalty", + "metadata_only", + "linked_issue_invalid", + "linked_issue_unvalidated", + "branch_ineligible", + "branch_eligibility_missing" + ] + }, + "severity": { + "type": "string", + "enum": [ + "blocker", + "reducer", + "context" + ] + }, + "detail": { + "type": "string" + } + }, + "required": [ + "code", + "severity", + "detail" ] - }, - "summary": { - "type": "string" } }, - "required": [ - "command", - "status" - ] - } - } - }, - "required": [ - "level", - "testFileCount", - "passedValidationCount", - "commands" - ] - }, - "linkedIssues": { - "type": "array", - "items": { - "type": "number" - } - }, - "baseFreshness": { - "type": "object", - "properties": { - "status": { - "type": "string", - "enum": [ - "fresh", - "stale", - "possibly_stale", - "unknown" - ] - }, - "baseRef": { - "type": "string" - }, - "baseSha": { - "type": "string" - }, - "headSha": { - "type": "string" - }, - "mergeBaseSha": { - "type": "string" - }, - "remoteTrackingSha": { - "type": "string" - }, - "changedFileCount": { - "type": "number" - }, - "testFileCount": { - "type": "number" - }, - "passedValidationCount": { - "type": "number" - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - } - }, - "recommendation": { - "type": "string" - } - }, - "required": [ - "status", - "changedFileCount", - "testFileCount", - "passedValidationCount", - "warnings" - ] - }, - "ciStatusHints": { - "type": "array", - "items": { - "type": "string" - } - }, - "localScorerDiagnostics": { - "type": "object", - "properties": { - "mode": { - "type": "string" - }, - "activeModel": { - "type": "string" - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - } - }, - "metadataOnly": { - "type": "boolean" - } - }, - "required": [ - "mode", - "warnings", - "metadataOnly" - ] - }, - "blockers": { - "type": "object", - "properties": { - "branchQuality": { - "type": "array", - "items": { - "type": "string" - } - }, - "accountState": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": [ - "branchQuality", - "accountState" - ] - }, - "rerunWhen": { - "type": "string" - } - }, - "required": [ - "version", - "sourceUpload", - "branch", - "changedFiles", - "testEvidence", - "linkedIssues", - "baseFreshness", - "ciStatusHints", - "blockers", - "rerunWhen" - ] - }, - "LocalBranchAnalysis": { - "type": "object", - "properties": { - "login": { - "type": "string" - }, - "repoFullName": { - "type": "string" - }, - "generatedAt": { - "type": "string" - }, - "baseRef": { - "type": "string" - }, - "headRef": { - "type": "string" - }, - "branchName": { - "type": "string" - }, - "baseFreshness": { - "type": "object", - "properties": { - "status": { - "type": "string", - "enum": [ - "fresh", - "stale", - "possibly_stale", - "unknown" + "linkedIssueMultiplier": { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "none", + "standard", + "maintainer" + ] + }, + "status": { + "type": "string", + "enum": [ + "not_required", + "raw", + "plausible", + "validated", + "invalid", + "unavailable" + ] + }, + "source": { + "type": "string", + "enum": [ + "none", + "user_supplied", + "official_mirror", + "github_cache", + "issue_quality", + "missing" + ] + }, + "eligible": { + "type": "boolean" + }, + "issueNumbers": { + "type": "array", + "items": { + "type": "number" + } + }, + "solvedByPullRequests": { + "type": "array", + "items": { + "type": "number" + } + }, + "baseMultiplier": { + "type": "number" + }, + "appliedMultiplier": { + "type": "number" + }, + "reason": { + "type": "string" + }, + "warnings": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "mode", + "status", + "source", + "eligible", + "issueNumbers", + "solvedByPullRequests", + "baseMultiplier", + "appliedMultiplier", + "reason", + "warnings" + ] + }, + "deltaExplanation": { + "type": "string" + } + }, + "required": [ + "name", + "source", + "assumptions", + "scoreEstimate", + "gates", + "effectiveEstimatedScore", + "underlyingPotentialScore", + "blockedBy", + "linkedIssueMultiplier", + "deltaExplanation" ] }, - "baseRef": { - "type": "string" - }, - "baseSha": { - "type": "string" - }, - "headSha": { - "type": "string" - }, - "mergeBaseSha": { - "type": "string" - }, - "remoteTrackingSha": { - "type": "string" - }, - "changedFileCount": { - "type": "number" - }, - "testFileCount": { - "type": "number" - }, - "passedValidationCount": { - "type": "number" - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - } - }, - "recommendation": { - "type": "string" - } - }, - "required": [ - "status", - "changedFileCount", - "testFileCount", - "passedValidationCount", - "warnings" - ] - }, - "lane": { - "$ref": "#/components/schemas/LaneAdvice" - }, - "roleContext": { - "$ref": "#/components/schemas/RoleContext" - }, - "preflight": { - "$ref": "#/components/schemas/LocalDiffPreflightResult" - }, - "scorePreview": { - "$ref": "#/components/schemas/ScorePreviewResult" - }, - "scenarioScorePreview": { - "type": "object", - "properties": { - "current": { + "afterPendingMerges": { "type": "object", "properties": { "name": { @@ -4777,7 +4108,7 @@ "deltaExplanation" ] }, - "bestReasonableCase": { + "afterApprovedPrsMerge": { "type": "object", "properties": { "name": { @@ -5025,7 +4356,7 @@ "deltaExplanation" ] }, - "afterPendingMerges": { + "afterStalePrsClose": { "type": "object", "properties": { "name": { @@ -5273,796 +4604,1542 @@ "deltaExplanation" ] }, - "afterApprovedPrsMerge": { - "type": "object", - "properties": { - "name": { - "type": "string", - "enum": [ - "current", - "cleanGates", - "afterPendingMerges", - "afterApprovedPrsMerge", - "afterStalePrsClose", - "linkedIssueFixed", - "bestReasonableCase" - ] - }, - "source": { - "type": "string", - "enum": [ - "current_data", - "user_supplied", - "github_observed", - "gittensory_projection" - ] - }, - "assumptions": { - "type": "array", - "items": { + "gateDeltas": { + "type": "array", + "items": { + "type": "object", + "properties": { + "gate": { + "type": "string", + "enum": [ + "open_pr_threshold", + "credibility_floor", + "linked_issue_multiplier" + ] + }, + "current": { + "type": "string" + }, + "projected": { + "type": "string" + }, + "explanation": { + "type": "string" + } + }, + "required": [ + "gate", + "current", + "projected", + "explanation" + ] + } + }, + "blockedBy": { + "type": "array", + "items": { + "type": "object", + "properties": { + "code": { + "type": "string", + "enum": [ + "repo_not_registered", + "inactive_allocation", + "base_token_gate", + "open_pr_threshold", + "credibility_floor", + "review_penalty", + "metadata_only", + "linked_issue_invalid", + "linked_issue_unvalidated", + "branch_ineligible", + "branch_eligibility_missing" + ] + }, + "severity": { + "type": "string", + "enum": [ + "blocker", + "reducer", + "context" + ] + }, + "detail": { + "type": "string" + } + }, + "required": [ + "code", + "severity", + "detail" + ] + } + } + }, + "required": [ + "current", + "bestReasonableCase", + "gateDeltas", + "blockedBy" + ] + }, + "observedPullRequestScenarios": { + "type": "object", + "properties": { + "approvedOrMergeable": { + "type": "number" + }, + "stale": { + "type": "number" + }, + "closed": { + "type": "number" + }, + "draft": { + "type": "number" + }, + "blocked": { + "type": "number" + }, + "maintainerLane": { + "type": "number" + }, + "notes": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "approvedOrMergeable", + "stale", + "closed", + "draft", + "blocked", + "maintainerLane", + "notes" + ] + }, + "githubBranchStatus": { + "type": "object", + "properties": { + "source": { + "type": "string", + "enum": [ + "cached_github_data" + ] + }, + "status": { + "type": "string", + "enum": [ + "approved", + "failing_checks", + "needs_author", + "blocked", + "pending_review", + "no_pr", + "unknown" + ] + }, + "pullNumber": { + "type": "number" + }, + "title": { + "type": "string" + }, + "reviewDecision": { + "type": "string", + "nullable": true + }, + "mergeableState": { + "type": "string", + "nullable": true + }, + "notes": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "source", + "status", + "notes" + ] + }, + "branchEligibility": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "status": { + "type": "string", + "enum": [ + "eligible", + "ineligible", + "unknown", + "not_required" + ] + }, + "evidence": { + "type": "string", + "enum": [ + "provided", + "missing" + ] + }, + "source": { + "type": "string", + "enum": [ + "github_metadata", + "local_metadata", + "registry", + "user_supplied", + "missing" + ] + }, + "reason": { + "type": "string" + }, + "checkedAt": { + "type": "string" + }, + "stale": { + "type": "boolean" + }, + "warnings": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "required", + "status", + "evidence", + "source", + "stale", + "warnings" + ] + }, + "rewardRisk": { + "$ref": "#/components/schemas/RepoRewardRisk" + }, + "scoreBlockers": { + "type": "array", + "items": { + "type": "string" + } + }, + "branchQualityBlockers": { + "type": "array", + "items": { + "type": "string" + } + }, + "accountStateBlockers": { + "type": "array", + "items": { + "type": "string" + } + }, + "recommendedRerunCondition": { + "type": "string" + }, + "localFindings": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Finding" + } + }, + "maintainerFit": { + "type": "object", + "properties": { + "recommendation": { + "type": "string", + "enum": [ + "pursue", + "cleanup_first", + "maintainer_lane", + "avoid_for_now", + "unknown" + ] + }, + "reviewBurden": { + "type": "string", + "enum": [ + "low", + "medium", + "high" + ] + }, + "role": { + "type": "string", + "enum": [ + "outside_contributor", + "repo_maintainer", + "org_member", + "collaborator", + "owner", + "unknown" + ] + }, + "maintainerLane": { + "type": "boolean" + }, + "reasons": { + "type": "array", + "items": { + "type": "string" + } + }, + "risks": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "recommendation", + "reviewBurden", + "role", + "maintainerLane", + "reasons", + "risks" + ] + }, + "manifestGuidance": { + "type": "object", + "properties": { + "present": { + "type": "boolean" + }, + "source": { + "type": "string", + "enum": [ + "repo_file", + "api_record", + "none" + ] + }, + "linkedIssuePolicy": { + "type": "string", + "enum": [ + "required", + "preferred", + "optional" + ] + }, + "issueDiscoveryPolicy": { + "type": "string", + "enum": [ + "encouraged", + "neutral", + "discouraged" + ] + }, + "matchedWantedPaths": { + "type": "array", + "items": { + "type": "string" + } + }, + "matchedBlockedPaths": { + "type": "array", + "items": { + "type": "string" + } + }, + "preferredLabelHits": { + "type": "array", + "items": { + "type": "string" + } + }, + "findings": { + "type": "array", + "items": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "severity": { + "type": "string", + "enum": [ + "info", + "warning", + "critical" + ] + }, + "title": { + "type": "string" + }, + "detail": { + "type": "string" + }, + "action": { "type": "string" } }, - "scoreEstimate": { - "type": "object", - "properties": { - "baseScore": { - "type": "number" - }, - "densityMultiplier": { - "type": "number" - }, - "contributionBonus": { - "type": "number" - }, - "labelMultiplier": { - "type": "number" - }, - "issueMultiplier": { - "type": "number" - }, - "credibilityMultiplier": { - "type": "number" - }, - "reviewPenaltyMultiplier": { - "type": "number" - }, - "openPrMultiplier": { - "type": "number" - }, - "estimatedMergedScore": { - "type": "number" - }, - "pendingSaturationScore": { - "type": "number" - } + "required": [ + "code", + "severity", + "title", + "detail" + ] + } + }, + "publicNextSteps": { + "type": "array", + "items": { + "type": "string" + } + }, + "warnings": { + "type": "array", + "items": { + "type": "string" + } + }, + "summary": { + "type": "string" + } + }, + "required": [ + "present", + "source", + "linkedIssuePolicy", + "issueDiscoveryPolicy", + "matchedWantedPaths", + "matchedBlockedPaths", + "preferredLabelHits", + "findings", + "publicNextSteps", + "warnings", + "summary" + ] + }, + "prPacket": { + "type": "object", + "properties": { + "titleSuggestion": { + "type": "string" + }, + "markdown": { + "type": "string" + }, + "bodySections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "heading": { + "type": "string" }, - "required": [ - "baseScore", - "densityMultiplier", - "contributionBonus", - "labelMultiplier", - "issueMultiplier", - "credibilityMultiplier", - "reviewPenaltyMultiplier", - "openPrMultiplier", - "estimatedMergedScore", - "pendingSaturationScore" - ] - }, - "gates": { - "type": "object", - "properties": { - "baseTokenGatePassed": { - "type": "boolean" - }, - "openPrThreshold": { - "type": "number" - }, - "openPrCount": { - "type": "number" - }, - "collateralFraction": { - "type": "number" - }, - "credibilityFloor": { - "type": "number" - }, - "credibilityObserved": { - "type": "number" + "lines": { + "type": "array", + "items": { + "type": "string" } - }, - "required": [ - "baseTokenGatePassed", - "openPrThreshold", - "openPrCount", - "collateralFraction", - "credibilityFloor", - "credibilityObserved" - ] + } }, - "effectiveEstimatedScore": { + "required": [ + "heading", + "lines" + ] + } + }, + "reviewerNotes": { + "type": "array", + "items": { + "type": "string" + } + }, + "validationSummary": { + "type": "object", + "properties": { + "passed": { "type": "number" }, - "underlyingPotentialScore": { + "failed": { "type": "number" }, - "blockedBy": { - "type": "array", - "items": { - "type": "object", - "properties": { - "code": { - "type": "string", - "enum": [ - "repo_not_registered", - "inactive_allocation", - "base_token_gate", - "open_pr_threshold", - "credibility_floor", - "review_penalty", - "metadata_only", - "linked_issue_invalid", - "linked_issue_unvalidated", - "branch_ineligible", - "branch_eligibility_missing" - ] - }, - "severity": { - "type": "string", - "enum": [ - "blocker", - "reducer", - "context" - ] - }, - "detail": { - "type": "string" - } - }, - "required": [ - "code", - "severity", - "detail" - ] - } + "notRun": { + "type": "number" }, - "linkedIssueMultiplier": { - "type": "object", - "properties": { - "mode": { - "type": "string", - "enum": [ - "none", - "standard", - "maintainer" - ] - }, - "status": { - "type": "string", - "enum": [ - "not_required", - "raw", - "plausible", - "validated", - "invalid", - "unavailable" - ] - }, - "source": { - "type": "string", - "enum": [ - "none", - "user_supplied", - "official_mirror", - "github_cache", - "issue_quality", - "missing" - ] - }, - "eligible": { - "type": "boolean" - }, - "issueNumbers": { - "type": "array", - "items": { + "commands": { + "type": "array", + "items": { + "type": "object", + "properties": { + "command": { + "type": "string" + }, + "status": { + "type": "string", + "enum": [ + "passed", + "failed", + "not_run", + "skipped", + "focused", + "unknown" + ] + }, + "summary": { + "type": "string" + }, + "durationMs": { "type": "number" - } - }, - "solvedByPullRequests": { - "type": "array", - "items": { + }, + "exitCode": { "type": "number" } }, - "baseMultiplier": { - "type": "number" - }, - "appliedMultiplier": { - "type": "number" - }, - "reason": { - "type": "string" - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": [ - "mode", - "status", - "source", - "eligible", - "issueNumbers", - "solvedByPullRequests", - "baseMultiplier", - "appliedMultiplier", - "reason", - "warnings" - ] - }, - "deltaExplanation": { - "type": "string" + "required": [ + "command", + "status" + ] + } } }, "required": [ - "name", - "source", - "assumptions", - "scoreEstimate", - "gates", - "effectiveEstimatedScore", - "underlyingPotentialScore", - "blockedBy", - "linkedIssueMultiplier", - "deltaExplanation" + "passed", + "failed", + "notRun", + "commands" + ] + }, + "publicSafeWarnings": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "titleSuggestion", + "markdown", + "bodySections", + "reviewerNotes", + "validationSummary", + "publicSafeWarnings" + ] + }, + "nextActions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RewardRiskAction" + } + }, + "workspaceIntelligence": { + "$ref": "#/components/schemas/LocalWorkspaceIntelligence" + }, + "summary": { + "type": "string" + } + }, + "required": [ + "login", + "repoFullName", + "generatedAt", + "baseFreshness", + "lane", + "roleContext", + "preflight", + "scorePreview", + "scenarioScorePreview", + "observedPullRequestScenarios", + "githubBranchStatus", + "branchEligibility", + "rewardRisk", + "scoreBlockers", + "branchQualityBlockers", + "accountStateBlockers", + "recommendedRerunCondition", + "localFindings", + "maintainerFit", + "manifestGuidance", + "prPacket", + "nextActions", + "workspaceIntelligence", + "summary" + ] + }, + "ScorePreviewResult": { + "type": "object", + "properties": { + "repoFullName": { + "type": "string" + }, + "generatedAt": { + "type": "string" + }, + "scoringModelSnapshotId": { + "type": "string" + }, + "activeModel": { + "type": "string", + "enum": [ + "current_density_model", + "pending_saturation_model", + "exponential_saturation_model", + "unknown" + ] + }, + "privateOnly": { + "type": "boolean", + "enum": [ + true + ] + }, + "laneMath": { + "type": "object", + "additionalProperties": { + "type": "number" + } + }, + "scoreEstimate": { + "type": "object", + "properties": { + "baseScore": { + "type": "number" + }, + "densityMultiplier": { + "type": "number" + }, + "contributionBonus": { + "type": "number" + }, + "labelMultiplier": { + "type": "number" + }, + "issueMultiplier": { + "type": "number" + }, + "credibilityMultiplier": { + "type": "number" + }, + "reviewPenaltyMultiplier": { + "type": "number" + }, + "openPrMultiplier": { + "type": "number" + }, + "estimatedMergedScore": { + "type": "number" + }, + "pendingSaturationScore": { + "type": "number" + } + }, + "required": [ + "baseScore", + "densityMultiplier", + "contributionBonus", + "labelMultiplier", + "issueMultiplier", + "credibilityMultiplier", + "reviewPenaltyMultiplier", + "openPrMultiplier", + "estimatedMergedScore", + "pendingSaturationScore" + ] + }, + "linkedIssueMultiplier": { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "none", + "standard", + "maintainer" + ] + }, + "status": { + "type": "string", + "enum": [ + "not_required", + "raw", + "plausible", + "validated", + "invalid", + "unavailable" + ] + }, + "source": { + "type": "string", + "enum": [ + "none", + "user_supplied", + "official_mirror", + "github_cache", + "issue_quality", + "missing" + ] + }, + "eligible": { + "type": "boolean" + }, + "issueNumbers": { + "type": "array", + "items": { + "type": "number" + } + }, + "solvedByPullRequests": { + "type": "array", + "items": { + "type": "number" + } + }, + "baseMultiplier": { + "type": "number" + }, + "appliedMultiplier": { + "type": "number" + }, + "reason": { + "type": "string" + }, + "warnings": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "mode", + "status", + "source", + "eligible", + "issueNumbers", + "solvedByPullRequests", + "baseMultiplier", + "appliedMultiplier", + "reason", + "warnings" + ] + }, + "gates": { + "type": "object", + "properties": { + "baseTokenGatePassed": { + "type": "boolean" + }, + "openPrThreshold": { + "type": "number" + }, + "openPrCount": { + "type": "number" + }, + "collateralFraction": { + "type": "number" + }, + "credibilityFloor": { + "type": "number" + }, + "credibilityObserved": { + "type": "number" + } + }, + "required": [ + "baseTokenGatePassed", + "openPrThreshold", + "openPrCount", + "collateralFraction", + "credibilityFloor", + "credibilityObserved" + ] + }, + "branchEligibility": { + "type": "object", + "properties": { + "required": { + "type": "boolean" + }, + "status": { + "type": "string", + "enum": [ + "eligible", + "ineligible", + "unknown", + "not_required" ] }, - "afterStalePrsClose": { - "type": "object", - "properties": { - "name": { - "type": "string", - "enum": [ - "current", - "cleanGates", - "afterPendingMerges", - "afterApprovedPrsMerge", - "afterStalePrsClose", - "linkedIssueFixed", - "bestReasonableCase" - ] - }, - "source": { - "type": "string", - "enum": [ - "current_data", - "user_supplied", - "github_observed", - "gittensory_projection" - ] - }, - "assumptions": { - "type": "array", - "items": { - "type": "string" + "evidence": { + "type": "string", + "enum": [ + "provided", + "missing" + ] + }, + "source": { + "type": "string", + "enum": [ + "github_metadata", + "local_metadata", + "registry", + "user_supplied", + "missing" + ] + }, + "reason": { + "type": "string" + }, + "checkedAt": { + "type": "string" + }, + "stale": { + "type": "boolean" + }, + "warnings": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "required", + "status", + "evidence", + "source", + "stale", + "warnings" + ] + }, + "effectiveEstimatedScore": { + "type": "number" + }, + "underlyingPotentialScore": { + "type": "number" + }, + "blockedBy": { + "type": "array", + "items": { + "type": "object", + "properties": { + "code": { + "type": "string", + "enum": [ + "repo_not_registered", + "inactive_allocation", + "base_token_gate", + "open_pr_threshold", + "credibility_floor", + "review_penalty", + "metadata_only", + "linked_issue_invalid", + "linked_issue_unvalidated", + "branch_ineligible", + "branch_eligibility_missing" + ] + }, + "severity": { + "type": "string", + "enum": [ + "blocker", + "reducer", + "context" + ] + }, + "detail": { + "type": "string" + } + }, + "required": [ + "code", + "severity", + "detail" + ] + } + }, + "gateDeltas": { + "type": "array", + "items": { + "type": "object", + "properties": { + "gate": { + "type": "string", + "enum": [ + "open_pr_threshold", + "credibility_floor", + "linked_issue_multiplier" + ] + }, + "current": { + "type": "string" + }, + "projected": { + "type": "string" + }, + "explanation": { + "type": "string" + } + }, + "required": [ + "gate", + "current", + "projected", + "explanation" + ] + } + }, + "scenarioPreviews": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "enum": [ + "current", + "cleanGates", + "afterPendingMerges", + "afterApprovedPrsMerge", + "afterStalePrsClose", + "linkedIssueFixed", + "bestReasonableCase" + ] + }, + "source": { + "type": "string", + "enum": [ + "current_data", + "user_supplied", + "github_observed", + "gittensory_projection" + ] + }, + "assumptions": { + "type": "array", + "items": { + "type": "string" + } + }, + "scoreEstimate": { + "type": "object", + "properties": { + "baseScore": { + "type": "number" + }, + "densityMultiplier": { + "type": "number" + }, + "contributionBonus": { + "type": "number" + }, + "labelMultiplier": { + "type": "number" + }, + "issueMultiplier": { + "type": "number" + }, + "credibilityMultiplier": { + "type": "number" + }, + "reviewPenaltyMultiplier": { + "type": "number" + }, + "openPrMultiplier": { + "type": "number" + }, + "estimatedMergedScore": { + "type": "number" + }, + "pendingSaturationScore": { + "type": "number" } }, - "scoreEstimate": { - "type": "object", - "properties": { - "baseScore": { - "type": "number" - }, - "densityMultiplier": { - "type": "number" - }, - "contributionBonus": { - "type": "number" - }, - "labelMultiplier": { - "type": "number" - }, - "issueMultiplier": { - "type": "number" - }, - "credibilityMultiplier": { - "type": "number" - }, - "reviewPenaltyMultiplier": { - "type": "number" - }, - "openPrMultiplier": { - "type": "number" - }, - "estimatedMergedScore": { - "type": "number" - }, - "pendingSaturationScore": { - "type": "number" - } + "required": [ + "baseScore", + "densityMultiplier", + "contributionBonus", + "labelMultiplier", + "issueMultiplier", + "credibilityMultiplier", + "reviewPenaltyMultiplier", + "openPrMultiplier", + "estimatedMergedScore", + "pendingSaturationScore" + ] + }, + "gates": { + "type": "object", + "properties": { + "baseTokenGatePassed": { + "type": "boolean" }, - "required": [ - "baseScore", - "densityMultiplier", - "contributionBonus", - "labelMultiplier", - "issueMultiplier", - "credibilityMultiplier", - "reviewPenaltyMultiplier", - "openPrMultiplier", - "estimatedMergedScore", - "pendingSaturationScore" - ] - }, - "gates": { - "type": "object", - "properties": { - "baseTokenGatePassed": { - "type": "boolean" - }, - "openPrThreshold": { - "type": "number" - }, - "openPrCount": { - "type": "number" - }, - "collateralFraction": { - "type": "number" - }, - "credibilityFloor": { - "type": "number" - }, - "credibilityObserved": { - "type": "number" - } + "openPrThreshold": { + "type": "number" }, - "required": [ - "baseTokenGatePassed", - "openPrThreshold", - "openPrCount", - "collateralFraction", - "credibilityFloor", - "credibilityObserved" - ] - }, - "effectiveEstimatedScore": { - "type": "number" - }, - "underlyingPotentialScore": { - "type": "number" - }, - "blockedBy": { - "type": "array", - "items": { - "type": "object", - "properties": { - "code": { - "type": "string", - "enum": [ - "repo_not_registered", - "inactive_allocation", - "base_token_gate", - "open_pr_threshold", - "credibility_floor", - "review_penalty", - "metadata_only", - "linked_issue_invalid", - "linked_issue_unvalidated", - "branch_ineligible", - "branch_eligibility_missing" - ] - }, - "severity": { - "type": "string", - "enum": [ - "blocker", - "reducer", - "context" - ] - }, - "detail": { - "type": "string" - } - }, - "required": [ - "code", - "severity", - "detail" - ] + "openPrCount": { + "type": "number" + }, + "collateralFraction": { + "type": "number" + }, + "credibilityFloor": { + "type": "number" + }, + "credibilityObserved": { + "type": "number" } }, - "linkedIssueMultiplier": { + "required": [ + "baseTokenGatePassed", + "openPrThreshold", + "openPrCount", + "collateralFraction", + "credibilityFloor", + "credibilityObserved" + ] + }, + "effectiveEstimatedScore": { + "type": "number" + }, + "underlyingPotentialScore": { + "type": "number" + }, + "blockedBy": { + "type": "array", + "items": { "type": "object", "properties": { - "mode": { - "type": "string", - "enum": [ - "none", - "standard", - "maintainer" - ] - }, - "status": { - "type": "string", - "enum": [ - "not_required", - "raw", - "plausible", - "validated", - "invalid", - "unavailable" - ] - }, - "source": { + "code": { "type": "string", "enum": [ - "none", - "user_supplied", - "official_mirror", - "github_cache", - "issue_quality", - "missing" - ] - }, - "eligible": { - "type": "boolean" - }, - "issueNumbers": { - "type": "array", - "items": { - "type": "number" - } - }, - "solvedByPullRequests": { - "type": "array", - "items": { - "type": "number" - } - }, - "baseMultiplier": { - "type": "number" + "repo_not_registered", + "inactive_allocation", + "base_token_gate", + "open_pr_threshold", + "credibility_floor", + "review_penalty", + "metadata_only", + "linked_issue_invalid", + "linked_issue_unvalidated", + "branch_ineligible", + "branch_eligibility_missing" + ] }, - "appliedMultiplier": { - "type": "number" + "severity": { + "type": "string", + "enum": [ + "blocker", + "reducer", + "context" + ] }, - "reason": { + "detail": { "type": "string" - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - } } }, "required": [ - "mode", - "status", - "source", - "eligible", - "issueNumbers", - "solvedByPullRequests", - "baseMultiplier", - "appliedMultiplier", - "reason", - "warnings" + "code", + "severity", + "detail" ] - }, - "deltaExplanation": { - "type": "string" } }, - "required": [ - "name", - "source", - "assumptions", - "scoreEstimate", - "gates", - "effectiveEstimatedScore", - "underlyingPotentialScore", - "blockedBy", - "linkedIssueMultiplier", - "deltaExplanation" - ] - }, - "gateDeltas": { - "type": "array", - "items": { + "linkedIssueMultiplier": { "type": "object", "properties": { - "gate": { + "mode": { "type": "string", "enum": [ - "open_pr_threshold", - "credibility_floor", - "linked_issue_multiplier" + "none", + "standard", + "maintainer" ] }, - "current": { - "type": "string" - }, - "projected": { - "type": "string" - }, - "explanation": { - "type": "string" - } - }, - "required": [ - "gate", - "current", - "projected", - "explanation" - ] - } - }, - "blockedBy": { - "type": "array", - "items": { - "type": "object", - "properties": { - "code": { + "status": { "type": "string", "enum": [ - "repo_not_registered", - "inactive_allocation", - "base_token_gate", - "open_pr_threshold", - "credibility_floor", - "review_penalty", - "metadata_only", - "linked_issue_invalid", - "linked_issue_unvalidated", - "branch_ineligible", - "branch_eligibility_missing" + "not_required", + "raw", + "plausible", + "validated", + "invalid", + "unavailable" ] }, - "severity": { + "source": { "type": "string", "enum": [ - "blocker", - "reducer", - "context" + "none", + "user_supplied", + "official_mirror", + "github_cache", + "issue_quality", + "missing" ] }, - "detail": { + "eligible": { + "type": "boolean" + }, + "issueNumbers": { + "type": "array", + "items": { + "type": "number" + } + }, + "solvedByPullRequests": { + "type": "array", + "items": { + "type": "number" + } + }, + "baseMultiplier": { + "type": "number" + }, + "appliedMultiplier": { + "type": "number" + }, + "reason": { "type": "string" + }, + "warnings": { + "type": "array", + "items": { + "type": "string" + } } }, "required": [ - "code", - "severity", - "detail" + "mode", + "status", + "source", + "eligible", + "issueNumbers", + "solvedByPullRequests", + "baseMultiplier", + "appliedMultiplier", + "reason", + "warnings" ] + }, + "deltaExplanation": { + "type": "string" + } + }, + "required": [ + "name", + "source", + "assumptions", + "scoreEstimate", + "gates", + "effectiveEstimatedScore", + "underlyingPotentialScore", + "blockedBy", + "linkedIssueMultiplier", + "deltaExplanation" + ] + } + }, + "scoreabilityStatus": { + "type": "string", + "enum": [ + "blocked", + "conditionally_scoreable", + "scoreable", + "hold" + ] + }, + "warnings": { + "type": "array", + "items": { + "type": "string" + } + }, + "assumptions": { + "type": "array", + "items": { + "type": "string" + } + }, + "recommendation": { + "type": "object", + "properties": { + "level": { + "type": "string", + "enum": [ + "strong_fit", + "reasonable_fit", + "needs_work", + "hold" + ] + }, + "actions": { + "type": "array", + "items": { + "type": "string" } } }, "required": [ - "current", - "bestReasonableCase", - "gateDeltas", - "blockedBy" + "level", + "actions" + ] + } + }, + "required": [ + "repoFullName", + "generatedAt", + "scoringModelSnapshotId", + "activeModel", + "privateOnly", + "laneMath", + "scoreEstimate", + "linkedIssueMultiplier", + "gates", + "branchEligibility", + "effectiveEstimatedScore", + "underlyingPotentialScore", + "blockedBy", + "gateDeltas", + "scenarioPreviews", + "scoreabilityStatus", + "warnings", + "assumptions", + "recommendation" + ] + }, + "RepoRewardRisk": { + "type": "object", + "properties": { + "login": { + "type": "string" + }, + "repoFullName": { + "type": "string" + }, + "generatedAt": { + "type": "string" + }, + "roleContext": { + "$ref": "#/components/schemas/RoleContext" + }, + "lane": { + "$ref": "#/components/schemas/LaneAdvice" + }, + "recommendation": { + "type": "string", + "enum": [ + "pursue", + "cleanup_first", + "maintainer_lane", + "avoid_for_now", + "unknown" ] }, - "observedPullRequestScenarios": { + "rewardUpside": { "type": "object", "properties": { - "approvedOrMergeable": { + "relevantLane": { + "type": "string", + "enum": [ + "direct_pr", + "issue_discovery", + "maintainer_lane", + "none" + ] + }, + "repoSlice": { "type": "number" }, - "stale": { + "directPrSlice": { "type": "number" }, - "closed": { + "issueDiscoverySlice": { "type": "number" }, - "draft": { + "maintainerCutSlice": { "type": "number" }, - "blocked": { + "labelMultiplier": { "type": "number" }, - "maintainerLane": { + "issueMultiplier": { "type": "number" }, - "notes": { - "type": "array", - "items": { - "type": "string" - } + "estimatedScoreIfClean": { + "type": "number" + }, + "currentEstimatedScore": { + "type": "number" } }, "required": [ - "approvedOrMergeable", - "stale", - "closed", - "draft", - "blocked", - "maintainerLane", - "notes" + "relevantLane", + "repoSlice", + "directPrSlice", + "issueDiscoverySlice", + "maintainerCutSlice", + "labelMultiplier", + "issueMultiplier", + "estimatedScoreIfClean", + "currentEstimatedScore" ] }, - "githubBranchStatus": { + "scoreBlockers": { + "type": "array", + "items": { + "type": "string" + } + }, + "riskBreakdown": { "type": "object", "properties": { - "source": { + "queueBurden": { "type": "string", "enum": [ - "cached_github_data" + "low", + "medium", + "high", + "critical" ] }, - "status": { + "queueBurdenScore": { + "type": "number" + }, + "duplicateClusters": { + "type": "number" + }, + "highRiskDuplicateClusters": { + "type": "number" + }, + "closedPullRequestRate": { + "type": "number" + }, + "openPullRequests": { + "type": "number" + }, + "credibility": { + "type": "number" + }, + "reviewChurnRisk": { "type": "string", "enum": [ - "approved", - "failing_checks", - "needs_author", - "blocked", - "pending_review", - "no_pr", - "unknown" + "low", + "medium", + "high" + ] + } + }, + "required": [ + "queueBurden", + "queueBurdenScore", + "duplicateClusters", + "highRiskDuplicateClusters", + "closedPullRequestRate", + "openPullRequests", + "credibility", + "reviewChurnRisk" + ] + }, + "actionImpact": { + "type": "object", + "additionalProperties": { + "nullable": true + } + }, + "currentPreview": { + "type": "object", + "additionalProperties": { + "nullable": true + } + }, + "afterCleanupPreview": { + "type": "object", + "additionalProperties": { + "nullable": true + } + }, + "actions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RewardRiskAction" + } + }, + "whyThisHelps": { + "type": "array", + "items": { + "type": "string" + } + }, + "nextActions": { + "type": "array", + "items": { + "type": "string" + } + }, + "summary": { + "type": "string" + } + }, + "required": [ + "login", + "repoFullName", + "generatedAt", + "roleContext", + "lane", + "recommendation", + "rewardUpside", + "scoreBlockers", + "riskBreakdown", + "actionImpact", + "currentPreview", + "afterCleanupPreview", + "actions", + "whyThisHelps", + "nextActions", + "summary" + ] + }, + "RewardRiskAction": { + "type": "object", + "properties": { + "actionKind": { + "type": "string", + "enum": [ + "cleanup_existing_prs", + "land_existing_prs", + "close_or_withdraw_low_fit_prs", + "open_new_direct_pr", + "file_issue_discovery", + "maintainer_lane_improve_repo", + "maintainer_cut_readiness" + ] + }, + "repoFullName": { + "type": "string" + }, + "priorityScore": { + "type": "number" + }, + "laneValueScore": { + "type": "number" + }, + "scoreabilityScore": { + "type": "number" + }, + "personalFitScore": { + "type": "number" + }, + "riskPenalty": { + "type": "number" + }, + "maintainerFrictionPenalty": { + "type": "number" + }, + "actionLeverageScore": { + "type": "number" + }, + "whyThisHelps": { + "type": "array", + "items": { + "type": "string" + } + }, + "nextActions": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "actionKind", + "repoFullName", + "priorityScore", + "laneValueScore", + "scoreabilityScore", + "personalFitScore", + "riskPenalty", + "maintainerFrictionPenalty", + "actionLeverageScore", + "whyThisHelps", + "nextActions" + ] + }, + "LocalWorkspaceIntelligence": { + "type": "object", + "properties": { + "version": { + "type": "number", + "enum": [ + 2 + ] + }, + "sourceUpload": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "enum": [ + false ] }, - "pullNumber": { - "type": "number" - }, - "title": { + "detail": { "type": "string" - }, - "reviewDecision": { - "type": "string", - "nullable": true - }, - "mergeableState": { - "type": "string", - "nullable": true - }, - "notes": { - "type": "array", - "items": { - "type": "string" - } } }, "required": [ - "source", - "status", - "notes" + "enabled", + "detail" ] }, - "branchEligibility": { + "branch": { "type": "object", "properties": { - "required": { - "type": "boolean" - }, - "status": { - "type": "string", - "enum": [ - "eligible", - "ineligible", - "unknown", - "not_required" - ] - }, - "evidence": { - "type": "string", - "enum": [ - "provided", - "missing" - ] - }, - "source": { - "type": "string", - "enum": [ - "github_metadata", - "local_metadata", - "registry", - "user_supplied", - "missing" - ] - }, - "reason": { + "name": { "type": "string" }, - "checkedAt": { + "baseRef": { "type": "string" }, - "stale": { - "type": "boolean" + "headSha": { + "type": "string" }, - "warnings": { - "type": "array", - "items": { - "type": "string" - } + "pendingCommitCount": { + "type": "number" } }, "required": [ - "required", - "status", - "evidence", - "source", - "stale", - "warnings" + "pendingCommitCount" ] }, - "rewardRisk": { - "$ref": "#/components/schemas/RepoRewardRisk" - }, - "scoreBlockers": { - "type": "array", - "items": { - "type": "string" - } - }, - "branchQualityBlockers": { - "type": "array", - "items": { - "type": "string" - } - }, - "accountStateBlockers": { - "type": "array", - "items": { - "type": "string" - } - }, - "recommendedRerunCondition": { - "type": "string" - }, - "localFindings": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Finding" - } - }, - "maintainerFit": { + "changedFiles": { "type": "object", "properties": { - "recommendation": { - "type": "string", - "enum": [ - "pursue", - "cleanup_first", - "maintainer_lane", - "avoid_for_now", - "unknown" - ] + "total": { + "type": "number" }, - "reviewBurden": { - "type": "string", - "enum": [ - "low", - "medium", - "high" - ] + "added": { + "type": "number" }, - "role": { - "type": "string", - "enum": [ - "outside_contributor", - "repo_maintainer", - "org_member", - "collaborator", - "owner", - "unknown" - ] + "modified": { + "type": "number" }, - "maintainerLane": { - "type": "boolean" + "deleted": { + "type": "number" }, - "reasons": { - "type": "array", - "items": { - "type": "string" - } + "renamed": { + "type": "number" }, - "risks": { + "binary": { + "type": "number" + }, + "paths": { "type": "array", "items": { "type": "string" @@ -6070,101 +6147,108 @@ } }, "required": [ - "recommendation", - "reviewBurden", - "role", - "maintainerLane", - "reasons", - "risks" + "total", + "added", + "modified", + "deleted", + "renamed", + "binary", + "paths" ] }, - "manifestGuidance": { + "testEvidence": { "type": "object", "properties": { - "present": { - "type": "boolean" - }, - "source": { + "level": { "type": "string", "enum": [ - "repo_file", - "api_record", + "test_files", + "validation_commands", + "both", "none" ] }, - "linkedIssuePolicy": { - "type": "string", - "enum": [ - "required", - "preferred", - "optional" - ] - }, - "issueDiscoveryPolicy": { - "type": "string", - "enum": [ - "encouraged", - "neutral", - "discouraged" - ] - }, - "matchedWantedPaths": { - "type": "array", - "items": { - "type": "string" - } - }, - "matchedBlockedPaths": { - "type": "array", - "items": { - "type": "string" - } + "testFileCount": { + "type": "number" }, - "preferredLabelHits": { - "type": "array", - "items": { - "type": "string" - } + "passedValidationCount": { + "type": "number" }, - "findings": { + "commands": { "type": "array", "items": { "type": "object", "properties": { - "code": { + "command": { "type": "string" }, - "severity": { + "status": { "type": "string", "enum": [ - "info", - "warning", - "critical" + "passed", + "failed", + "not_run" ] }, - "title": { - "type": "string" - }, - "detail": { - "type": "string" - }, - "action": { + "summary": { "type": "string" } }, "required": [ - "code", - "severity", - "title", - "detail" + "command", + "status" ] } + } + }, + "required": [ + "level", + "testFileCount", + "passedValidationCount", + "commands" + ] + }, + "linkedIssues": { + "type": "array", + "items": { + "type": "number" + } + }, + "baseFreshness": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "fresh", + "stale", + "possibly_stale", + "unknown" + ] }, - "publicNextSteps": { - "type": "array", - "items": { - "type": "string" - } + "baseRef": { + "type": "string" + }, + "baseSha": { + "type": "string" + }, + "headSha": { + "type": "string" + }, + "mergeBaseSha": { + "type": "string" + }, + "remoteTrackingSha": { + "type": "string" + }, + "changedFileCount": { + "type": "number" + }, + "testFileCount": { + "type": "number" + }, + "passedValidationCount": { + "type": "number" }, "warnings": { "type": "array", @@ -6172,116 +6256,59 @@ "type": "string" } }, - "summary": { + "recommendation": { "type": "string" } }, "required": [ - "present", - "source", - "linkedIssuePolicy", - "issueDiscoveryPolicy", - "matchedWantedPaths", - "matchedBlockedPaths", - "preferredLabelHits", - "findings", - "publicNextSteps", - "warnings", - "summary" + "status", + "changedFileCount", + "testFileCount", + "passedValidationCount", + "warnings" ] }, - "prPacket": { + "ciStatusHints": { + "type": "array", + "items": { + "type": "string" + } + }, + "localScorerDiagnostics": { "type": "object", "properties": { - "titleSuggestion": { + "mode": { "type": "string" }, - "markdown": { + "activeModel": { "type": "string" }, - "bodySections": { + "warnings": { "type": "array", "items": { - "type": "object", - "properties": { - "heading": { - "type": "string" - }, - "lines": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": [ - "heading", - "lines" - ] + "type": "string" } }, - "reviewerNotes": { + "metadataOnly": { + "type": "boolean" + } + }, + "required": [ + "mode", + "warnings", + "metadataOnly" + ] + }, + "blockers": { + "type": "object", + "properties": { + "branchQuality": { "type": "array", "items": { "type": "string" } }, - "validationSummary": { - "type": "object", - "properties": { - "passed": { - "type": "number" - }, - "failed": { - "type": "number" - }, - "notRun": { - "type": "number" - }, - "commands": { - "type": "array", - "items": { - "type": "object", - "properties": { - "command": { - "type": "string" - }, - "status": { - "type": "string", - "enum": [ - "passed", - "failed", - "not_run", - "skipped", - "focused", - "unknown" - ] - }, - "summary": { - "type": "string" - }, - "durationMs": { - "type": "number" - }, - "exitCode": { - "type": "number" - } - }, - "required": [ - "command", - "status" - ] - } - } - }, - "required": [ - "passed", - "failed", - "notRun", - "commands" - ] - }, - "publicSafeWarnings": { + "accountState": { "type": "array", "items": { "type": "string" @@ -6289,52 +6316,25 @@ } }, "required": [ - "titleSuggestion", - "markdown", - "bodySections", - "reviewerNotes", - "validationSummary", - "publicSafeWarnings" + "branchQuality", + "accountState" ] }, - "nextActions": { - "type": "array", - "items": { - "$ref": "#/components/schemas/RewardRiskAction" - } - }, - "workspaceIntelligence": { - "$ref": "#/components/schemas/LocalWorkspaceIntelligence" - }, - "summary": { + "rerunWhen": { "type": "string" } }, "required": [ - "login", - "repoFullName", - "generatedAt", + "version", + "sourceUpload", + "branch", + "changedFiles", + "testEvidence", + "linkedIssues", "baseFreshness", - "lane", - "roleContext", - "preflight", - "scorePreview", - "scenarioScorePreview", - "observedPullRequestScenarios", - "githubBranchStatus", - "branchEligibility", - "rewardRisk", - "scoreBlockers", - "branchQualityBlockers", - "accountStateBlockers", - "recommendedRerunCondition", - "localFindings", - "maintainerFit", - "manifestGuidance", - "prPacket", - "nextActions", - "workspaceIntelligence", - "summary" + "ciStatusHints", + "blockers", + "rerunWhen" ] }, "MaintainerPacket": { @@ -6393,21 +6393,71 @@ ] } }, - "suggestedActions": { + "suggestedActions": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "repoFullName", + "generatedAt", + "queueHealth", + "configQuality", + "collisions", + "pullRequestPackets", + "suggestedActions" + ] + }, + "MaintainerLaneReport": { + "type": "object", + "properties": { + "repoFullName": { + "type": "string" + }, + "generatedAt": { + "type": "string" + }, + "lane": { + "$ref": "#/components/schemas/LaneAdvice" + }, + "maintainerCut": { + "type": "number" + }, + "maintainerCutConfigured": { + "type": "boolean" + }, + "queueHealth": { + "$ref": "#/components/schemas/QueueHealth" + }, + "configQuality": { + "$ref": "#/components/schemas/ConfigQuality" + }, + "contributorIntakeHealth": { + "$ref": "#/components/schemas/ContributorIntakeHealth" + }, + "summary": { + "type": "string" + }, + "findings": { "type": "array", "items": { - "type": "string" + "$ref": "#/components/schemas/Finding" } } }, "required": [ "repoFullName", "generatedAt", + "lane", + "maintainerCut", + "maintainerCutConfigured", "queueHealth", "configQuality", - "collisions", - "pullRequestPackets", - "suggestedActions" + "contributorIntakeHealth", + "summary", + "findings" ] }, "ContributorIntakeHealth": { @@ -6475,56 +6525,6 @@ "findings" ] }, - "MaintainerLaneReport": { - "type": "object", - "properties": { - "repoFullName": { - "type": "string" - }, - "generatedAt": { - "type": "string" - }, - "lane": { - "$ref": "#/components/schemas/LaneAdvice" - }, - "maintainerCut": { - "type": "number" - }, - "maintainerCutConfigured": { - "type": "boolean" - }, - "queueHealth": { - "$ref": "#/components/schemas/QueueHealth" - }, - "configQuality": { - "$ref": "#/components/schemas/ConfigQuality" - }, - "contributorIntakeHealth": { - "$ref": "#/components/schemas/ContributorIntakeHealth" - }, - "summary": { - "type": "string" - }, - "findings": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Finding" - } - } - }, - "required": [ - "repoFullName", - "generatedAt", - "lane", - "maintainerCut", - "maintainerCutConfigured", - "queueHealth", - "configQuality", - "contributorIntakeHealth", - "summary", - "findings" - ] - }, "MaintainerCutReadiness": { "type": "object", "properties": { @@ -7240,7 +7240,8 @@ "bot_author", "maintainer_author", "miner_detection_unavailable", - "not_official_gittensor_miner" + "not_official_gittensor_miner", + null ] }, "actions": { @@ -8032,46 +8033,234 @@ ] } }, - "eventRemediation": { + "eventRemediation": { + "type": "array", + "items": { + "type": "object", + "properties": { + "event": { + "type": "string" + }, + "ok": { + "type": "boolean" + }, + "action": { + "type": "string" + } + }, + "required": [ + "event", + "ok", + "action" + ] + } + }, + "repairSteps": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "installationId", + "accountLogin", + "installedReposCount", + "registeredInstalledCount", + "status", + "missingPermissions", + "missingEvents", + "permissions", + "events", + "checkedAt" + ] + }, + "SyncStatus": { + "type": "object", + "properties": { + "generatedAt": { + "type": "string" + }, + "signalFidelity": { + "$ref": "#/components/schemas/SignalFidelity" + }, + "freshnessSlo": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "fresh", + "degraded", + "blocked" + ] + }, + "generatedAt": { + "type": "string" + }, + "staleCount": { + "type": "number" + }, + "degradedCount": { + "type": "number" + }, + "blockedCount": { + "type": "number" + }, + "missingCount": { + "type": "number" + }, + "launchBlockingCount": { + "type": "number" + }, + "repairRecommended": { + "type": "boolean" + }, + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "area": { + "type": "string" + }, + "targetKey": { + "type": "string" + }, + "status": { + "type": "string" + }, + "launchBlocking": { + "type": "boolean" + }, + "ageSeconds": { + "type": "number" + }, + "sloSeconds": { + "type": "number" + }, + "breachSeconds": { + "type": "number" + }, + "observedAt": { + "type": "string", + "nullable": true + }, + "summary": { + "type": "string" + } + }, + "required": [ + "area", + "targetKey", + "status", + "launchBlocking", + "sloSeconds", + "summary" + ] + } + }, + "warnings": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "status", + "generatedAt", + "staleCount", + "degradedCount", + "blockedCount", + "missingCount", + "launchBlockingCount", + "repairRecommended", + "items", + "warnings" + ] + }, + "coreSignalFidelity": { + "$ref": "#/components/schemas/CoreSignalFidelity" + }, + "upstreamDrift": { + "$ref": "#/components/schemas/UpstreamStatus" + }, + "historyCoverage": { + "type": "string", + "enum": [ + "sampled", + "counts_only", + "full" + ] + }, + "refreshingRepos": { + "type": "array", + "items": { + "type": "string" + } + }, + "waitingForRateLimitRepos": { + "type": "array", + "items": { + "type": "string" + } + }, + "repositories": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RepoSyncState" + } + }, + "segments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RepoSyncSegment" + } + }, + "githubTotals": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RepoGithubTotalsSnapshot" + } + }, + "pullRequestDetailSync": { "type": "array", "items": { "type": "object", - "properties": { - "event": { - "type": "string" - }, - "ok": { - "type": "boolean" - }, - "action": { - "type": "string" - } - }, - "required": [ - "event", - "ok", - "action" - ] + "additionalProperties": { + "nullable": true + } } }, - "repairSteps": { + "installations": { "type": "array", "items": { - "type": "string" + "$ref": "#/components/schemas/InstallationHealth" + } + }, + "rateLimits": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GitHubRateLimitObservation" } } }, "required": [ - "installationId", - "accountLogin", - "installedReposCount", - "registeredInstalledCount", - "status", - "missingPermissions", - "missingEvents", - "permissions", - "events", - "checkedAt" + "generatedAt", + "signalFidelity", + "freshnessSlo", + "coreSignalFidelity", + "upstreamDrift", + "historyCoverage", + "refreshingRepos", + "waitingForRateLimitRepos", + "repositories", + "segments", + "githubTotals", + "pullRequestDetailSync", + "installations", + "rateLimits" ] }, "CoreSignalFidelity": { @@ -8137,6 +8326,91 @@ "historyCoverage" ] }, + "UpstreamStatus": { + "type": "object", + "properties": { + "generatedAt": { + "type": "string" + }, + "status": { + "type": "string", + "enum": [ + "current", + "drift_detected", + "stale", + "unavailable" + ] + }, + "latestCommitSha": { + "type": "string", + "nullable": true + }, + "latestRulesetId": { + "type": "string", + "nullable": true + }, + "latestRulesetGeneratedAt": { + "type": "string", + "nullable": true + }, + "activeModel": { + "type": "string", + "nullable": true, + "enum": [ + "current_density_model", + "pending_saturation_model", + "exponential_saturation_model", + "unknown", + null + ] + }, + "highestSeverity": { + "type": "string", + "nullable": true, + "enum": [ + "low", + "medium", + "high", + "blocking", + null + ] + }, + "affectedAreas": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "registry", + "scoring_model", + "issue_discovery", + "mirror_linkage", + "language_weights", + "source" + ] + } + }, + "registryHyperparameterDrift": { + "$ref": "#/components/schemas/RegistryHyperparameterDriftSummary" + }, + "openReportCount": { + "type": "number" + }, + "reports": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UpstreamDriftReport" + } + } + }, + "required": [ + "generatedAt", + "status", + "affectedAreas", + "registryHyperparameterDrift", + "openReportCount", + "reports" + ] + }, "RegistryHyperparameterDriftSummary": { "type": "object", "properties": { @@ -8199,124 +8473,11 @@ "id": { "type": "string" }, - "fingerprint": { - "type": "string" - }, - "severity": { - "type": "string", - "enum": [ - "low", - "medium", - "high", - "blocking" - ] - }, - "status": { - "type": "string", - "enum": [ - "open", - "acknowledged", - "resolved", - "ignored" - ] - }, - "summary": { - "type": "string" - }, - "affectedAreas": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "registry", - "scoring_model", - "issue_discovery", - "mirror_linkage", - "language_weights", - "source" - ] - } - }, - "previousRulesetId": { - "type": "string", - "nullable": true - }, - "currentRulesetId": { - "type": "string", - "nullable": true - }, - "issueNumber": { - "type": "number", - "nullable": true - }, - "issueUrl": { - "type": "string", - "nullable": true - }, - "payload": { - "type": "object", - "additionalProperties": { - "nullable": true - } - }, - "generatedAt": { - "type": "string" - }, - "updatedAt": { - "type": "string" - } - }, - "required": [ - "id", - "fingerprint", - "severity", - "status", - "summary", - "affectedAreas", - "generatedAt", - "updatedAt" - ] - }, - "UpstreamStatus": { - "type": "object", - "properties": { - "generatedAt": { - "type": "string" - }, - "status": { - "type": "string", - "enum": [ - "current", - "drift_detected", - "stale", - "unavailable" - ] - }, - "latestCommitSha": { - "type": "string", - "nullable": true - }, - "latestRulesetId": { - "type": "string", - "nullable": true - }, - "latestRulesetGeneratedAt": { - "type": "string", - "nullable": true - }, - "activeModel": { - "type": "string", - "nullable": true, - "enum": [ - "current_density_model", - "pending_saturation_model", - "exponential_saturation_model", - "unknown" - ] + "fingerprint": { + "type": "string" }, - "highestSeverity": { + "severity": { "type": "string", - "nullable": true, "enum": [ "low", "medium", @@ -8324,6 +8485,18 @@ "blocking" ] }, + "status": { + "type": "string", + "enum": [ + "open", + "acknowledged", + "resolved", + "ignored" + ] + }, + "summary": { + "type": "string" + }, "affectedAreas": { "type": "array", "items": { @@ -8338,26 +8511,44 @@ ] } }, - "registryHyperparameterDrift": { - "$ref": "#/components/schemas/RegistryHyperparameterDriftSummary" + "previousRulesetId": { + "type": "string", + "nullable": true }, - "openReportCount": { - "type": "number" + "currentRulesetId": { + "type": "string", + "nullable": true }, - "reports": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UpstreamDriftReport" + "issueNumber": { + "type": "number", + "nullable": true + }, + "issueUrl": { + "type": "string", + "nullable": true + }, + "payload": { + "type": "object", + "additionalProperties": { + "nullable": true } + }, + "generatedAt": { + "type": "string" + }, + "updatedAt": { + "type": "string" } }, "required": [ - "generatedAt", + "id", + "fingerprint", + "severity", "status", + "summary", "affectedAreas", - "registryHyperparameterDrift", - "openReportCount", - "reports" + "generatedAt", + "updatedAt" ] }, "RepoGithubTotalsSnapshot": { @@ -8422,194 +8613,6 @@ "fetchedAt" ] }, - "SyncStatus": { - "type": "object", - "properties": { - "generatedAt": { - "type": "string" - }, - "signalFidelity": { - "$ref": "#/components/schemas/SignalFidelity" - }, - "freshnessSlo": { - "type": "object", - "properties": { - "status": { - "type": "string", - "enum": [ - "fresh", - "degraded", - "blocked" - ] - }, - "generatedAt": { - "type": "string" - }, - "staleCount": { - "type": "number" - }, - "degradedCount": { - "type": "number" - }, - "blockedCount": { - "type": "number" - }, - "missingCount": { - "type": "number" - }, - "launchBlockingCount": { - "type": "number" - }, - "repairRecommended": { - "type": "boolean" - }, - "items": { - "type": "array", - "items": { - "type": "object", - "properties": { - "area": { - "type": "string" - }, - "targetKey": { - "type": "string" - }, - "status": { - "type": "string" - }, - "launchBlocking": { - "type": "boolean" - }, - "ageSeconds": { - "type": "number" - }, - "sloSeconds": { - "type": "number" - }, - "breachSeconds": { - "type": "number" - }, - "observedAt": { - "type": "string", - "nullable": true - }, - "summary": { - "type": "string" - } - }, - "required": [ - "area", - "targetKey", - "status", - "launchBlocking", - "sloSeconds", - "summary" - ] - } - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": [ - "status", - "generatedAt", - "staleCount", - "degradedCount", - "blockedCount", - "missingCount", - "launchBlockingCount", - "repairRecommended", - "items", - "warnings" - ] - }, - "coreSignalFidelity": { - "$ref": "#/components/schemas/CoreSignalFidelity" - }, - "upstreamDrift": { - "$ref": "#/components/schemas/UpstreamStatus" - }, - "historyCoverage": { - "type": "string", - "enum": [ - "sampled", - "counts_only", - "full" - ] - }, - "refreshingRepos": { - "type": "array", - "items": { - "type": "string" - } - }, - "waitingForRateLimitRepos": { - "type": "array", - "items": { - "type": "string" - } - }, - "repositories": { - "type": "array", - "items": { - "$ref": "#/components/schemas/RepoSyncState" - } - }, - "segments": { - "type": "array", - "items": { - "$ref": "#/components/schemas/RepoSyncSegment" - } - }, - "githubTotals": { - "type": "array", - "items": { - "$ref": "#/components/schemas/RepoGithubTotalsSnapshot" - } - }, - "pullRequestDetailSync": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "nullable": true - } - } - }, - "installations": { - "type": "array", - "items": { - "$ref": "#/components/schemas/InstallationHealth" - } - }, - "rateLimits": { - "type": "array", - "items": { - "$ref": "#/components/schemas/GitHubRateLimitObservation" - } - } - }, - "required": [ - "generatedAt", - "signalFidelity", - "freshnessSlo", - "coreSignalFidelity", - "upstreamDrift", - "historyCoverage", - "refreshingRepos", - "waitingForRateLimitRepos", - "repositories", - "segments", - "githubTotals", - "pullRequestDetailSync", - "installations", - "rateLimits" - ] - }, "Readiness": { "type": "object", "properties": { diff --git a/package-lock.json b/package-lock.json index f667e25581..44384ddc7b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,13 +13,13 @@ "packages/*" ], "dependencies": { - "@asteasolutions/zod-to-openapi": "^7.3.4", - "@modelcontextprotocol/sdk": "1.26.0", + "@asteasolutions/zod-to-openapi": "^8.5.0", + "@modelcontextprotocol/sdk": "1.29.0", "@octokit/core": "^7.0.6", "agents": "^0.7.9", "drizzle-orm": "^0.45.0", "hono": "^4.12.23", - "zod": "^3.25.76" + "zod": "^4.4.3" }, "devDependencies": { "@cloudflare/vitest-pool-workers": "^0.16.10", @@ -95,7 +95,7 @@ "tw-animate-css": "^1.3.4", "vaul": "^1.1.2", "vite-tsconfig-paths": "^6.0.2", - "zod": "^3.24.2" + "zod": "^4.4.3" }, "devDependencies": { "@eslint/js": "^9.32.0", @@ -619,9 +619,9 @@ "license": "MIT" }, "apps/gittensory-ui/node_modules/vite": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.3.tgz", - "integrity": "sha512-/4XH147Ui7OGTjg3HbdWe5arnZQSbfuRzdr9Ec7TQi5I7R+ir0Rlc9GIvD4v0XZurELqA035KVXJXpR61xhiTA==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.5.tgz", + "integrity": "sha512-KuOaNhcnGFN2zIPGA7wRmzF+lJA1sea7rHq17aiJ++9lzY1WWG6Jpwqwe1KNbRVPIqHmr8GLYx7jbrQcN/7/ww==", "dev": true, "license": "MIT", "dependencies": { @@ -773,15 +773,15 @@ } }, "node_modules/@asteasolutions/zod-to-openapi": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@asteasolutions/zod-to-openapi/-/zod-to-openapi-7.3.4.tgz", - "integrity": "sha512-/2rThQ5zPi9OzVwes6U7lK1+Yvug0iXu25olp7S0XsYmOqnyMfxH7gdSQjn/+DSOHRg7wnotwGJSyL+fBKdnEA==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@asteasolutions/zod-to-openapi/-/zod-to-openapi-8.5.0.tgz", + "integrity": "sha512-SABbKiObg5dLRiTFnqiW1WWwGcg1BJfmHtT2asIBnBHg6Smy/Ms2KHc650+JI4Hw7lSkdiNebEGXpwoxfben8Q==", "license": "MIT", "dependencies": { "openapi3-ts": "^4.1.2" }, "peerDependencies": { - "zod": "^3.20.2" + "zod": "^4.0.0" } }, "node_modules/@babel/code-frame": { @@ -843,34 +843,6 @@ "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/core/node_modules/@babel/parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", - "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.7" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/core/node_modules/@babel/types": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", - "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -896,34 +868,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/generator/node_modules/@babel/parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", - "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.7" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/generator/node_modules/@babel/types": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", - "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/generator/node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", @@ -981,19 +925,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-module-imports/node_modules/@babel/types": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", - "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-module-transforms": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", @@ -1060,26 +991,13 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helpers/node_modules/@babel/types": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", - "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/parser": { - "version": "7.29.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz", - "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", "license": "MIT", "dependencies": { - "@babel/types": "^7.29.0" + "@babel/types": "^7.29.7" }, "bin": { "parser": "bin/babel-parser.js" @@ -1185,34 +1103,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/template/node_modules/@babel/parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", - "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.7" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/template/node_modules/@babel/types": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", - "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/traverse": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", @@ -1231,22 +1121,7 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/traverse/node_modules/@babel/parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", - "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.7" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/traverse/node_modules/@babel/types": { + "node_modules/@babel/types": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", @@ -1259,19 +1134,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@bcoe/v8-coverage": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", @@ -1333,6 +1195,16 @@ "vitest": "^4.1.0" } }, + "node_modules/@cloudflare/vitest-pool-workers/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "node_modules/@cloudflare/workerd-darwin-64": { "version": "1.20260526.1", "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260526.1.tgz", @@ -2918,9 +2790,9 @@ } }, "node_modules/@modelcontextprotocol/sdk": { - "version": "1.26.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.26.0.tgz", - "integrity": "sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==", + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", + "integrity": "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==", "license": "MIT", "dependencies": { "@hono/node-server": "^1.19.9", @@ -6076,15 +5948,6 @@ "url": "https://github.com/sponsors/tannerlinsley" } }, - "node_modules/@tanstack/router-generator/node_modules/zod": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", - "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, "node_modules/@tanstack/router-plugin": { "version": "1.168.13", "resolved": "https://registry.npmjs.org/@tanstack/router-plugin/-/router-plugin-1.168.13.tgz", @@ -6137,15 +6000,6 @@ } } }, - "node_modules/@tanstack/router-plugin/node_modules/zod": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", - "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, "node_modules/@tanstack/router-utils": { "version": "1.162.1", "resolved": "https://registry.npmjs.org/@tanstack/router-utils/-/router-utils-1.162.1.tgz", @@ -6280,15 +6134,6 @@ "node": ">= 12" } }, - "node_modules/@tanstack/start-plugin-core/node_modules/zod": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", - "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, "node_modules/@tanstack/start-server-core": { "version": "1.169.8", "resolved": "https://registry.npmjs.org/@tanstack/start-server-core/-/start-server-core-1.169.8.tgz", @@ -6487,9 +6332,9 @@ "license": "MIT" }, "node_modules/@types/estree": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", - "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true, "license": "MIT" }, @@ -7112,6 +6957,55 @@ } } }, + "node_modules/agents/node_modules/@modelcontextprotocol/sdk": { + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.26.0.tgz", + "integrity": "sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==", + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.9", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, + "node_modules/agents/node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/agents/node_modules/nanoid": { "version": "5.1.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.11.tgz", @@ -12277,13 +12171,6 @@ "fsevents": "~2.3.2" } }, - "node_modules/rollup/node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, "node_modules/rosie-skills": { "version": "0.6.4", "resolved": "https://registry.npmjs.org/rosie-skills/-/rosie-skills-0.6.4.tgz", @@ -13143,9 +13030,9 @@ "license": "MIT" }, "node_modules/undici": { - "version": "6.25.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.25.0.tgz", - "integrity": "sha512-ZgpWDC5gmNiuY9CnLVXEH8rl50xhRCuLNA97fAUnKi8RRuV4E6KG31pDTsLVUKnohJE0I3XDrTeEydAXRw47xg==", + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.26.0.tgz", + "integrity": "sha512-4yqz8a3n5HmGTlsbADNtr/dJlhkh/55Rq798G6ibiULcXbDtaLpTl1pvdqcbFfeoj3iSi52lePFM7h9H21cw/A==", "dev": true, "license": "MIT", "engines": { @@ -13832,9 +13719,9 @@ } }, "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" @@ -13851,11 +13738,11 @@ }, "packages/gittensory-mcp": { "name": "@jsonbored/gittensory-mcp", - "version": "0.3.0", + "version": "0.4.0", "license": "AGPL-3.0-only", "dependencies": { - "@modelcontextprotocol/sdk": "1.26.0", - "zod": "^3.25.76" + "@modelcontextprotocol/sdk": "1.29.0", + "zod": "^4.4.3" }, "bin": { "gittensory-mcp": "bin/gittensory-mcp.js" diff --git a/package.json b/package.json index 3f99a8f455..15bd02a435 100644 --- a/package.json +++ b/package.json @@ -34,10 +34,11 @@ "ui:version:built": "wrangler versions upload --config apps/gittensory-ui/dist/server/wrangler.json", "changelog": "npm run changelog:root && npm run changelog:mcp", "changelog:root": "git-cliff --config cliff.toml --output CHANGELOG.md", - "changelog:mcp": "git-cliff --config cliff.mcp.toml --include-path 'packages/gittensory-mcp/**' --include-path '.github/workflows/npm-publish.yml' --output packages/gittensory-mcp/CHANGELOG.md", + "changelog:mcp": "node scripts/generate-mcp-changelog.mjs --output packages/gittensory-mcp/CHANGELOG.md", "changelog:check": "node scripts/check-changelog.mjs", "changelog:check:root": "node scripts/check-changelog.mjs --root", "changelog:check:mcp": "node scripts/check-changelog.mjs --mcp", + "mcp:release-due": "node scripts/check-mcp-release-due.mjs --json", "typecheck": "tsc --noEmit", "test": "vitest run", "test:unit": "vitest run test/unit", @@ -55,13 +56,13 @@ "validate": "npm run typecheck && npm run test:coverage" }, "dependencies": { - "@asteasolutions/zod-to-openapi": "^7.3.4", - "@modelcontextprotocol/sdk": "1.26.0", + "@asteasolutions/zod-to-openapi": "^8.5.0", + "@modelcontextprotocol/sdk": "1.29.0", "@octokit/core": "^7.0.6", "agents": "^0.7.9", "drizzle-orm": "^0.45.0", "hono": "^4.12.23", - "zod": "^3.25.76" + "zod": "^4.4.3" }, "devDependencies": { "@cloudflare/vitest-pool-workers": "^0.16.10", diff --git a/packages/gittensory-mcp/CHANGELOG.md b/packages/gittensory-mcp/CHANGELOG.md index b986c4f597..1f3ba7854a 100644 --- a/packages/gittensory-mcp/CHANGELOG.md +++ b/packages/gittensory-mcp/CHANGELOG.md @@ -1,5 +1,37 @@ # Changelog +## mcp-v0.4.0 - 2026-06-02 + +### Features +- Add lifecycle watcher signals (#29) +- Add local workspace intelligence v2 (#70) +- Monitor open PRs and wire into decision packs (#72) +- Validate linked issue multiplier (#179) +- Classify control-panel roles (#189) +- Add privacy-safe usage event spine (#182) +- Track MCP compatibility adoption (#185) +- Ingest maintainer focus manifests for repo-specific guidance (#191) +- Learn accepted and rejected PR patterns by repo (#75) +- Model branch eligibility for issue PRs (#178) +- Add recommendation confidence provenance (#226) +- Add contributor evidence graph (#218) +- Require 0.4.0 as the current supported client + +### Fixes +- Saturation-model contribution bonus capped at 5 instead of 25 (#181) +- Bound local scorer warning diagnostics (#210) +- Scope open PR monitor public actions (#208) +- Pending-PR projection double-counting merge-ready PRs (#222) + +### Security +- Keep maintainer notes out of branch guidance (#213) + +### Docs +- Add coverage buffer and contributor test-quality guidance (#55) + +### Dependencies +- Update MCP release dependency stack (@modelcontextprotocol/sdk 1.26.0 -> 1.29.0, zod ^3.25.76 -> ^4.4.3, @asteasolutions/zod-to-openapi ^7.3.4 -> ^8.5.0) + ## mcp-v0.3.0 - 2026-05-31 @@ -58,6 +90,3 @@ - Add install site and mcp diagnostics - Add situational score projections - - - diff --git a/packages/gittensory-mcp/bin/gittensory-mcp.js b/packages/gittensory-mcp/bin/gittensory-mcp.js index 078d7abd61..b17a5575a9 100755 --- a/packages/gittensory-mcp/bin/gittensory-mcp.js +++ b/packages/gittensory-mcp/bin/gittensory-mcp.js @@ -10,7 +10,7 @@ import { buildBranchAnalysisPayload, collectLocalDiff, collectLocalBranchMetadat const defaultApiUrl = "https://gittensory-api.aethereal.dev"; const legacyDefaultApiUrls = new Set(["https://gittensory-api.zeronode.workers.dev"]); const packageName = "@jsonbored/gittensory-mcp"; -const packageVersion = "0.3.0"; +const packageVersion = "0.4.0"; const npmRegistryUrl = (process.env.GITTENSORY_NPM_REGISTRY_URL ?? "https://registry.npmjs.org").replace(/\/+$/, ""); const upgradeCommand = `npm install -g ${packageName}@latest`; const npxFallbackCommand = `npx ${packageName}@latest `; diff --git a/packages/gittensory-mcp/package.json b/packages/gittensory-mcp/package.json index ecb5e4f51a..4a70ca50c2 100644 --- a/packages/gittensory-mcp/package.json +++ b/packages/gittensory-mcp/package.json @@ -1,6 +1,6 @@ { "name": "@jsonbored/gittensory-mcp", - "version": "0.3.0", + "version": "0.4.0", "license": "AGPL-3.0-only", "type": "module", "description": "Local stdio MCP wrapper for the Gittensory Gittensor base-agent.", @@ -38,8 +38,8 @@ "build": "node --check bin/gittensory-mcp.js && node --check lib/local-branch.js && node --check scripts/gittensor-score-preview.mjs" }, "dependencies": { - "@modelcontextprotocol/sdk": "1.26.0", - "zod": "^3.25.76" + "@modelcontextprotocol/sdk": "1.29.0", + "zod": "^4.4.3" }, "engines": { "node": ">=22.0.0" diff --git a/scripts/check-changelog.mjs b/scripts/check-changelog.mjs index bbfba5287b..99d5e9f2be 100644 --- a/scripts/check-changelog.mjs +++ b/scripts/check-changelog.mjs @@ -1,5 +1,5 @@ #!/usr/bin/env node -import { mkdtempSync, readFileSync, rmSync } from "node:fs"; +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { spawnSync } from "node:child_process"; @@ -22,34 +22,30 @@ try { output: "CHANGELOG.md", command: "npm run changelog:root", selector: "--root", - args: ["--config", "cliff.toml", "--output", join(tempDir, "CHANGELOG.md")], + runner: () => { + const generatedPath = join(tempDir, "CHANGELOG.md"); + run(["git-cliff", "--config", "cliff.toml", "--output", generatedPath], "root changelog"); + return generatedPath; + }, }, { label: "MCP package changelog", output: "packages/gittensory-mcp/CHANGELOG.md", command: "npm run changelog:mcp", selector: "--mcp", - releaseTag: () => `mcp-v${JSON.parse(readFileSync("packages/gittensory-mcp/package.json", "utf8")).version}`, - args: [ - "--config", - "cliff.mcp.toml", - "--include-path", - "packages/gittensory-mcp/**", - "--include-path", - ".github/workflows/npm-publish.yml", - "--output", - join(tempDir, "MCP_CHANGELOG.md"), - ], + runner: () => { + const generatedPath = join(tempDir, "MCP_CHANGELOG.md"); + const version = JSON.parse(readFileSync("packages/gittensory-mcp/package.json", "utf8")).version; + writeFileSync(generatedPath, readFileSync("packages/gittensory-mcp/CHANGELOG.md", "utf8")); + run(["node", "scripts/generate-mcp-changelog.mjs", "--output", generatedPath, "--version", version], "MCP package changelog"); + return generatedPath; + }, }, ].filter((check) => requestedChecks.size === 0 || requestedChecks.has(check.selector)); const failures = []; for (const check of checks) { - const args = [...check.args]; - const releaseTag = typeof check.releaseTag === "function" ? check.releaseTag() : null; - if (releaseTag && changelogHasReleaseHeader(check.output, releaseTag)) args.push("--tag", releaseTag); - const generatedPath = args[args.lastIndexOf("--output") + 1]; - run(["git-cliff", ...args], check.label); + const generatedPath = check.runner(); const expected = readFileSync(generatedPath, "utf8"); const actual = readFileSync(check.output, "utf8"); if (normalize(actual) !== normalize(expected)) failures.push(`${check.output} is stale; run ${check.command}.`); @@ -76,11 +72,3 @@ function run(command, label) { function normalize(value) { return value.replace(/\r\n/g, "\n").trimEnd(); } - -function changelogHasReleaseHeader(path, tag) { - return new RegExp(`^## ${escapeRegExp(tag)} - `, "m").test(readFileSync(path, "utf8")); -} - -function escapeRegExp(value) { - return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); -} diff --git a/scripts/check-mcp-release-due.mjs b/scripts/check-mcp-release-due.mjs new file mode 100644 index 0000000000..9e0c22a3de --- /dev/null +++ b/scripts/check-mcp-release-due.mjs @@ -0,0 +1,153 @@ +#!/usr/bin/env node +import { execFileSync, spawnSync } from "node:child_process"; +import { readFileSync, writeFileSync } from "node:fs"; +import { resolve } from "node:path"; +import { pathToFileURL } from "node:url"; +import { buildMcpReleaseIssue, buildMcpReleaseReport, latestSemverTag, MCP_RELEASE_DUE_MARKER } from "./mcp-release-core.mjs"; + +const packageJsonPath = "packages/gittensory-mcp/package.json"; + +async function main() { + const args = parseArgs(process.argv.slice(2)); + const latestTag = latestSemverTag(git(["tag", "--list", "mcp-v*", "--sort=-v:refname"]).split("\n").filter(Boolean)); + const packageVersion = JSON.parse(readFileSync(packageJsonPath, "utf8")).version; + const publishedVersion = readPublishedPackageVersion(); + const commits = latestTag ? readCommits(`${latestTag.tag}..HEAD`) : readCommits("HEAD"); + const report = buildMcpReleaseReport({ latestTag, packageVersion, publishedVersion, commits }); + + if (args.output) writeFileSync(args.output, `${JSON.stringify(report, null, 2)}\n`); + if (args.upsertIssue && report.due) await upsertIssue(report); + if (args.json) process.stdout.write(`${JSON.stringify(report, null, 2)}\n`); + if (!args.json && !args.output) { + process.stdout.write(report.due ? `MCP release due: ${report.proposedVersion}\n` : "No MCP release due.\n"); + } +} + +function parseArgs(argv) { + const args = { json: false, output: null, upsertIssue: false }; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === "--json") { + args.json = true; + } else if (arg === "--output") { + args.output = argv[++index]; + } else if (arg === "--upsert-issue") { + args.upsertIssue = true; + } else { + throw new Error(`Unknown option: ${arg}`); + } + } + return args; +} + +function readPublishedPackageVersion() { + const result = spawnSync("npm", ["view", "@jsonbored/gittensory-mcp", "version", "--json"], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }); + if (result.status !== 0) return null; + try { + const parsed = JSON.parse(result.stdout); + return typeof parsed === "string" ? parsed : null; + } catch { + return result.stdout.trim() || null; + } +} + +function readCommits(revisionRange) { + const format = "%x1e%H%x1f%s%x1f%B"; + const logOutput = git(["log", "--reverse", "--no-merges", `--format=${format}`, revisionRange]); + return logOutput + .split("\x1e") + .map((entry) => entry.trim()) + .filter(Boolean) + .map((entry) => { + const [sha, subject, ...bodyParts] = entry.split("\x1f"); + return { + sha, + subject: subject?.split("\n")[0] ?? "", + body: bodyParts.join("\x1f"), + files: readCommitFiles(sha), + }; + }); +} + +function readCommitFiles(sha) { + return git(["diff-tree", "--no-commit-id", "--name-only", "-r", sha]).split("\n").filter(Boolean); +} + +function git(args) { + return execFileSync("git", args, { encoding: "utf8" }); +} + +async function upsertIssue(report) { + const repository = process.env.GITHUB_REPOSITORY; + const token = process.env.GITHUB_TOKEN; + if (!repository) throw new Error("GITHUB_REPOSITORY is required for --upsert-issue"); + if (!token) throw new Error("GITHUB_TOKEN is required for --upsert-issue"); + const [owner, repo] = repository.split("/"); + if (!owner || !repo) throw new Error(`Invalid GITHUB_REPOSITORY: ${repository}`); + + const issue = buildMcpReleaseIssue(report); + const existingIssue = await findExistingIssue({ owner, repo, token }); + if (existingIssue) { + await githubRequest({ + token, + method: "PATCH", + path: `/repos/${owner}/${repo}/issues/${existingIssue.number}`, + body: { title: issue.title, body: issue.body }, + }); + process.stdout.write(`Updated issue #${existingIssue.number}: ${issue.title}\n`); + return; + } + + const created = await githubRequest({ + token, + method: "POST", + path: `/repos/${owner}/${repo}/issues`, + body: issue, + }); + process.stdout.write(`Opened issue #${created.number}: ${issue.title}\n`); +} + +async function findExistingIssue({ owner, repo, token }) { + let page = 1; + while (page <= 10) { + const issues = await githubRequest({ + token, + method: "GET", + path: `/repos/${owner}/${repo}/issues?state=open&per_page=100&page=${page}`, + }); + if (!Array.isArray(issues) || issues.length === 0) return null; + const match = issues.find((issue) => !issue.pull_request && typeof issue.body === "string" && issue.body.includes(MCP_RELEASE_DUE_MARKER)); + if (match) return match; + page += 1; + } + return null; +} + +async function githubRequest({ token, method, path, body }) { + const response = await fetch(`https://api.github.com${path}`, { + method, + headers: { + accept: "application/vnd.github+json", + authorization: `Bearer ${token}`, + "content-type": "application/json", + "user-agent": "gittensory-mcp-release-watch", + "x-github-api-version": "2022-11-28", + }, + body: body ? JSON.stringify(body) : undefined, + }); + const text = await response.text(); + const payload = text ? JSON.parse(text) : null; + if (!response.ok) { + const message = payload?.message ?? response.statusText; + throw new Error(`GitHub API ${method} ${path} failed: ${response.status} ${message}`); + } + return payload; +} + +const entrypointPath = process.argv[1] ? resolve(process.argv[1]) : ""; +if (import.meta.url === pathToFileURL(entrypointPath).href) { + main().catch((error) => { + process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`); + process.exit(1); + }); +} diff --git a/scripts/generate-mcp-changelog.mjs b/scripts/generate-mcp-changelog.mjs new file mode 100644 index 0000000000..c4e1e089d2 --- /dev/null +++ b/scripts/generate-mcp-changelog.mjs @@ -0,0 +1,180 @@ +#!/usr/bin/env node +import { execFileSync } from "node:child_process"; +import { existsSync, readFileSync, writeFileSync } from "node:fs"; +import { resolve } from "node:path"; +import { pathToFileURL } from "node:url"; +import { latestSemverTag, renderMcpChangelog, selectMcpReleaseCommits } from "./mcp-release-core.mjs"; + +const defaultOutput = "packages/gittensory-mcp/CHANGELOG.md"; +const defaultPackageJson = "packages/gittensory-mcp/package.json"; + +export function generateMcpChangelog({ output = defaultOutput, version, generatedAt, baseTag, dryRun = false } = {}) { + const targetVersion = version ?? readPackageVersion(defaultPackageJson); + const resolvedBaseTag = baseTag ?? latestTagBeforeVersion(targetVersion)?.tag ?? null; + const commits = resolvedBaseTag ? readCommits(`${resolvedBaseTag}..HEAD`) : readCommits("HEAD"); + const selectedCommits = [...selectMcpReleaseCommits(commits), ...readReleasePrepEntries({ baseTag: resolvedBaseTag, targetVersion })]; + const existingChangelog = existsSync(output) ? readFileSync(output, "utf8") : ""; + const releaseDate = generatedAt ?? existingReleaseDate(existingChangelog, targetVersion) ?? todayIsoDate(); + const changelog = renderMcpChangelog({ + existingChangelog, + targetVersion, + generatedAt: releaseDate, + commits: selectedCommits, + }); + + if (!dryRun) writeFileSync(output, changelog); + return { output, version: targetVersion, baseTag: resolvedBaseTag, commits: selectedCommits, changelog }; +} + +function main() { + const args = parseArgs(process.argv.slice(2)); + const result = generateMcpChangelog(args); + if (args.dryRun) { + process.stdout.write(result.changelog); + } else { + process.stdout.write(`Generated ${result.output} for mcp-v${result.version} from ${result.baseTag ?? "repository root"} (${result.commits.length} commits)\n`); + } +} + +function parseArgs(argv) { + const args = {}; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === "--output") { + args.output = argv[++index]; + } else if (arg === "--version") { + args.version = argv[++index]; + } else if (arg === "--date") { + args.generatedAt = argv[++index]; + } else if (arg === "--base-tag") { + args.baseTag = argv[++index]; + } else if (arg === "--dry-run") { + args.dryRun = true; + } else { + throw new Error(`Unknown option: ${arg}`); + } + } + return args; +} + +function latestTagBeforeVersion(version) { + const tags = git(["tag", "--list", "mcp-v*", "--sort=-v:refname"]).split("\n").filter(Boolean); + return latestSemverTag(tags.filter((tag) => tag.replace(/^mcp-v/, "") !== version)); +} + +function readCommits(revisionRange) { + const format = "%x1e%H%x1f%s%x1f%B"; + const logOutput = git(["log", "--reverse", "--no-merges", `--format=${format}`, revisionRange]); + return logOutput + .split("\x1e") + .map((entry) => entry.trim()) + .filter(Boolean) + .map((entry) => { + const [sha, subject, ...bodyParts] = entry.split("\x1f"); + return { + sha, + subject: subject?.split("\n")[0] ?? "", + body: bodyParts.join("\x1f"), + files: readCommitFiles(sha), + }; + }); +} + +function readCommitFiles(sha) { + return git(["diff-tree", "--no-commit-id", "--name-only", "-r", sha]).split("\n").filter(Boolean); +} + +function readPackageVersion(path) { + return JSON.parse(readFileSync(path, "utf8")).version; +} + +function readReleasePrepEntries({ baseTag, targetVersion }) { + if (!baseTag) return []; + const entries = []; + const previousMcpPackage = readJsonAt(baseTag, defaultPackageJson); + const currentMcpPackage = JSON.parse(readFileSync(defaultPackageJson, "utf8")); + const previousRootPackage = readJsonAt(baseTag, "package.json"); + const currentRootPackage = JSON.parse(readFileSync("package.json", "utf8")); + const previousCompatibility = readFileAt(baseTag, "src/services/mcp-compatibility.ts"); + const currentCompatibility = readFileSync("src/services/mcp-compatibility.ts", "utf8"); + + const dependencyChanges = [ + dependencyChange("@modelcontextprotocol/sdk", previousMcpPackage?.dependencies, currentMcpPackage.dependencies), + dependencyChange("zod", previousMcpPackage?.dependencies, currentMcpPackage.dependencies), + dependencyChange("@asteasolutions/zod-to-openapi", previousRootPackage?.dependencies, currentRootPackage.dependencies), + dependencyChange("agents", previousRootPackage?.dependencies, currentRootPackage.dependencies), + ].filter(Boolean); + + if (dependencyChanges.length > 0) { + entries.push({ + sha: "release-prep-deps", + subject: `chore(deps): update MCP release dependency stack (${dependencyChanges.join(", ")})`, + files: ["package.json", "packages/gittensory-mcp/package.json", "package-lock.json"], + }); + } + + const previousMinimum = readConstant(previousCompatibility, "MINIMUM_SUPPORTED_MCP_VERSION"); + const currentMinimum = readConstant(currentCompatibility, "MINIMUM_SUPPORTED_MCP_VERSION"); + const previousLatest = readConstant(previousCompatibility, "LATEST_RECOMMENDED_MCP_VERSION"); + const currentLatest = readConstant(currentCompatibility, "LATEST_RECOMMENDED_MCP_VERSION"); + if ((previousMinimum !== currentMinimum || previousLatest !== currentLatest) && currentMinimum === targetVersion && currentLatest === targetVersion) { + entries.push({ + sha: "release-prep-compat", + subject: `feat(mcp): require ${targetVersion} as the current supported client`, + files: ["src/services/mcp-compatibility.ts"], + }); + } + + return entries; +} + +function dependencyChange(name, previousDependencies = {}, currentDependencies = {}) { + const previousVersion = previousDependencies?.[name]; + const currentVersion = currentDependencies?.[name]; + if (!previousVersion || !currentVersion || previousVersion === currentVersion) return null; + return `${name} ${previousVersion} -> ${currentVersion}`; +} + +function readConstant(source, constantName) { + return new RegExp(`export const ${constantName} = "([^"]+)"`).exec(source)?.[1] ?? null; +} + +function readJsonAt(ref, path) { + const source = readFileAt(ref, path); + return source ? JSON.parse(source) : null; +} + +function readFileAt(ref, path) { + try { + return git(["show", `${ref}:${path}`]); + } catch { + return null; + } +} + +function existingReleaseDate(changelog, version) { + const match = new RegExp(`^## mcp-v${escapeRegExp(version)} - (\\d{4}-\\d{2}-\\d{2})$`, "m").exec(changelog); + return match?.[1] ?? null; +} + +function todayIsoDate() { + return new Date().toISOString().slice(0, 10); +} + +function git(args) { + return execFileSync("git", args, { encoding: "utf8" }); +} + +function escapeRegExp(value) { + return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); +} + +const entrypointPath = process.argv[1] ? resolve(process.argv[1]) : ""; +if (import.meta.url === pathToFileURL(entrypointPath).href) { + try { + main(); + } catch (error) { + process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`); + process.exit(1); + } +} diff --git a/scripts/mcp-release-core.d.mts b/scripts/mcp-release-core.d.mts new file mode 100644 index 0000000000..c129a0122d --- /dev/null +++ b/scripts/mcp-release-core.d.mts @@ -0,0 +1,43 @@ +export const MCP_RELEASE_DUE_MARKER: string; + +export type McpReleaseCommit = { + sha?: string; + subject?: string; + body?: string; + files?: string[]; +}; + +export type McpReleaseReport = { + due: boolean; + proposedVersion: string; + latestTag: string | null; + latestTagVersion: string | null; + packageVersion: string; + publishedVersion: string | null; + releaseType: "major" | "minor" | "patch" | null; + commits: McpReleaseCommit[]; + changedFiles: string[]; +}; + +export function parseConventionalSubject(subject: string): { + type: string | null; + scope: string | null; + breaking: boolean; + description: string; + conventional: boolean; +}; +export function compareSemver(leftVersion: string, rightVersion: string): number | null; +export function bumpVersion(version: string, releaseType: "major" | "minor" | "patch"): string; +export function latestSemverTag(tags: string[]): { tag: string; version: string } | null; +export function selectMcpReleaseCommits(commits: T[]): T[]; +export function isMcpReleaseRelevantCommit(commit: McpReleaseCommit): boolean; +export function renderMcpChangelog(input: { existingChangelog?: string; targetVersion: string; generatedAt: string; commits: McpReleaseCommit[] }): string; +export function renderReleaseSection(input: { tag: string; generatedAt: string; commits: McpReleaseCommit[] }): string; +export function buildMcpReleaseReport(input: { + latestTag: { tag: string; version: string } | null; + packageVersion: string; + publishedVersion: string | null; + commits: McpReleaseCommit[]; +}): McpReleaseReport; +export function buildMcpReleaseIssue(report: McpReleaseReport): { title: string; body: string }; +export function normalizeNewlines(value: string): string; diff --git a/scripts/mcp-release-core.mjs b/scripts/mcp-release-core.mjs new file mode 100644 index 0000000000..6d686a1291 --- /dev/null +++ b/scripts/mcp-release-core.mjs @@ -0,0 +1,331 @@ +export const MCP_RELEASE_DUE_MARKER = ""; + +const DIRECT_MCP_PATHS = [ + "packages/gittensory-mcp/", + ".github/workflows/npm-publish.yml", + "src/mcp/", + "src/services/mcp-compatibility.ts", + "src/signals/local-branch.ts", + "src/signals/local-workspace-intelligence.ts", +]; + +const CLIENT_VISIBLE_PATHS = [ + "src/services/agent-orchestrator.ts", + "src/services/client-telemetry.ts", + "src/services/contributor-evidence-graph.ts", + "src/services/decision-pack.ts", + "src/services/repo-outcome-patterns.ts", + "src/scoring/pending-pr-scenarios.ts", + "src/scoring/preview.ts", + "src/signals/focus-manifest-loader.ts", + "src/signals/focus-manifest.ts", +]; + +const SUPPORTING_VISIBLE_PATHS = ["src/openapi/schemas.ts", "src/openapi/spec.ts"]; + +const GENERATED_OPENAPI_PATHS = ["apps/gittensory-ui/public/openapi.json", "src/openapi/spec.ts"]; +const UI_ONLY_PREFIXES = ["apps/gittensory-ui/", "apps/gittensory-extension/"]; +const RELEASE_SCOPES = new Set(["release", "changelog"]); +const EXCLUDED_SCOPES = new Set(["pwa", "ui", "extension", "github-agent", "sync", "upstream"]); +const GROUP_ORDER = ["Features", "Fixes", "Security", "CI", "Build", "Docs", "Tests", "Refactors", "Dependencies", "Chores", "Reverts"]; + +export function parseConventionalSubject(subject) { + const trimmed = subject.trim(); + const match = /^(?[a-z]+)(?:\((?[^)]+)\))?(?!)?:\s*(?.+)$/.exec(trimmed); + if (match?.groups) { + return { + type: match.groups.type, + scope: match.groups.scope ?? null, + breaking: Boolean(match.groups.breaking), + description: match.groups.description.trim(), + conventional: true, + }; + } + + if (/^fix\b/i.test(trimmed)) { + return { + type: "fix", + scope: null, + breaking: false, + description: trimmed.replace(/^fix[:\s-]*/i, "").trim() || trimmed, + conventional: false, + }; + } + + return { + type: null, + scope: null, + breaking: false, + description: trimmed, + conventional: false, + }; +} + +export function compareSemver(leftVersion, rightVersion) { + const left = parseSemver(leftVersion); + const right = parseSemver(rightVersion); + if (!left || !right) return null; + for (const part of ["major", "minor", "patch"]) { + if (left[part] !== right[part]) return left[part] < right[part] ? -1 : 1; + } + if (left.prerelease === right.prerelease) return 0; + if (!left.prerelease) return 1; + if (!right.prerelease) return -1; + const prereleaseComparison = left.prerelease.localeCompare(right.prerelease, undefined, { numeric: true, sensitivity: "base" }); + return prereleaseComparison === 0 ? 0 : prereleaseComparison < 0 ? -1 : 1; +} + +export function bumpVersion(version, releaseType) { + const parsed = parseSemver(version); + if (!parsed) throw new Error(`Invalid semver version: ${version}`); + if (releaseType === "major") return `${parsed.major + 1}.0.0`; + if (releaseType === "minor") return `${parsed.major}.${parsed.minor + 1}.0`; + return `${parsed.major}.${parsed.minor}.${parsed.patch + 1}`; +} + +export function latestSemverTag(tags) { + return tags + .map((tag) => ({ tag, version: tag.replace(/^mcp-v/, "") })) + .filter(({ version }) => parseSemver(version)) + .sort((left, right) => compareSemver(right.version, left.version) ?? 0)[0] ?? null; +} + +export function selectMcpReleaseCommits(commits) { + return commits.filter((commit) => isMcpReleaseRelevantCommit(commit)); +} + +export function isMcpReleaseRelevantCommit(commit) { + const subject = commit.subject ?? ""; + const files = uniqueSorted(commit.files ?? []); + if (!subject.trim()) return false; + if (/^merge\b/i.test(subject)) return false; + if (isGeneratedOnlyOpenApiChange(files)) return false; + if (isUiOnlyChange(files)) return false; + + const parsed = parseConventionalSubject(subject); + if (parsed.scope && RELEASE_SCOPES.has(parsed.scope)) return false; + if (parsed.scope && EXCLUDED_SCOPES.has(parsed.scope) && !hasAnyPath(files, DIRECT_MCP_PATHS)) return false; + if (!parsed.type && !parsed.conventional) return false; + + const hasDirectMcpPath = hasAnyPath(files, DIRECT_MCP_PATHS); + const hasPackageReleasePath = hasAnyPath(files, ["packages/gittensory-mcp/", ".github/workflows/npm-publish.yml"]); + const hasClientVisiblePath = hasAnyPath(files, CLIENT_VISIBLE_PATHS); + const hasOnlySupportingVisiblePath = hasAnyPath(files, SUPPORTING_VISIBLE_PATHS) && !hasDirectMcpPath && !hasClientVisiblePath; + + if (parsed.type === "test" && !hasPackageReleasePath) return false; + + if (hasDirectMcpPath) return true; + if (hasClientVisiblePath && isClientVisibleChange(parsed, subject)) return true; + if (hasOnlySupportingVisiblePath && parsed.scope === "mcp") return true; + return false; +} + +export function renderMcpChangelog({ existingChangelog = "", targetVersion, generatedAt, commits }) { + const targetTag = `mcp-v${targetVersion}`; + const normalizedExisting = normalizeNewlines(existingChangelog).trimEnd(); + const headerMatch = /^# Changelog\n+/.exec(normalizedExisting); + const header = "# Changelog\n\n"; + const body = headerMatch ? normalizedExisting.slice(headerMatch[0].length) : normalizedExisting.replace(/^# Changelog\s*/m, "").trimStart(); + const newSection = renderReleaseSection({ tag: targetTag, generatedAt, commits }); + const targetHeaderPattern = new RegExp(`^## ${escapeRegExp(targetTag)} - .+$`, "m"); + const targetHeaderMatch = targetHeaderPattern.exec(body); + + if (targetHeaderMatch && targetHeaderMatch.index === 0) { + const nextHeaderIndex = body.indexOf("\n## ", targetHeaderMatch[0].length); + if (nextHeaderIndex === -1) return `${header}${newSection}\n`; + return `${header}${newSection}\n\n${body.slice(nextHeaderIndex + 1)}\n`; + } + + const historical = body.trim().length > 0 ? `${body}\n` : ""; + return historical ? `${header}${newSection}\n\n${historical}` : `${header}${newSection}\n`; +} + +export function renderReleaseSection({ tag, generatedAt, commits }) { + const groups = groupCommits(commits); + const lines = [`## ${tag} - ${generatedAt}`]; + for (const group of GROUP_ORDER) { + const groupCommits = groups.get(group) ?? []; + if (groupCommits.length === 0) continue; + lines.push("", `### ${group}`); + for (const commit of groupCommits) lines.push(`- ${formatCommitForChangelog(commit)}`); + } + if ([...groups.values()].every((entries) => entries.length === 0)) { + lines.push("", "### Chores", "- Prepare MCP release metadata"); + } + return lines.join("\n"); +} + +export function buildMcpReleaseReport({ latestTag, packageVersion, publishedVersion, commits }) { + const includedCommits = selectMcpReleaseCommits(commits); + const releaseType = inferReleaseType(includedCommits); + const latestVersion = latestTag?.version ?? "0.0.0"; + const inferredVersion = releaseType ? bumpVersion(latestVersion, releaseType) : latestVersion; + const proposedVersion = + packageVersion && compareSemver(packageVersion, inferredVersion) === 1 + ? packageVersion + : inferredVersion; + const tagMatchesPackage = latestTag?.version === packageVersion; + const npmMatchesPackage = publishedVersion === packageVersion; + const due = includedCommits.length > 0 || !tagMatchesPackage || !npmMatchesPackage; + + return { + due, + proposedVersion, + latestTag: latestTag?.tag ?? null, + latestTagVersion: latestTag?.version ?? null, + packageVersion, + publishedVersion, + releaseType, + commits: includedCommits, + changedFiles: uniqueSorted(includedCommits.flatMap((commit) => commit.files ?? [])), + }; +} + +export function buildMcpReleaseIssue(report) { + const title = `MCP release due: ${report.proposedVersion}`; + const npmVersion = report.publishedVersion ?? "unknown"; + const latestTag = report.latestTag ?? "none"; + const commits = report.commits.length > 0 ? report.commits.map((commit) => `- \`${shortSha(commit.sha)}\` ${commit.subject}`).join("\n") : "- No unreleased MCP-related commits detected."; + const changedFiles = report.changedFiles.length > 0 ? report.changedFiles.map((file) => `- \`${file}\``).join("\n") : "- No MCP-related changed files detected."; + + const body = `${MCP_RELEASE_DUE_MARKER} + +## Summary + +An MCP release appears due. + +- Proposed version: \`${report.proposedVersion}\` +- Latest MCP tag: \`${latestTag}\` +- npm latest: \`${npmVersion}\` +- MCP package version in repo: \`${report.packageVersion}\` +- Unreleased MCP-related commits: \`${report.commits.length}\` + +## Unreleased MCP-Related Commits + +${commits} + +## Changed Files + +${changedFiles} + +## Release-Prep Checklist + +- [ ] Bump \`packages/gittensory-mcp/package.json\` to \`${report.proposedVersion}\` +- [ ] Bump the CLI \`packageVersion\` constant to \`${report.proposedVersion}\` +- [ ] Update MCP compatibility metadata minimum supported and latest recommended versions to \`${report.proposedVersion}\` +- [ ] Generate \`packages/gittensory-mcp/CHANGELOG.md\` with a \`mcp-v${report.proposedVersion}\` section +- [ ] Run \`npm run build:mcp\` +- [ ] Run \`npm run test:mcp-pack\` +- [ ] Run \`npm run changelog:check:mcp\` +- [ ] Run \`npm run actionlint\` +- [ ] Run \`npm run test:release:mcp\` +- [ ] Merge the release-prep PR +- [ ] Tag \`mcp-v${report.proposedVersion}\` +- [ ] Watch npm trusted publishing and the GitHub Release job +`; + + return { title, body }; +} + +export function normalizeNewlines(value) { + return value.replace(/\r\n/g, "\n"); +} + +function parseSemver(version) { + const match = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(String(version ?? "").trim()); + if (!match) return null; + return { + major: Number(match[1]), + minor: Number(match[2]), + patch: Number(match[3]), + prerelease: match[4] ?? null, + }; +} + +function isClientVisibleChange(parsed, subject) { + if (parsed.breaking) return true; + if (parsed.type === "feat" || parsed.type === "fix" || parsed.type === "refactor") return true; + if (parsed.type === "docs" && /mcp|local|branch|compat|client|release/i.test(subject)) return true; + return /^fix\b/i.test(subject); +} + +function isGeneratedOnlyOpenApiChange(files) { + const meaningfulFiles = files.filter((file) => !isTestFile(file)); + return meaningfulFiles.length > 0 && meaningfulFiles.every((file) => GENERATED_OPENAPI_PATHS.includes(file)); +} + +function isUiOnlyChange(files) { + const meaningfulFiles = files.filter((file) => !isTestFile(file)); + return meaningfulFiles.length > 0 && meaningfulFiles.every((file) => UI_ONLY_PREFIXES.some((prefix) => file.startsWith(prefix))); +} + +function hasAnyPath(files, paths) { + return files.some((file) => paths.some((path) => matchesPath(file, path))); +} + +function matchesPath(file, path) { + return path.endsWith("/") ? file.startsWith(path) : file === path; +} + +function isTestFile(file) { + return file.startsWith("test/") || file.includes(".test.") || file.includes(".spec."); +} + +function groupCommits(commits) { + const groups = new Map(GROUP_ORDER.map((group) => [group, []])); + for (const commit of commits) { + const group = groupForCommit(commit); + groups.get(group)?.push(commit); + } + return groups; +} + +function groupForCommit(commit) { + const parsed = parseConventionalSubject(commit.subject ?? ""); + if (parsed.scope === "security") return "Security"; + if (parsed.type === "feat") return "Features"; + if (parsed.type === "fix") return "Fixes"; + if (parsed.type === "ci") return "CI"; + if (parsed.type === "build") return "Build"; + if (parsed.type === "docs") return "Docs"; + if (parsed.type === "test") return "Tests"; + if (parsed.type === "refactor") return "Refactors"; + if (parsed.type === "chore" && parsed.scope === "deps") return "Dependencies"; + if (parsed.type === "chore") return "Chores"; + if (parsed.type === "revert") return "Reverts"; + return "Chores"; +} + +function formatCommitForChangelog(commit) { + const parsed = parseConventionalSubject(commit.subject ?? ""); + const description = parsed.description || commit.subject || shortSha(commit.sha); + return upperFirst(description); +} + +function inferReleaseType(commits) { + if (commits.length === 0) return null; + let type = "patch"; + for (const commit of commits) { + const parsed = parseConventionalSubject(commit.subject ?? ""); + if (parsed.breaking || /BREAKING CHANGE:/i.test(commit.body ?? "")) return "major"; + if (parsed.type === "feat") type = "minor"; + } + return type; +} + +function uniqueSorted(values) { + return [...new Set(values.filter(Boolean))].sort((left, right) => left.localeCompare(right)); +} + +function shortSha(sha) { + return String(sha ?? "").slice(0, 7); +} + +function upperFirst(value) { + const trimmed = value.trim(); + return trimmed ? `${trimmed[0].toUpperCase()}${trimmed.slice(1)}` : trimmed; +} + +function escapeRegExp(value) { + return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); +} diff --git a/scripts/smoke-production.mjs b/scripts/smoke-production.mjs index c2759e8b8a..3da0f026ac 100644 --- a/scripts/smoke-production.mjs +++ b/scripts/smoke-production.mjs @@ -31,8 +31,14 @@ async function main() { checks.push(checkStatus(`${siteOrigin}/sitemap.xml`, 200, "sitemap", { contentType: /application\/xml/i })); checks.push(checkStatus(`${siteOrigin}/CNAME`, 404, "retired GitHub Pages CNAME")); - checks.push(checkJson(`${apiOrigin}/health`, "API health", (json) => json.status === "ok" && json.latestRecommendedMcpVersion === "0.3.0")); - checks.push(checkJson(`${apiOrigin}/v1/mcp/compatibility`, "MCP compatibility", (json) => json.status === "ok" && json.mcp?.latestPackageVersion === "0.3.0")); + checks.push(checkJson(`${apiOrigin}/health`, "API health", (json) => json.status === "ok" && json.minMcpVersion === "0.4.0" && json.latestRecommendedMcpVersion === "0.4.0")); + checks.push( + checkJson( + `${apiOrigin}/v1/mcp/compatibility`, + "MCP compatibility", + (json) => json.status === "ok" && json.mcp?.minimumSupportedVersion === "0.4.0" && json.mcp?.latestPackageVersion === "0.4.0", + ), + ); checks.push(checkJson(`${apiOrigin}/v1/auth/session`, "signed-out session", (json) => json.status === "signed_out")); checks.push(checkJson(`${apiOrigin}/v1/repos`, "protected API auth", (json, response) => response.status === 401 && json.error === "unauthorized", { expectedStatus: 401 })); checks.push(checkRedirect(`${apiOrigin}/v1/auth/github/start`, "GitHub OAuth start", /^https:\/\/github\.com\/login\/oauth\/authorize\?/)); diff --git a/src/api/routes.ts b/src/api/routes.ts index 44b7f71c9f..704afdb33a 100644 --- a/src/api/routes.ts +++ b/src/api/routes.ts @@ -316,7 +316,7 @@ const localBranchAnalysisSchema = z scenarioNotes: z.array(z.string().max(MAX_LOCAL_BRANCH_TEXT_CHARS)).max(20).optional(), pendingCommitCount: z.number().int().min(0).optional(), ciStatusHints: z.array(z.string().max(MAX_LOCAL_BRANCH_TEXT_CHARS)).max(20).optional(), - focusManifest: z.record(z.unknown()).optional(), + focusManifest: z.record(z.string(), z.unknown()).optional(), branchEligibility: branchEligibilitySchema.optional(), }) .strict(); diff --git a/src/mcp/server.ts b/src/mcp/server.ts index 24f13a09a4..ead4cc0e87 100644 --- a/src/mcp/server.ts +++ b/src/mcp/server.ts @@ -66,6 +66,7 @@ import { buildRepoDataQuality } from "../signals/data-quality"; import { loadUpstreamStatus } from "../upstream/ruleset"; type AppContext = Context<{ Bindings: Env }>; +type AgentsMcpServer = Parameters[0]; type ToolPayload = { summary: string; data: Record; @@ -173,7 +174,7 @@ const localBranchAnalysisShape = { expectedOpenPrCountAfterMerge: z.number().int().min(0).optional(), projectedCredibility: z.number().min(0).max(1).optional(), scenarioNotes: z.array(z.string()).max(20).optional(), - focusManifest: z.record(z.unknown()).optional(), + focusManifest: z.record(z.string(), z.unknown()).optional(), branchEligibility: z.object(branchEligibilityShape).strict().optional(), localScorer: z .object({ @@ -262,7 +263,7 @@ export async function handleMcpRequest(c: AppContext): Promise { const startedAt = Date.now(); const server = new GittensoryMcp(c.env, identity).createServer(); try { - const response = await createMcpHandler(server, { route: "/mcp", enableJsonResponse: true })(c.req.raw, c.env, getExecutionContext(c)); + const response = await createMcpHandler(server as unknown as AgentsMcpServer, { route: "/mcp", enableJsonResponse: true })(c.req.raw, c.env, getExecutionContext(c)); await recordProductUsageEvent(c.env, { surface: "mcp", eventName: typeof usageMetadata.toolName === "string" ? "mcp_tool_called" : "mcp_request", diff --git a/src/openapi/schemas.ts b/src/openapi/schemas.ts index 4a1d5209cc..9eb52acb32 100644 --- a/src/openapi/schemas.ts +++ b/src/openapi/schemas.ts @@ -37,13 +37,13 @@ export const RegistryRepoSchema = z repo: z.string(), emissionShare: z.number(), issueDiscoveryShare: z.number(), - labelMultipliers: z.record(z.number()), + labelMultipliers: z.record(z.string(), z.number()), trustedLabelPipeline: z.boolean().nullable().optional(), maintainerCut: z.number(), defaultLabelMultiplier: z.number().nullable().optional(), fixedBaseScore: z.number().nullable().optional(), eligibilityMode: z.string().nullable().optional(), - raw: z.record(z.unknown()), + raw: z.record(z.string(), z.unknown()), }) .openapi("RegistryRepo"); @@ -469,7 +469,7 @@ export const BountySchema = z status: z.string(), amountText: z.string().nullable().optional(), sourceUrl: z.string().nullable().optional(), - payload: z.record(z.unknown()), + payload: z.record(z.string(), z.unknown()), discoveredAt: z.string().nullable().optional(), updatedAt: z.string().nullable().optional(), }) @@ -506,7 +506,7 @@ export const BountyLifecycleEventsSchema = z repoFullName: z.string(), issueNumber: z.number(), status: z.string(), - payload: z.record(z.unknown()), + payload: z.record(z.string(), z.unknown()), generatedAt: z.string(), }), ), @@ -716,7 +716,7 @@ export const RepoGithubTotalsSnapshotSchema = z fetchedAt: z.string(), rateLimitRemaining: z.number().nullable().optional(), rateLimitResetAt: z.string().nullable().optional(), - payload: z.record(z.unknown()).optional(), + payload: z.record(z.string(), z.unknown()).optional(), }) .openapi("RepoGithubTotalsSnapshot"); @@ -730,11 +730,11 @@ export const InstallationHealthSchema = z status: z.enum(["healthy", "needs_attention", "broken"]), missingPermissions: z.array(z.string()), missingEvents: z.array(z.string()), - permissions: z.record(z.string()), + permissions: z.record(z.string(), z.string()), events: z.array(z.string()), checkedAt: z.string(), errorSummary: z.string().nullable().optional(), - requiredPermissions: z.record(z.string()).optional(), + requiredPermissions: z.record(z.string(), z.string()).optional(), requiredEvents: z.array(z.string()).optional(), optionalVisibleEvents: z.array(z.string()).optional(), permissionRemediation: z @@ -757,7 +757,7 @@ export const UpstreamDriftReportSchema = z currentRulesetId: z.string().nullable().optional(), issueNumber: z.number().nullable().optional(), issueUrl: z.string().nullable().optional(), - payload: z.record(z.unknown()).optional(), + payload: z.record(z.string(), z.unknown()).optional(), generatedAt: z.string(), updatedAt: z.string(), }) @@ -799,7 +799,7 @@ export const UpstreamRulesetSnapshotSchema = z registryRepoCount: z.number(), totalEmissionShare: z.number(), semanticHash: z.string(), - payload: z.record(z.unknown()), + payload: z.record(z.string(), z.unknown()), warnings: z.array(z.string()), generatedAt: z.string(), }) @@ -845,7 +845,7 @@ export const SyncStatusSchema = z repositories: z.array(RepoSyncStateSchema), segments: z.array(RepoSyncSegmentSchema), githubTotals: z.array(RepoGithubTotalsSnapshotSchema), - pullRequestDetailSync: z.array(z.record(z.unknown())), + pullRequestDetailSync: z.array(z.record(z.string(), z.unknown())), installations: z.array(InstallationHealthSchema), rateLimits: z.array(GitHubRateLimitObservationSchema), }) @@ -900,7 +900,7 @@ export const ReadinessSchema = z .nullable(), githubBackfill: z.object({ repoSyncCount: z.number(), - statusCounts: z.record(z.number()), + statusCounts: z.record(z.string(), z.number()), failingSyncs: z.array( z.object({ repoFullName: z.string(), @@ -947,11 +947,11 @@ export const ScoringModelSnapshotSchema = z sourceUrl: z.string(), fetchedAt: z.string(), activeModel: z.enum(["current_density_model", "pending_saturation_model", "exponential_saturation_model", "unknown"]), - constants: z.record(z.number()), - programmingLanguages: z.record(z.unknown()), + constants: z.record(z.string(), z.number()), + programmingLanguages: z.record(z.string(), z.unknown()), registrySnapshotId: z.string().nullable().optional(), warnings: z.array(z.string()), - payload: z.record(z.unknown()), + payload: z.record(z.string(), z.unknown()), }) .openapi("ScoringModelSnapshot"); @@ -1046,7 +1046,7 @@ export const ScorePreviewResultSchema = z scoringModelSnapshotId: z.string(), activeModel: z.enum(["current_density_model", "pending_saturation_model", "exponential_saturation_model", "unknown"]), privateOnly: z.literal(true), - laneMath: z.record(z.number()), + laneMath: z.record(z.string(), z.number()), scoreEstimate: ScoreEstimateSchema, linkedIssueMultiplier: LinkedIssueMultiplierDecisionSchema, gates: ScoreGatesSchema, @@ -1074,7 +1074,7 @@ export const ScorePreviewSchema = z targetType: z.enum(["planned_pr", "pull_request", "local_diff", "variant"]), targetKey: z.string(), contributorLogin: z.string().nullable().optional(), - input: z.record(z.unknown()), + input: z.record(z.string(), z.unknown()), result: ScorePreviewResultSchema, generatedAt: z.string(), }) @@ -1125,7 +1125,7 @@ export const BurdenForecastSchema = z generatedAt: z.string(), horizonDays: z.union([z.literal(7), z.literal(30)]), level: z.enum(["low", "medium", "high", "critical"]), - forecast: z.record(z.number()), + forecast: z.record(z.string(), z.number()), findings: z.array(FindingSchema), summary: z.string(), }) @@ -1136,7 +1136,7 @@ export const ContributorScoringProfileSchema = z login: z.string(), generatedAt: z.string(), scoringModelSnapshotId: z.string(), - evidence: z.record(z.number()), + evidence: z.record(z.string(), z.number()), privateSignals: z.array(z.string()), }) .openapi("ContributorScoringProfile"); @@ -1208,10 +1208,10 @@ export const ContributorOutcomeHistorySchema = z generatedAt: z.string(), source: z.enum(["gittensor_api", "github_cache"]), reconciliation: ContributorReconciliationReportSchema.optional(), - totals: z.record(z.number()), - repoOutcomes: z.array(z.record(z.unknown())), - successPatterns: z.array(z.record(z.unknown())), - failurePatterns: z.array(z.record(z.unknown())), + totals: z.record(z.string(), z.number()), + repoOutcomes: z.array(z.record(z.string(), z.unknown())), + successPatterns: z.array(z.record(z.string(), z.unknown())), + failurePatterns: z.array(z.record(z.string(), z.unknown())), summary: z.string(), }) .openapi("ContributorOutcomeHistory"); @@ -1221,7 +1221,7 @@ export const ContributorPatternReportSchema = z login: z.string(), generatedAt: z.string(), patternType: z.enum(["success", "failure"]), - patterns: z.array(z.record(z.unknown())), + patterns: z.array(z.record(z.string(), z.unknown())), summary: z.string(), }) .openapi("ContributorPatternReport"); @@ -1247,12 +1247,12 @@ export const RepoOutcomePatternsSchema = z lane: z.enum(["direct_pr", "issue_discovery", "split", "inactive", "unknown"]), primaryLanguage: z.string().nullable(), sampleSize: z.number(), - totals: z.record(z.number()), + totals: z.record(z.string(), z.number()), outsideContributorMergeRate: z.number(), maintainerLaneMergeRate: z.number(), - dimensions: z.array(z.record(z.unknown())), - successPatterns: z.array(z.record(z.unknown())), - riskPatterns: z.array(z.record(z.unknown())), + dimensions: z.array(z.record(z.string(), z.unknown())), + successPatterns: z.array(z.record(z.string(), z.unknown())), + riskPatterns: z.array(z.record(z.string(), z.unknown())), evidenceCompleteness: RepoOutcomeEvidenceCompletenessSchema, findings: z.array(FindingSchema), summary: z.string(), @@ -1268,7 +1268,7 @@ export const RepoOutcomePatternsResponseSchema = z ageSeconds: z.number(), freshness: z.enum(["fresh", "stale"]), patterns: RepoOutcomePatternsSchema, - dataQuality: z.record(z.unknown()).optional(), + dataQuality: z.record(z.string(), z.unknown()).optional(), }) .openapi("RepoOutcomePatternsResponse"); @@ -1284,9 +1284,9 @@ export const RepoFitRecommendationSchema = z reasons: z.array(z.string()), risks: z.array(z.string()), nextActions: z.array(z.string()), - rewardRisk: z.record(z.unknown()).optional(), + rewardRisk: z.record(z.string(), z.unknown()).optional(), reasoning: z.array(z.string()).optional(), - actionImpact: z.record(z.unknown()).optional(), + actionImpact: z.record(z.string(), z.unknown()).optional(), }) .openapi("RepoFitRecommendation"); @@ -1296,7 +1296,7 @@ export const ContributorIntakeHealthSchema = z generatedAt: z.string(), level: z.enum(["healthy", "watch", "strained", "blocked"]), score: z.number(), - queueHealth: z.record(z.unknown()), + queueHealth: z.record(z.string(), z.unknown()), configLevel: z.enum(["excellent", "good", "needs_attention", "fragile"]), duplicateClusters: z.number(), reviewablePullRequests: z.number(), @@ -1334,10 +1334,10 @@ export const MaintainerLaneReportSchema = z export const PullRequestReviewIntelligenceSchema = PullRequestMaintainerPacketSchema.extend({ roleContext: RoleContextSchema, - outcomeContext: z.record(z.unknown()).optional(), + outcomeContext: z.record(z.string(), z.unknown()).optional(), recommendation: z.enum(["review", "needs_author", "watch", "likely_duplicate", "maintainer_lane"]), privateSummary: z.string(), - reviewability: z.record(z.unknown()).optional(), + reviewability: z.record(z.string(), z.unknown()).optional(), }).openapi("PullRequestReviewIntelligence"); export const ContributorStrategySchema = z @@ -1346,15 +1346,15 @@ export const ContributorStrategySchema = z generatedAt: z.string(), scoringModelSnapshotId: z.string(), summary: z.string(), - bestFitRepos: z.array(z.record(z.unknown())), - avoidRepos: z.array(z.record(z.unknown())), - cleanupFirst: z.array(z.record(z.unknown())), - maintainerLaneRepos: z.array(z.record(z.unknown())), - successPatterns: z.array(z.record(z.unknown())), - failurePatterns: z.array(z.record(z.unknown())), + bestFitRepos: z.array(z.record(z.string(), z.unknown())), + avoidRepos: z.array(z.record(z.string(), z.unknown())), + cleanupFirst: z.array(z.record(z.string(), z.unknown())), + maintainerLaneRepos: z.array(z.record(z.string(), z.unknown())), + successPatterns: z.array(z.record(z.string(), z.unknown())), + failurePatterns: z.array(z.record(z.string(), z.unknown())), laneWarnings: z.array(z.string()), nextActions: z.array(z.string()), - rewardRisk: z.record(z.unknown()).optional(), + rewardRisk: z.record(z.string(), z.unknown()).optional(), reasoning: z.array(z.string()).optional(), actionImpact: z.array(z.string()).optional(), }) @@ -1373,19 +1373,19 @@ export const ContributorDecisionPackSchema = z freshness: DecisionPackFreshnessSchema, rebuildEnqueued: z.boolean(), scoringModelSnapshotId: z.string(), - profile: z.record(z.unknown()), + profile: z.record(z.string(), z.unknown()), outcomeHistory: ContributorOutcomeHistorySchema, roleContexts: z.array(RoleContextSchema), opportunities: z.array(ContributorOpportunitySchema), - repoDecisions: z.array(z.record(z.unknown())), - topActions: z.array(z.record(z.unknown())), - cleanupFirst: z.array(z.record(z.unknown())), - pursueRepos: z.array(z.record(z.unknown())), - avoidRepos: z.array(z.record(z.unknown())), - maintainerLaneRepos: z.array(z.record(z.unknown())), - scoreBlockers: z.array(z.record(z.unknown())), - evidenceGraph: z.record(z.unknown()).optional(), - dataQuality: z.record(z.unknown()), + repoDecisions: z.array(z.record(z.string(), z.unknown())), + topActions: z.array(z.record(z.string(), z.unknown())), + cleanupFirst: z.array(z.record(z.string(), z.unknown())), + pursueRepos: z.array(z.record(z.string(), z.unknown())), + avoidRepos: z.array(z.record(z.string(), z.unknown())), + maintainerLaneRepos: z.array(z.record(z.string(), z.unknown())), + scoreBlockers: z.array(z.record(z.string(), z.unknown())), + evidenceGraph: z.record(z.string(), z.unknown()).optional(), + dataQuality: z.record(z.string(), z.unknown()), summary: z.string(), nextActions: z.array(z.string()), openPrMonitor: ContributorOpenPrMonitorSchema.optional(), @@ -1413,8 +1413,8 @@ export const RepoDecisionResponseSchema = z source: z.enum(["computed", "snapshot"]), freshness: DecisionPackFreshnessSchema, rebuildEnqueued: z.boolean(), - decision: z.record(z.unknown()), - dataQuality: z.record(z.unknown()), + decision: z.record(z.string(), z.unknown()), + dataQuality: z.record(z.string(), z.unknown()), }) .openapi("RepoDecisionResponse"); @@ -1426,14 +1426,14 @@ export const RepoIntelligenceSchema = z generatedAt: z.string(), repo: RepositorySchema.nullable(), lane: LaneAdviceSchema, - queueHealth: z.record(z.unknown()).nullable().optional(), - collisions: z.record(z.unknown()).optional(), - configQuality: z.record(z.unknown()).nullable().optional(), - labelAudit: z.record(z.unknown()).nullable().optional(), - maintainerLane: z.record(z.unknown()).nullable().optional(), - maintainerCutReadiness: z.record(z.unknown()).nullable().optional(), - contributorIntakeHealth: z.record(z.unknown()).nullable().optional(), - dataQuality: z.record(z.unknown()), + queueHealth: z.record(z.string(), z.unknown()).nullable().optional(), + collisions: z.record(z.string(), z.unknown()).optional(), + configQuality: z.record(z.string(), z.unknown()).nullable().optional(), + labelAudit: z.record(z.string(), z.unknown()).nullable().optional(), + maintainerLane: z.record(z.string(), z.unknown()).nullable().optional(), + maintainerCutReadiness: z.record(z.string(), z.unknown()).nullable().optional(), + contributorIntakeHealth: z.record(z.string(), z.unknown()).nullable().optional(), + dataQuality: z.record(z.string(), z.unknown()), burdenForecast: BurdenForecastSchema.optional(), burdenForecastFreshness: z .object({ @@ -1455,8 +1455,8 @@ export const RegistrationReadinessSchema = z issuePolicy: z.enum(["issue_discovery_enabled", "split_pr_and_issue_discovery_enabled", "direct_pr_requires_linked_issue", "direct_pr_no_issue_required"]), directPrReadiness: z.object({ ready: z.boolean(), reasons: z.array(z.string()) }), issueDiscoveryReadiness: z.object({ ready: z.boolean(), recommendation: z.enum(["enabled", "recommended", "not_recommended"]), reasons: z.array(z.string()) }), - labelPolicy: z.record(z.unknown()), - maintainerCutReadiness: z.record(z.unknown()), + labelPolicy: z.record(z.string(), z.unknown()), + maintainerCutReadiness: z.record(z.string(), z.unknown()), testCoverageHealth: z.object({ status: z.enum(["gate_ready", "gate_unknown"]), trustedLabelPipelineReady: z.boolean(), @@ -1466,8 +1466,8 @@ export const RegistrationReadinessSchema = z warnings: z.array(z.string()), }), queueHealth: z.object({ level: z.enum(["low", "medium", "high", "critical"]), burdenScore: z.number(), reviewablePullRequests: z.number(), summary: z.string() }), - contributorIntakeHealth: z.record(z.unknown()), - docsCompleteness: z.record(z.unknown()), + contributorIntakeHealth: z.record(z.string(), z.unknown()), + docsCompleteness: z.record(z.string(), z.unknown()), githubApp: z.object({ installed: z.boolean(), publicSurface: z.enum(["off", "comment_and_label", "comment_only", "label_only"]), @@ -1479,7 +1479,7 @@ export const RegistrationReadinessSchema = z }), blockers: z.array(z.string()), warnings: z.array(z.string()), - dataQuality: z.record(z.unknown()), + dataQuality: z.record(z.string(), z.unknown()), }) .openapi("RegistrationReadiness"); @@ -1488,12 +1488,12 @@ export const GittensorConfigRecommendationSchema = z repoFullName: z.string(), generatedAt: z.string(), privateOnly: z.boolean(), - current: z.record(z.unknown()).nullable(), - recommended: z.record(z.unknown()), + current: z.record(z.string(), z.unknown()).nullable(), + recommended: z.record(z.string(), z.unknown()), tradeoffs: z.array(z.string()), reasons: z.array(z.string()), warnings: z.array(z.string()), - dataQuality: z.record(z.unknown()), + dataQuality: z.record(z.string(), z.unknown()), }) .openapi("GittensorConfigRecommendation"); @@ -1551,9 +1551,9 @@ export const RepoRewardRiskSchema = z credibility: z.number(), reviewChurnRisk: z.enum(["low", "medium", "high"]), }), - actionImpact: z.record(z.unknown()), - currentPreview: z.record(z.unknown()), - afterCleanupPreview: z.record(z.unknown()), + actionImpact: z.record(z.string(), z.unknown()), + currentPreview: z.record(z.string(), z.unknown()), + afterCleanupPreview: z.record(z.string(), z.unknown()), actions: z.array(RewardRiskActionSchema), whyThisHelps: z.array(z.string()), nextActions: z.array(z.string()), @@ -1819,7 +1819,7 @@ export const AgentActionSchema = z publicSafeSummary: z.string(), approvalRequired: z.boolean(), safetyClass: z.enum(["private", "public_safe", "approval_required"]), - payload: z.record(z.unknown()), + payload: z.record(z.string(), z.unknown()), createdAt: z.string().nullable().optional(), }) .openapi("AgentAction"); @@ -1834,7 +1834,7 @@ export const AgentRunSchema = z status: z.enum(["queued", "running", "completed", "failed", "needs_snapshot_refresh"]), dataQualityStatus: z.enum(["complete", "degraded", "blocked", "unknown"]), errorSummary: z.string().nullable().optional(), - payload: z.record(z.unknown()), + payload: z.record(z.string(), z.unknown()), createdAt: z.string().nullable().optional(), updatedAt: z.string().nullable().optional(), }) @@ -1848,7 +1848,7 @@ export const AgentContextSnapshotSchema = z repoSignalSnapshotIds: z.array(z.string()), scoringModelId: z.string().nullable().optional(), freshnessWarnings: z.array(z.string()), - payload: z.record(z.unknown()), + payload: z.record(z.string(), z.unknown()), createdAt: z.string().nullable().optional(), }) .openapi("AgentContextSnapshot"); diff --git a/src/openapi/spec.ts b/src/openapi/spec.ts index ff0929ad38..5343b06f13 100644 --- a/src/openapi/spec.ts +++ b/src/openapi/spec.ts @@ -242,7 +242,7 @@ export function buildOpenApiSpec() { content: { "application/json": { schema: z.object({ - installations: z.array(z.record(z.unknown())), + installations: z.array(z.record(z.string(), z.unknown())), health: z.array(InstallationHealthSchema), }), }, @@ -569,7 +569,7 @@ export function buildOpenApiSpec() { method: "get", path: "/v1/app/overview", responses: { - 200: { description: "Live app overview assembled from backend data", content: { "application/json": { schema: z.record(z.unknown()) } } }, + 200: { description: "Live app overview assembled from backend data", content: { "application/json": { schema: z.record(z.string(), z.unknown()) } } }, 401: { description: "Unauthorized" }, }, }); @@ -589,7 +589,7 @@ export function buildOpenApiSpec() { method: "get", path, responses: { - 200: { description: "Live app API response", content: { "application/json": { schema: z.record(z.unknown()) } } }, + 200: { description: "Live app API response", content: { "application/json": { schema: z.record(z.string(), z.unknown()) } } }, 401: { description: "Unauthorized" }, }, }); @@ -599,8 +599,8 @@ export function buildOpenApiSpec() { method: "post", path, responses: { - 200: { description: "Live app mutation or preview response", content: { "application/json": { schema: z.record(z.unknown()) } } }, - 201: { description: "Created", content: { "application/json": { schema: z.record(z.unknown()) } } }, + 200: { description: "Live app mutation or preview response", content: { "application/json": { schema: z.record(z.string(), z.unknown()) } } }, + 201: { description: "Created", content: { "application/json": { schema: z.record(z.string(), z.unknown()) } } }, 400: { description: "Invalid request" }, 401: { description: "Unauthorized" }, }, @@ -617,7 +617,7 @@ export function buildOpenApiSpec() { }), }, responses: { - 200: { description: "Browser extension PR context overlay payload", content: { "application/json": { schema: z.record(z.unknown()) } } }, + 200: { description: "Browser extension PR context overlay payload", content: { "application/json": { schema: z.record(z.string(), z.unknown()) } } }, 400: { description: "Invalid pull context query" }, 401: { description: "Unauthorized" }, 403: { description: "Extension-scoped session required" }, diff --git a/src/services/mcp-compatibility.ts b/src/services/mcp-compatibility.ts index a885259525..abb28697d7 100644 --- a/src/services/mcp-compatibility.ts +++ b/src/services/mcp-compatibility.ts @@ -1,7 +1,7 @@ export const GITTENSORY_API_VERSION = "0.1.0"; export const GITTENSORY_MCP_PACKAGE_NAME = "@jsonbored/gittensory-mcp"; -export const MINIMUM_SUPPORTED_MCP_VERSION = "0.2.0"; -export const LATEST_RECOMMENDED_MCP_VERSION = "0.3.0"; +export const MINIMUM_SUPPORTED_MCP_VERSION = "0.4.0"; +export const LATEST_RECOMMENDED_MCP_VERSION = "0.4.0"; export type McpCompatibilityStatus = "current" | "stale" | "incompatible" | "unknown"; @@ -59,8 +59,7 @@ export function classifyMcpClientVersion(version: string | null | undefined): Mc const minimumComparison = compareMcpSemver(version, MINIMUM_SUPPORTED_MCP_VERSION); if (minimumComparison === null) return "unknown"; if (minimumComparison < 0) return "incompatible"; - const latestComparison = compareMcpSemver(version, LATEST_RECOMMENDED_MCP_VERSION)!; - return latestComparison < 0 ? "stale" : "current"; + return "current"; } function parseSemver(version: string) { diff --git a/test/integration/api.test.ts b/test/integration/api.test.ts index 18a2075676..2bbf76271c 100644 --- a/test/integration/api.test.ts +++ b/test/integration/api.test.ts @@ -67,8 +67,8 @@ describe("api routes", () => { await expect(health.json()).resolves.toMatchObject({ status: "ok", service: "gittensory-api", - minMcpVersion: "0.2.0", - latestRecommendedMcpVersion: "0.3.0", + minMcpVersion: "0.4.0", + latestRecommendedMcpVersion: "0.4.0", }); const compatibility = await app.request("/v1/mcp/compatibility", {}, env); @@ -80,9 +80,9 @@ describe("api routes", () => { apiVersion: "0.1.0", mcp: { packageName: "@jsonbored/gittensory-mcp", - minimumSupportedVersion: "0.2.0", - latestRecommendedVersion: "0.3.0", - latestPackageVersion: "0.3.0", + minimumSupportedVersion: "0.4.0", + latestRecommendedVersion: "0.4.0", + latestPackageVersion: "0.4.0", }, compatibilityWarnings: [], breakingChanges: [], @@ -1864,7 +1864,7 @@ describe("api routes", () => { headers: { ...apiHeaders(env), "x-gittensory-mcp-package": "@jsonbored/gittensory-mcp", - "x-gittensory-mcp-version": "0.3.0", + "x-gittensory-mcp-version": "0.4.0", "x-gittensory-mcp-client": "gittensory-mcp-cli", }, body: JSON.stringify({ login: "oktofeesh1", repoFullName: "entrius/allways-ui", branchName: "usage-spine" }), @@ -2047,7 +2047,7 @@ describe("api routes", () => { sessionId: "current-mcp-session", outcome: "success", clientName: "gittensory-mcp", - clientVersion: "0.3.0", + clientVersion: "0.4.0", metadata: { protocolVersion: "2025-03-26", }, @@ -2138,7 +2138,7 @@ describe("api routes", () => { byClientVersion: expect.arrayContaining([ { key: "0.1.0", count: 1 }, { key: "0.2.1", count: 1 }, - { key: "0.3.0", count: 2 }, + { key: "0.4.0", count: 2 }, ]), byProtocolVersion: expect.arrayContaining([ { key: "2024-11-05", count: 1 }, @@ -2156,8 +2156,8 @@ describe("api routes", () => { const mcpCompatibilityBody = await mcpCompatibility.json(); expect(mcpCompatibilityBody).toMatchObject({ adoption: expect.objectContaining({ - minimumSupportedVersion: "0.2.0", - latestRecommendedVersion: "0.3.0", + minimumSupportedVersion: "0.4.0", + latestRecommendedVersion: "0.4.0", staleEvents: 1, incompatibleEvents: 1, totalEvents: 4, @@ -3513,19 +3513,19 @@ describe("api routes", () => { const mcpUsageEvents = await listProductUsageEvents(env, { limit: 100 }); expect(mcpUsageEvents).toEqual( expect.arrayContaining([ - expect.objectContaining({ surface: "mcp", eventName: "mcp_request", outcome: "success", clientName: "gittensory-mcp-cli", clientVersion: "0.3.0" }), + expect.objectContaining({ surface: "mcp", eventName: "mcp_request", outcome: "success", clientName: "gittensory-mcp-cli", clientVersion: "0.4.0" }), expect.objectContaining({ surface: "mcp", eventName: "mcp_tool_called", outcome: "success", clientName: "gittensory-mcp-cli", - clientVersion: "0.3.0", + clientVersion: "0.4.0", metadata: expect.objectContaining({ toolName: "gittensory_get_bounty_advisory", protocolVersion: "2025-03-26", compatibilityStatus: "current", - minimumSupportedVersion: "0.2.0", - latestRecommendedVersion: "0.3.0", + minimumSupportedVersion: "0.4.0", + latestRecommendedVersion: "0.4.0", }), }), ]), @@ -4074,7 +4074,7 @@ function mcpHeaders(env: Env, sessionId?: string): Record { "content-type": "application/json", "mcp-protocol-version": "2025-03-26", "x-gittensory-mcp-package": "@jsonbored/gittensory-mcp", - "x-gittensory-mcp-version": "0.3.0", + "x-gittensory-mcp-version": "0.4.0", "x-gittensory-mcp-client": "gittensory-mcp-cli", ...(sessionId ? { "mcp-session-id": sessionId } : {}), }; diff --git a/test/unit/mcp-cli.test.ts b/test/unit/mcp-cli.test.ts index 65aaf23fed..a68a7d718d 100644 --- a/test/unit/mcp-cli.test.ts +++ b/test/unit/mcp-cli.test.ts @@ -96,7 +96,7 @@ describe("gittensory-mcp CLI", () => { it("reports a current install without upgrade guidance", async () => { tempDir = mkdtempSync(join(tmpdir(), "gittensory-cli-")); - const url = await startFixtureServer({ latestVersion: "0.3.0" }); + const url = await startFixtureServer({ latestVersion: "0.4.0" }); const payload = JSON.parse( await runAsync(["status", "--json"], { GITTENSORY_API_URL: url, @@ -115,16 +115,16 @@ describe("gittensory-mcp CLI", () => { expect(payload.apiCompatibility).toMatchObject({ status: "compatible", source: "compatibility_endpoint", - minVersion: "0.2.0", - latestRecommendedVersion: "0.3.0", + minVersion: "0.4.0", + latestRecommendedVersion: "0.4.0", apiVersion: "0.1.0", }); }); it("orders prerelease npm versions correctly (release outranks prerelease of the same core)", async () => { tempDir = mkdtempSync(join(tmpdir(), "gittensory-cli-")); - // Local 0.3.0 (release) vs latest 0.3.0-rc.1 (prerelease) -> local is ahead, not stale. - const aheadUrl = await startFixtureServer({ latestVersion: "0.3.0-rc.1" }); + // Local 0.4.0 (release) vs latest 0.4.0-rc.1 (prerelease) -> local is ahead, not stale. + const aheadUrl = await startFixtureServer({ latestVersion: "0.4.0-rc.1" }); const ahead = JSON.parse( await runAsync(["status", "--json"], { GITTENSORY_API_URL: aheadUrl, @@ -136,8 +136,8 @@ describe("gittensory-mcp CLI", () => { expect(ahead.package).toMatchObject({ state: "ahead", updateAvailable: false }); await new Promise((resolve) => server?.close(() => resolve())); - // Local 0.3.0 vs a higher-core prerelease 0.4.0-rc.1 -> stale. - const staleUrl = await startFixtureServer({ latestVersion: "0.4.0-rc.1" }); + // Local 0.4.0 vs a higher-core prerelease 0.5.0-rc.1 -> stale. + const staleUrl = await startFixtureServer({ latestVersion: "0.5.0-rc.1" }); const stale = JSON.parse( await runAsync(["status", "--json"], { GITTENSORY_API_URL: staleUrl, @@ -218,7 +218,7 @@ describe("gittensory-mcp CLI", () => { it("falls back to legacy health compatibility when the endpoint is unavailable", async () => { tempDir = mkdtempSync(join(tmpdir(), "gittensory-cli-")); - const url = await startFixtureServer({ compatibilityStatus: 503, minMcpVersion: "0.2.0" }); + const url = await startFixtureServer({ compatibilityStatus: 503, minMcpVersion: "0.4.0" }); const payload = JSON.parse( await runAsync(["status", "--json"], { GITTENSORY_API_URL: url, @@ -227,12 +227,12 @@ describe("gittensory-mcp CLI", () => { GITTENSORY_SKIP_NPM_VERSION_CHECK: "true", }), ) as { apiCompatibility: { status: string; source: string; minVersion: string } }; - expect(payload.apiCompatibility).toMatchObject({ status: "compatible", source: "health", minVersion: "0.2.0" }); + expect(payload.apiCompatibility).toMatchObject({ status: "compatible", source: "health", minVersion: "0.4.0" }); }); it("uses API recommended package metadata when the npm registry is unavailable", async () => { tempDir = mkdtempSync(join(tmpdir(), "gittensory-cli-")); - const url = await startFixtureServer({ npmStatus: 500, latestRecommendedMcpVersion: "0.4.0" }); + const url = await startFixtureServer({ npmStatus: 500, latestRecommendedMcpVersion: "0.5.0" }); const payload = JSON.parse( await runAsync(["status", "--json"], { GITTENSORY_API_URL: url, @@ -244,7 +244,7 @@ describe("gittensory-mcp CLI", () => { expect(payload.package).toMatchObject({ state: "stale", latestStatus: "api", - latestVersion: "0.4.0", + latestVersion: "0.5.0", upgradeCommand: "npm install -g @jsonbored/gittensory-mcp@latest", }); }); @@ -314,12 +314,12 @@ describe("gittensory-mcp CLI", () => { }), ) as { package: { name: string; version: string; latestStatus: string }; api: { status: string }; auth: { login: string } }; - expect(status.package).toMatchObject({ name: "@jsonbored/gittensory-mcp", version: "0.3.0", latestStatus: "skipped" }); + expect(status.package).toMatchObject({ name: "@jsonbored/gittensory-mcp", version: "0.4.0", latestStatus: "skipped" }); expect(status.api.status).toBe("ok"); expect(status.auth.login).toBe("JSONbored"); const changelog = JSON.parse(run(["changelog", "--json"])) as { package: { version: string }; changelog: string }; - expect(changelog.package.version).toBe("0.3.0"); + expect(changelog.package.version).toBe("0.4.0"); expect(changelog.changelog).toContain("# Changelog"); }); @@ -337,7 +337,7 @@ describe("gittensory-mcp CLI", () => { const sessionRequest = requests.find((request) => request.url === "/v1/auth/session"); expect(sessionRequest?.headers["x-gittensory-mcp-package"]).toBe("@jsonbored/gittensory-mcp"); - expect(sessionRequest?.headers["x-gittensory-mcp-version"]).toBe("0.3.0"); + expect(sessionRequest?.headers["x-gittensory-mcp-version"]).toBe("0.4.0"); expect(sessionRequest?.headers["x-gittensory-mcp-client"]).toBe("gittensory-mcp-cli"); const telemetryHeaders = JSON.stringify({ package: sessionRequest?.headers["x-gittensory-mcp-package"], @@ -718,7 +718,7 @@ async function startFixtureServer( response.end(JSON.stringify({ error: "registry_error" })); return; } - response.end(JSON.stringify({ version: options.latestVersion ?? "0.3.0" })); + response.end(JSON.stringify({ version: options.latestVersion ?? "0.4.0" })); return; } if (request.url === "/v1/mcp/compatibility") { @@ -727,8 +727,8 @@ async function startFixtureServer( response.end(JSON.stringify({ error: "compatibility_unavailable" })); return; } - const minimumSupportedVersion = options.minMcpVersion ?? "0.2.0"; - const latestRecommendedVersion = options.latestRecommendedMcpVersion ?? options.latestVersion ?? "0.3.0"; + const minimumSupportedVersion = options.minMcpVersion ?? "0.4.0"; + const latestRecommendedVersion = options.latestRecommendedMcpVersion ?? options.latestVersion ?? "0.4.0"; response.end( JSON.stringify({ status: "ok", diff --git a/test/unit/mcp-compatibility.test.ts b/test/unit/mcp-compatibility.test.ts index 661b94e77d..f123bcfc71 100644 --- a/test/unit/mcp-compatibility.test.ts +++ b/test/unit/mcp-compatibility.test.ts @@ -5,8 +5,9 @@ import { classifyMcpClientVersion, compareMcpSemver } from "../../src/services/m describe("MCP compatibility telemetry", () => { it("classifies local MCP package versions against the advertised support window", () => { expect(classifyMcpClientVersion("0.1.9")).toBe("incompatible"); - expect(classifyMcpClientVersion("0.2.1")).toBe("stale"); - expect(classifyMcpClientVersion("0.3.0")).toBe("current"); + expect(classifyMcpClientVersion("0.2.1")).toBe("incompatible"); + expect(classifyMcpClientVersion("0.3.0")).toBe("incompatible"); + expect(classifyMcpClientVersion("0.4.0")).toBe("current"); expect(classifyMcpClientVersion("not-a-version")).toBe("unknown"); expect(classifyMcpClientVersion(undefined)).toBe("unknown"); }); @@ -29,7 +30,7 @@ describe("MCP compatibility telemetry", () => { packageName: "@jsonbored/gittensory-mcp", packageVersion: "0.2.1", protocolVersion: "2025-03-26", - compatibilityStatus: "stale", + compatibilityStatus: "incompatible", }, }); }); @@ -38,14 +39,14 @@ describe("MCP compatibility telemetry", () => { const telemetry = buildMcpClientTelemetry( new Headers({ "x-gittensory-mcp-package": "@example/custom-mcp", - "x-gittensory-mcp-version": "0.3.0", + "x-gittensory-mcp-version": "0.4.0", }), { requireGittensoryHeader: true }, ); expect(telemetry).toMatchObject({ clientName: "custom-mcp", - clientVersion: "0.3.0", + clientVersion: "0.4.0", metadata: { packageName: "@example/custom-mcp", compatibilityStatus: "current", @@ -57,11 +58,11 @@ describe("MCP compatibility telemetry", () => { const canonical = buildMcpClientTelemetry( new Headers({ "x-gittensory-mcp-package": "@jsonbored/gittensory-mcp", - "x-gittensory-mcp-version": "0.3.0", + "x-gittensory-mcp-version": "0.4.0", }), { requireGittensoryHeader: true }, ); - expect(canonical).toMatchObject({ clientName: "gittensory-mcp", clientVersion: "0.3.0" }); + expect(canonical).toMatchObject({ clientName: "gittensory-mcp", clientVersion: "0.4.0" }); const defaulted = buildMcpClientTelemetry(new Headers(), { defaultClientName: "mcp" }); expect(defaulted).toMatchObject({ diff --git a/test/unit/mcp-release.test.ts b/test/unit/mcp-release.test.ts new file mode 100644 index 0000000000..7ac5b99f6a --- /dev/null +++ b/test/unit/mcp-release.test.ts @@ -0,0 +1,84 @@ +import { describe, expect, it } from "vitest"; +import { buildMcpReleaseIssue, buildMcpReleaseReport, renderMcpChangelog, selectMcpReleaseCommits } from "../../scripts/mcp-release-core.mjs"; + +type TestCommit = { + sha: string; + subject: string; + files: string[]; +}; + +function commit(subject: string, files: string[], sha = subject): TestCommit { + return { sha: sha.padEnd(40, "0").slice(0, 40), subject, files }; +} + +describe("MCP release changelog detection", () => { + it("includes package-only MCP package changes", () => { + const commits = selectMcpReleaseCommits([commit("docs(ci): add MCP package usage note (#1)", ["packages/gittensory-mcp/README.md"])]); + + expect(commits.map((entry) => entry.subject)).toEqual(["docs(ci): add MCP package usage note (#1)"]); + }); + + it("includes MCP server tool changes", () => { + const commits = selectMcpReleaseCommits([commit("feat(mcp): add branch eligibility tool (#2)", ["src/mcp/server.ts"])]); + + expect(commits.map((entry) => entry.subject)).toEqual(["feat(mcp): add branch eligibility tool (#2)"]); + }); + + it("includes compatibility metadata changes", () => { + const commits = selectMcpReleaseCommits([commit("feat(analytics): track MCP compatibility adoption (#3)", ["src/services/mcp-compatibility.ts"])]); + + expect(commits.map((entry) => entry.subject)).toEqual(["feat(analytics): track MCP compatibility adoption (#3)"]); + }); + + it("excludes UI-only changes", () => { + const commits = selectMcpReleaseCommits([ + commit("feat(ui): add release dashboard card (#4)", ["apps/gittensory-ui/src/routes/app.operator.tsx", "apps/gittensory-ui/public/openapi.json"]), + ]); + + expect(commits).toEqual([]); + }); + + it("excludes test-only support changes even when they touch local signal helpers", () => { + const commits = selectMcpReleaseCommits([commit("test(coverage): raise website closeout gates (#5)", ["src/signals/local-branch.ts", "test/unit/local-branch.test.ts"])]); + + expect(commits).toEqual([]); + }); + + it("preserves previous release sections byte-for-byte", () => { + const priorSections = `## mcp-v0.3.0 - 2026-05-31 + +### Features +- Existing feature text + +## mcp-v0.2.0 - 2026-05-29 + +### Fixes +- Existing fix text +`; + const changelog = renderMcpChangelog({ + existingChangelog: `# Changelog\n\n${priorSections}`, + targetVersion: "0.4.0", + generatedAt: "2026-06-02", + commits: [commit("feat(mcp): add local workspace intelligence v2 (#70)", ["packages/gittensory-mcp/bin/gittensory-mcp.js"])], + }); + + expect(changelog).toContain("## mcp-v0.4.0 - 2026-06-02"); + expect(changelog.slice(changelog.indexOf("## mcp-v0.3.0"))).toBe(priorSections); + }); + + it("builds a release-due issue with the version and checklist", () => { + const report = buildMcpReleaseReport({ + latestTag: { tag: "mcp-v0.3.0", version: "0.3.0" }, + packageVersion: "0.4.0", + publishedVersion: "0.3.0", + commits: [commit("feat(mcp): add local workspace intelligence v2 (#70)", ["src/mcp/server.ts"])], + }); + const issue = buildMcpReleaseIssue(report); + + expect(report).toMatchObject({ due: true, proposedVersion: "0.4.0", releaseType: "minor" }); + expect(issue.title).toBe("MCP release due: 0.4.0"); + expect(issue.body).toContain(""); + expect(issue.body).toContain("- [ ] Run `npm run test:release:mcp`"); + expect(issue.body).toContain("- [ ] Tag `mcp-v0.4.0`"); + }); +}); diff --git a/test/unit/mcp-server-telemetry.test.ts b/test/unit/mcp-server-telemetry.test.ts index cfeb38ec52..ba7f963553 100644 --- a/test/unit/mcp-server-telemetry.test.ts +++ b/test/unit/mcp-server-telemetry.test.ts @@ -24,7 +24,7 @@ describe("MCP server telemetry", () => { authorization: `Bearer ${env.GITTENSORY_MCP_TOKEN}`, "content-type": "application/json", "x-gittensory-mcp-package": "@jsonbored/gittensory-mcp", - "x-gittensory-mcp-version": "0.3.0", + "x-gittensory-mcp-version": "0.4.0", "x-gittensory-mcp-client": "gittensory-mcp-cli", }, body: JSON.stringify({ @@ -54,7 +54,7 @@ describe("MCP server telemetry", () => { eventName: "mcp_tool_called", outcome: "error", clientName: "gittensory-mcp-cli", - clientVersion: "0.3.0", + clientVersion: "0.4.0", metadata: expect.objectContaining({ toolName: "gittensory_local_status", compatibilityStatus: "current", diff --git a/test/unit/product-usage-mcp-adoption.test.ts b/test/unit/product-usage-mcp-adoption.test.ts index fc9da4955e..c5ada65e56 100644 --- a/test/unit/product-usage-mcp-adoption.test.ts +++ b/test/unit/product-usage-mcp-adoption.test.ts @@ -37,7 +37,7 @@ describe("MCP compatibility adoption summaries", () => { { key: "unknown", count: 1 }, ]), byCompatibilityStatus: expect.arrayContaining([ - { status: "stale", count: 1 }, + { status: "incompatible", count: 1 }, { status: "unknown", count: 1 }, ]), }); From c4e04fddebb3cd2a12e3884da05eb6604a3cbc8b Mon Sep 17 00:00:00 2001 From: JSONbored <49853598+JSONbored@users.noreply.github.com> Date: Tue, 2 Jun 2026 01:13:33 -0700 Subject: [PATCH 2/3] fix(release): support current agents package --- package-lock.json | 336 ++++++++++++++++----------- package.json | 2 +- packages/gittensory-mcp/CHANGELOG.md | 2 +- src/mcp/server.ts | 3 +- test/stubs/cloudflare-workers.ts | 3 + 5 files changed, 200 insertions(+), 146 deletions(-) diff --git a/package-lock.json b/package-lock.json index 44384ddc7b..6cacf8cfe7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "@asteasolutions/zod-to-openapi": "^8.5.0", "@modelcontextprotocol/sdk": "1.29.0", "@octokit/core": "^7.0.6", - "agents": "^0.7.9", + "agents": "^0.13.3", "drizzle-orm": "^0.45.0", "hono": "^4.12.23", "zod": "^4.4.3" @@ -755,23 +755,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@apidevtools/json-schema-ref-parser": { - "version": "11.9.3", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.9.3.tgz", - "integrity": "sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ==", - "license": "MIT", - "dependencies": { - "@jsdevtools/ono": "^7.1.3", - "@types/json-schema": "^7.0.15", - "js-yaml": "^4.1.0" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/philsturgeon" - } - }, "node_modules/@asteasolutions/zod-to-openapi": { "version": "8.5.0", "resolved": "https://registry.npmjs.org/@asteasolutions/zod-to-openapi/-/zod-to-openapi-8.5.0.tgz", @@ -878,6 +861,18 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", + "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-compilation-targets": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", @@ -903,6 +898,36 @@ "semver": "bin/semver.js" } }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz", + "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/traverse": "^7.29.7", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/helper-globals": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", @@ -912,6 +937,19 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz", + "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-module-imports": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", @@ -942,6 +980,18 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz", + "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-plugin-utils": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", @@ -951,6 +1001,36 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", + "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz", + "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-string-parser": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", @@ -1006,6 +1086,38 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/plugin-proposal-decorators": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.29.7.tgz", + "integrity": "sha512-EtU0Hi3GvrTqD56xKmZvV/uCXK2ZbwVNPNLAquVItcAZpUhkXwWlo3Fmj0c2LxgSf2I8IDULeAepwNP1OefLXg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-syntax-decorators": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-decorators": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.29.7.tgz", + "integrity": "sha512-9MTTLbF39X6sqM92JPEsoI7++26hjZvzkxKZy64aMhWLH2mPkJ/Q3AV4QLmls3R14FpSpkOwQQfUh962JGQxxg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-jsx": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", @@ -2720,12 +2832,6 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "node_modules/@jsdevtools/ono": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", - "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", - "license": "MIT" - }, "node_modules/@jsonbored/gittensory-mcp": { "resolved": "packages/gittensory-mcp", "link": true @@ -4971,6 +5077,36 @@ "node": "^20.19.0 || >=22.12.0" } }, + "node_modules/@rolldown/plugin-babel": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/plugin-babel/-/plugin-babel-0.2.3.tgz", + "integrity": "sha512-+zEk16yGlz1F9STiRr6uG9hmIXb6nprjLczV/htGptYuLoCuxb+itZ03RKCEeOhBpDDd1NU7qF6x1VLMUp62bw==", + "license": "MIT", + "dependencies": { + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=22.12.0 || ^24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.29.0 || ^8.0.0-rc.1", + "@babel/plugin-transform-runtime": "^7.29.0 || ^8.0.0-rc.1", + "@babel/runtime": "^7.27.0 || ^8.0.0-rc.1", + "rolldown": "^1.0.0-rc.5", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@babel/plugin-transform-runtime": { + "optional": true + }, + "@babel/runtime": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, "node_modules/@rolldown/pluginutils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", @@ -6342,12 +6478,7 @@ "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "license": "MIT" - }, - "node_modules/@types/lodash": { - "version": "4.17.24", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.24.tgz", - "integrity": "sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==", + "dev": true, "license": "MIT" }, "node_modules/@types/node": { @@ -6901,111 +7032,61 @@ } }, "node_modules/agents": { - "version": "0.7.9", - "resolved": "https://registry.npmjs.org/agents/-/agents-0.7.9.tgz", - "integrity": "sha512-NNzFkDLrsZQC9oJlDOcgktQxeNWUfZuftimhGmcin+7kULsmdks1AUPXTXQ4mHJZBilKpL0pQzCq5aQMQCYEKA==", + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/agents/-/agents-0.13.3.tgz", + "integrity": "sha512-sanbvHT9rdMuxq9rsBukqqVr88W7s0t6WXFuRdA0uxqikTMCb7Oki9aGWcgjoUN0qvaV/qlJ9RLTQAVSw/eLNg==", "license": "MIT", "dependencies": { + "@babel/plugin-proposal-decorators": "^7.29.0", "@cfworker/json-schema": "^4.1.1", - "@modelcontextprotocol/sdk": "1.26.0", + "@modelcontextprotocol/sdk": "1.29.0", + "@rolldown/plugin-babel": "^0.2.3", "cron-schedule": "^6.0.0", - "json-schema": "^0.4.0", - "json-schema-to-typescript": "^15.0.4", "mimetext": "^3.0.28", - "nanoid": "^5.1.6", - "partyserver": "^0.3.3", - "partysocket": "1.1.16", - "picomatch": "^4.0.3", + "nanoid": "^5.1.11", + "partyserver": "^0.5.6", + "partysocket": "1.1.19", "yargs": "^18.0.0" }, "bin": { "agents": "dist/cli/index.js" }, "peerDependencies": { - "@ai-sdk/openai": "^3.0.0", - "@ai-sdk/react": "^3.0.0", - "@cloudflare/ai-chat": "^0.1.9", - "@cloudflare/codemode": "^0.2.2", + "@cloudflare/ai-chat": ">=0.6.1 <1.0.0", + "@cloudflare/codemode": ">=0.3.4 <1.0.0", + "@tanstack/ai": ">=0.10.2 <1.0.0", "@x402/core": "^2.0.0", "@x402/evm": "^2.0.0", "ai": "^6.0.0", + "chat": "^4.29.0", "react": "^19.0.0", - "viem": ">=2.0.0", - "zod": "^3.25.0 || ^4.0.0" + "vite": ">=6.0.0 <9.0.0", + "zod": "^4.0.0" }, "peerDependenciesMeta": { - "@ai-sdk/openai": { - "optional": true - }, - "@ai-sdk/react": { - "optional": true - }, "@cloudflare/ai-chat": { "optional": true }, "@cloudflare/codemode": { "optional": true }, + "@tanstack/ai": { + "optional": true + }, "@x402/core": { "optional": true }, "@x402/evm": { "optional": true }, - "viem": { - "optional": true - } - } - }, - "node_modules/agents/node_modules/@modelcontextprotocol/sdk": { - "version": "1.26.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.26.0.tgz", - "integrity": "sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==", - "license": "MIT", - "dependencies": { - "@hono/node-server": "^1.19.9", - "ajv": "^8.17.1", - "ajv-formats": "^3.0.1", - "content-type": "^1.0.5", - "cors": "^2.8.5", - "cross-spawn": "^7.0.5", - "eventsource": "^3.0.2", - "eventsource-parser": "^3.0.0", - "express": "^5.2.1", - "express-rate-limit": "^8.2.1", - "hono": "^4.11.4", - "jose": "^6.1.3", - "json-schema-typed": "^8.0.2", - "pkce-challenge": "^5.0.0", - "raw-body": "^3.0.0", - "zod": "^3.25 || ^4.0", - "zod-to-json-schema": "^3.25.1" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@cfworker/json-schema": "^4.1.1", - "zod": "^3.25 || ^4.0" - }, - "peerDependenciesMeta": { - "@cfworker/json-schema": { + "chat": { "optional": true }, - "zod": { - "optional": false + "vite": { + "optional": true } } }, - "node_modules/agents/node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/agents/node_modules/nanoid": { "version": "5.1.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.11.tgz", @@ -9703,6 +9784,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -9712,6 +9794,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -9912,30 +9995,8 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "license": "(AFL-2.1 OR BSD-3-Clause)" - }, - "node_modules/json-schema-to-typescript": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-15.0.4.tgz", - "integrity": "sha512-Su9oK8DR4xCmDsLlyvadkXzX6+GGXJpbhwoLtOGArAG61dvbW4YQmSEno2y66ahpIdmLMg6YUf/QHLgiwvkrHQ==", - "license": "MIT", - "dependencies": { - "@apidevtools/json-schema-ref-parser": "^11.5.5", - "@types/json-schema": "^7.0.15", - "@types/lodash": "^4.17.7", - "is-glob": "^4.0.3", - "js-yaml": "^4.1.0", - "lodash": "^4.17.21", - "minimist": "^1.2.8", - "prettier": "^3.2.5", - "tinyglobby": "^0.2.9" - }, - "bin": { - "json2ts": "dist/src/cli.js" - }, - "engines": { - "node": ">=16.0.0" - } + "license": "(AFL-2.1 OR BSD-3-Clause)", + "peer": true }, "node_modules/json-schema-traverse": { "version": "1.0.0", @@ -10696,15 +10757,6 @@ "node": "*" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/minipass": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", @@ -11285,15 +11337,15 @@ } }, "node_modules/partyserver": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/partyserver/-/partyserver-0.3.3.tgz", - "integrity": "sha512-jSGWNZ5lJj9czq+97y9N02HyZZtQH8wmgJRkTQahfGnzgL5+R12dMX3E+p7BscB2cVj6LZLv1uHpKL057rjJmw==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/partyserver/-/partyserver-0.5.6.tgz", + "integrity": "sha512-/LKCqlq9nWzNXA8UXZFO/Xz15QDCjJnGAgRQVLnXJO9bA0HKt5J8VM8wLnGc814WatzuQgeG17tqzI//y5WFGA==", "license": "ISC", "dependencies": { - "nanoid": "^5.1.6" + "nanoid": "^5.1.9" }, "peerDependencies": { - "@cloudflare/workers-types": "^4.20240729.0" + "@cloudflare/workers-types": "^4.20260424.1" } }, "node_modules/partyserver/node_modules/nanoid": { @@ -11315,9 +11367,9 @@ } }, "node_modules/partysocket": { - "version": "1.1.16", - "resolved": "https://registry.npmjs.org/partysocket/-/partysocket-1.1.16.tgz", - "integrity": "sha512-d7xFv+ZC7x0p/DAHWJ5FhxQhimIx+ucyZY+kxL0cKddLBmK9c4p2tEA/L+dOOrWm6EYrRwrBjKQV0uSzOY9x1w==", + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/partysocket/-/partysocket-1.1.19.tgz", + "integrity": "sha512-hPwsXSdUc8PKNCinET6TD3JQOxzQ2JaP0bUZQXBVl6UM8UuLn1odgf1LcJXHy4UHSQwWL/RU3AnyhEsGM+W+sg==", "license": "MIT", "dependencies": { "event-target-polyfill": "^0.0.4" diff --git a/package.json b/package.json index 15bd02a435..554b0f9464 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "@asteasolutions/zod-to-openapi": "^8.5.0", "@modelcontextprotocol/sdk": "1.29.0", "@octokit/core": "^7.0.6", - "agents": "^0.7.9", + "agents": "^0.13.3", "drizzle-orm": "^0.45.0", "hono": "^4.12.23", "zod": "^4.4.3" diff --git a/packages/gittensory-mcp/CHANGELOG.md b/packages/gittensory-mcp/CHANGELOG.md index 1f3ba7854a..315b4a146a 100644 --- a/packages/gittensory-mcp/CHANGELOG.md +++ b/packages/gittensory-mcp/CHANGELOG.md @@ -30,7 +30,7 @@ - Add coverage buffer and contributor test-quality guidance (#55) ### Dependencies -- Update MCP release dependency stack (@modelcontextprotocol/sdk 1.26.0 -> 1.29.0, zod ^3.25.76 -> ^4.4.3, @asteasolutions/zod-to-openapi ^7.3.4 -> ^8.5.0) +- Update MCP release dependency stack (@modelcontextprotocol/sdk 1.26.0 -> 1.29.0, zod ^3.25.76 -> ^4.4.3, @asteasolutions/zod-to-openapi ^7.3.4 -> ^8.5.0, agents ^0.7.9 -> ^0.13.3) ## mcp-v0.3.0 - 2026-05-31 diff --git a/src/mcp/server.ts b/src/mcp/server.ts index ead4cc0e87..7829e7034c 100644 --- a/src/mcp/server.ts +++ b/src/mcp/server.ts @@ -66,7 +66,6 @@ import { buildRepoDataQuality } from "../signals/data-quality"; import { loadUpstreamStatus } from "../upstream/ruleset"; type AppContext = Context<{ Bindings: Env }>; -type AgentsMcpServer = Parameters[0]; type ToolPayload = { summary: string; data: Record; @@ -263,7 +262,7 @@ export async function handleMcpRequest(c: AppContext): Promise { const startedAt = Date.now(); const server = new GittensoryMcp(c.env, identity).createServer(); try { - const response = await createMcpHandler(server as unknown as AgentsMcpServer, { route: "/mcp", enableJsonResponse: true })(c.req.raw, c.env, getExecutionContext(c)); + const response = await createMcpHandler(server, { route: "/mcp", enableJsonResponse: true })(c.req.raw, c.env, getExecutionContext(c)); await recordProductUsageEvent(c.env, { surface: "mcp", eventName: typeof usageMetadata.toolName === "string" ? "mcp_tool_called" : "mcp_request", diff --git a/test/stubs/cloudflare-workers.ts b/test/stubs/cloudflare-workers.ts index dc06767061..5eaf552b32 100644 --- a/test/stubs/cloudflare-workers.ts +++ b/test/stubs/cloudflare-workers.ts @@ -18,4 +18,7 @@ export class WorkflowEntrypoint { } } +export class RpcTarget {} + +export const exports = {}; export const env = {}; From c8ee454961b54a54655de0adad763fc783401aec Mon Sep 17 00:00:00 2001 From: JSONbored <49853598+JSONbored@users.noreply.github.com> Date: Tue, 2 Jun 2026 01:16:38 -0700 Subject: [PATCH 3/3] fix(ci): harden MCP release reminder matching --- scripts/check-mcp-release-due.d.mts | 10 ++++++++++ scripts/check-mcp-release-due.mjs | 13 ++++++++++++- test/unit/mcp-release.test.ts | 19 +++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 scripts/check-mcp-release-due.d.mts diff --git a/scripts/check-mcp-release-due.d.mts b/scripts/check-mcp-release-due.d.mts new file mode 100644 index 0000000000..7030bb0dcd --- /dev/null +++ b/scripts/check-mcp-release-due.d.mts @@ -0,0 +1,10 @@ +export type GitHubIssueCandidate = { + pull_request?: unknown; + title?: unknown; + body?: unknown; + user?: { + login?: unknown; + } | null; +}; + +export function isReleaseWatchIssue(issue: GitHubIssueCandidate): boolean; diff --git a/scripts/check-mcp-release-due.mjs b/scripts/check-mcp-release-due.mjs index 9e0c22a3de..213d44c6de 100644 --- a/scripts/check-mcp-release-due.mjs +++ b/scripts/check-mcp-release-due.mjs @@ -116,13 +116,24 @@ async function findExistingIssue({ owner, repo, token }) { path: `/repos/${owner}/${repo}/issues?state=open&per_page=100&page=${page}`, }); if (!Array.isArray(issues) || issues.length === 0) return null; - const match = issues.find((issue) => !issue.pull_request && typeof issue.body === "string" && issue.body.includes(MCP_RELEASE_DUE_MARKER)); + const match = issues.find(isReleaseWatchIssue); if (match) return match; page += 1; } return null; } +export function isReleaseWatchIssue(issue) { + return ( + !issue.pull_request && + issue.user?.login === "github-actions[bot]" && + typeof issue.title === "string" && + issue.title.startsWith("MCP release due: ") && + typeof issue.body === "string" && + issue.body.includes(MCP_RELEASE_DUE_MARKER) + ); +} + async function githubRequest({ token, method, path, body }) { const response = await fetch(`https://api.github.com${path}`, { method, diff --git a/test/unit/mcp-release.test.ts b/test/unit/mcp-release.test.ts index 7ac5b99f6a..21f54f2c25 100644 --- a/test/unit/mcp-release.test.ts +++ b/test/unit/mcp-release.test.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from "vitest"; +import { isReleaseWatchIssue } from "../../scripts/check-mcp-release-due.mjs"; import { buildMcpReleaseIssue, buildMcpReleaseReport, renderMcpChangelog, selectMcpReleaseCommits } from "../../scripts/mcp-release-core.mjs"; type TestCommit = { @@ -81,4 +82,22 @@ describe("MCP release changelog detection", () => { expect(issue.body).toContain("- [ ] Run `npm run test:release:mcp`"); expect(issue.body).toContain("- [ ] Tag `mcp-v0.4.0`"); }); + + it("only updates the bot-owned release reminder issue", () => { + expect( + isReleaseWatchIssue({ + title: "MCP release due: 0.4.0", + body: "", + user: { login: "github-actions[bot]" }, + }), + ).toBe(true); + + expect( + isReleaseWatchIssue({ + title: "MCP release due: 0.4.0", + body: "", + user: { login: "public-contributor" }, + }), + ).toBe(false); + }); });