From 50f3e846019a70aa5a6de296c612090d67660eae Mon Sep 17 00:00:00 2001 From: 0xVox Date: Wed, 13 May 2026 00:01:24 -0400 Subject: [PATCH 01/12] ci(templates): add PR + security tracker issue templates for Linear/Slack mirror sync MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds two issue templates under .github/ISSUE_TEMPLATE/ for long-lived, auditable mirrors of in-flight upstream PRs: - pr_tracker.yml: general PR mirror (scope, evidence, decision log, closure) - security_tracker.yml: high-priority variant (CWE, severity, reachability, verification, disclosure hygiene) Both carry a `pr-mirror` label so the Linear evermind-dash project and the Slack #bots channel can subscribe by label. Bilingual EN + 中文. --- .github/ISSUE_TEMPLATE/pr_tracker.yml | 109 ++++++++++++++++++ .github/ISSUE_TEMPLATE/security_tracker.yml | 116 ++++++++++++++++++++ 2 files changed, 225 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/pr_tracker.yml create mode 100644 .github/ISSUE_TEMPLATE/security_tracker.yml diff --git a/.github/ISSUE_TEMPLATE/pr_tracker.yml b/.github/ISSUE_TEMPLATE/pr_tracker.yml new file mode 100644 index 00000000..1dbe050a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/pr_tracker.yml @@ -0,0 +1,109 @@ +name: PR tracker (mirror) +description: Mirror an in-flight pull request as a tracking issue for Linear and Slack sync / 镜像一个进行中的 PR 作为追踪 issue +title: "[PR Track] #: " +labels: ["pr-mirror", "tracking"] +body: + - type: markdown + attributes: + value: | + Use this when you want a long-lived, auditable record of an upstream PR. + Linear and Slack subscribe to issues with the `pr-mirror` label. + 镜像一个 PR 用于 Linear / Slack 长期可审计追踪。带 `pr-mirror` 标签的 issue 会被订阅。 + - type: input + id: pr_number + attributes: + label: PR number + placeholder: "e.g. 196" + validations: + required: true + - type: input + id: pr_url + attributes: + label: PR URL + placeholder: https://github.com/EverMind-AI/EverOS/pull/ + validations: + required: true + - type: input + id: author + attributes: + label: Author handle + placeholder: "@github-login" + validations: + required: true + - type: dropdown + id: area + attributes: + label: Area + options: + - methods/EverCore + - methods/HyperMem + - benchmarks/EverMemBench + - benchmarks/EvoAgentBench + - use-cases + - documentation + - CI / build / release + - other + validations: + required: true + - type: dropdown + id: lane + attributes: + label: Review lane + description: How this PR should be triaged. / 该 PR 的优先级处理通道。 + options: + - hotfix (block release until merged) + - normal (standard review) + - docs-only (light review) + - exploratory (no merge intent) + validations: + required: true + - type: textarea + id: scope + attributes: + label: Scope summary + description: One paragraph. What does the PR change, and what is intentionally left out? + placeholder: | + Changes: + - ... + Out of scope: + - ... + validations: + required: true + - type: textarea + id: evidence + attributes: + label: Evidence snapshot + description: | + Required before this mirror can be closed. Paste the CI summary, test command output, + or the link to the run. "No mirror closes without evidence." + 关闭镜像 issue 前必填。粘贴 CI 摘要、测试命令输出或 run 链接。 + render: shell + validations: + required: true + - type: textarea + id: decisions + attributes: + label: Decision log + description: Notable review decisions (approvals, requested changes, deferrals). + placeholder: | + - 2026-05-13 @reviewer: requested change on tests/test_x.py + - 2026-05-13 @author: scoped follow-up to PR #... + - type: input + id: linear_issue + attributes: + label: Linear issue (optional) + placeholder: "EVE-123" + - type: input + id: slack_thread + attributes: + label: Slack thread (optional) + placeholder: "https://everminddash.slack.com/archives/.../p..." + - type: checkboxes + id: closure + attributes: + label: Closure criteria + description: Check all that apply before closing this mirror. + options: + - label: PR is merged, closed, or marked won't-fix upstream. + - label: Evidence snapshot above reflects the final state. + - label: Linear and Slack records have been updated (if linked). diff --git a/.github/ISSUE_TEMPLATE/security_tracker.yml b/.github/ISSUE_TEMPLATE/security_tracker.yml new file mode 100644 index 00000000..10844bf1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/security_tracker.yml @@ -0,0 +1,116 @@ +name: Security tracker (mirror) +description: Mirror a security PR or disclosure for Linear and Slack escalation / 镜像一个安全 PR 或披露 +title: "[Security Track] CWE-: " +labels: ["security", "pr-mirror", "tracking", "urgent"] +body: + - type: markdown + attributes: + value: | + Use this for any PR or disclosure that affects credentials, authn/authz, data exposure, + supply chain, or sandbox escape. The `urgent` label routes this to high-priority + notifications in Slack and Linear. + 用于凭证、认证授权、数据暴露、供应链、沙箱逃逸等安全 PR / 披露。`urgent` 标签会触发高优先级通知。 + Do NOT include exploit details that are not already public in the upstream PR. + 请勿写入未在 upstream PR 公开的利用细节。 + - type: input + id: cwe + attributes: + label: CWE id + placeholder: "CWE-798" + validations: + required: true + - type: input + id: pr_url + attributes: + label: Upstream PR or advisory URL + placeholder: https://github.com/EverMind-AI/EverOS/pull/ + validations: + required: true + - type: dropdown + id: severity + attributes: + label: Severity + options: + - Critical (full auth bypass / unauthenticated RCE / mass data loss) + - High (privileged data access / credential exposure / persistent compromise) + - Medium (limited data access / requires user interaction) + - Low (defense-in-depth / hardening) + validations: + required: true + - type: dropdown + id: exposure + attributes: + label: Reachability + description: How reachable is this in the documented quickstart / default config? + options: + - Default config (reproducible from a clean clone) + - Default config + network position + - Non-default config but documented + - Hypothetical / not yet reproducible + validations: + required: true + - type: textarea + id: affected + attributes: + label: Affected components + description: File paths, services, or versions impacted. + placeholder: | + - methods/EverCore/docker-compose.yaml (memsys-milvus-minio block) + - methods/EverCore/env.template + validations: + required: true + - type: textarea + id: fix_summary + attributes: + label: Proposed fix summary + description: One paragraph. What does the PR change? Cite the contract that makes it fail-closed. + validations: + required: true + - type: textarea + id: evidence + attributes: + label: Verification evidence + description: | + Required before closure. Show the commands and output that prove the fix works AND + that the unpatched state was exploitable. "No security mirror closes without evidence." + 关闭前必填。展示证明 fix 生效以及未修复状态可利用的命令与输出。 + render: shell + validations: + required: true + - type: textarea + id: residual + attributes: + label: Residual risk / follow-ups + description: Anything intentionally out of scope, plus follow-up issues that should be filed. + placeholder: | + - docs/installation/ still references the old default in examples; follow-up sweep needed. + - Consider adding a CI lint to catch hardcoded secrets in docker-compose files. + - type: input + id: linear_issue + attributes: + label: Linear issue (optional) + placeholder: "EVE-123" + - type: input + id: slack_thread + attributes: + label: Slack thread (optional) + placeholder: "https://everminddash.slack.com/archives/.../p..." + - type: checkboxes + id: disclosure + attributes: + label: Disclosure hygiene + description: Confirm before submitting. + options: + - label: This mirror contains no exploit details beyond what is already public in the upstream PR. + required: true + - label: The upstream PR or advisory link is correct and reachable. + required: true + - label: A maintainer has been pinged in Slack #bots or via Linear EVE if Severity is Critical or High. + - type: checkboxes + id: closure + attributes: + label: Closure criteria + options: + - label: Upstream PR merged, advisory published, or risk formally accepted. + - label: Verification evidence above reflects the merged state. + - label: Residual-risk follow-ups have issues filed (or explicitly waived). From 8a121390bd2494826dc1cf109ff4cfa4f529bc57 Mon Sep 17 00:00:00 2001 From: 0xVox Date: Wed, 13 May 2026 01:26:59 -0400 Subject: [PATCH 02/12] ci(sync): add auto-rebase workflow keeping fork main current with upstream MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Runs every 6 hours via cron + manual workflow_dispatch. - Rebases fork main onto upstream/main (preserves fork-only commits like the issue templates) - Force-pushes with --force-with-lease for safety - Opens a tracking issue on conflict instead of failing silently Uses default GITHUB_TOKEN — no PAT needed since we only push to fork. --- .github/workflows/sync-upstream.yml | 61 +++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 .github/workflows/sync-upstream.yml diff --git a/.github/workflows/sync-upstream.yml b/.github/workflows/sync-upstream.yml new file mode 100644 index 00000000..bfd8d884 --- /dev/null +++ b/.github/workflows/sync-upstream.yml @@ -0,0 +1,61 @@ +name: Sync fork from upstream + +on: + schedule: + - cron: '17 */6 * * *' # 每 6 小时跑一次,分钟 17 错开高峰 + workflow_dispatch: # 也支持手动触发 + +permissions: + contents: write + issues: write + +jobs: + sync: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Configure git + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + + - name: Add upstream remote + run: git remote add upstream https://github.com/EverMind-AI/EverOS.git + + - name: Fetch upstream + run: git fetch upstream + + - name: Rebase fork main onto upstream/main + id: rebase + run: | + git checkout main + set +e + git rebase upstream/main + rc=$? + if [ $rc -ne 0 ]; then + git rebase --abort + echo "conflict=true" >> "$GITHUB_OUTPUT" + exit $rc + fi + echo "conflict=false" >> "$GITHUB_OUTPUT" + + - name: Push to fork main + if: steps.rebase.outputs.conflict == 'false' + run: git push origin main --force-with-lease + + - name: Open issue on conflict + if: failure() && steps.rebase.outputs.conflict == 'true' + uses: actions/github-script@v7 + with: + script: | + await github.rest.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: `[sync] Rebase conflict syncing fork from upstream (${new Date().toISOString().slice(0,10)})`, + body: `Auto-sync from \`upstream/main\` failed due to rebase conflicts.\n\nRun id: ${context.runId}\nWorkflow: ${context.workflow}\n\nResolve manually:\n\n\`\`\`\ncd ~/EverOS && git fetch upstream && git rebase upstream/main\n# resolve conflicts, then:\ngit push origin main --force-with-lease\n\`\`\``, + labels: ['tracking'] + }); From 831bcd8945c92cd132fdd74ef966e1635cc033d3 Mon Sep 17 00:00:00 2001 From: 0xVox Date: Wed, 13 May 2026 01:41:46 -0400 Subject: [PATCH 03/12] ci(linear): add issue mirror workflow for pr-mirror labeled issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Triggers on issues.opened and issues.labeled. When pr-mirror label is present, creates a corresponding Linear issue in the EverMind-Dash project via Linear GraphQL API. Comments back on GitHub with the EVE-id link. Idempotency: skips if a '🔗 Linear:' marker comment already exists. Priority: 'urgent' label -> Linear urgent (1); otherwise medium (3). On API failure: applies 'sync-failed' label for triage. Requires (configured separately): Secret: LINEAR_API_KEY (Linear Personal API key, lin_api_*) Vars: LINEAR_TEAM_ID (EverMind team UUID) LINEAR_PROJECT_ID (EverMind-Dash project UUID) --- .github/workflows/linear-sync.yml | 118 ++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 .github/workflows/linear-sync.yml diff --git a/.github/workflows/linear-sync.yml b/.github/workflows/linear-sync.yml new file mode 100644 index 00000000..82b01e7c --- /dev/null +++ b/.github/workflows/linear-sync.yml @@ -0,0 +1,118 @@ +name: Linear sync for tracking mirrors + +on: + issues: + types: [opened, labeled] + +permissions: + issues: write + contents: read + +jobs: + sync: + if: contains(github.event.issue.labels.*.name, 'pr-mirror') + runs-on: ubuntu-latest + steps: + - name: Mirror GitHub issue to Linear + uses: actions/github-script@v7 + env: + LINEAR_API_KEY: ${{ secrets.LINEAR_API_KEY }} + LINEAR_TEAM_ID: ${{ vars.LINEAR_TEAM_ID }} + LINEAR_PROJECT_ID: ${{ vars.LINEAR_PROJECT_ID }} + with: + script: | + const issue = context.payload.issue; + const repo = `${context.repo.owner}/${context.repo.repo}`; + + // Idempotency: skip if Linear marker comment already exists + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + per_page: 100 + }); + if (comments.some(c => c.body.includes('🔗 Linear:'))) { + core.info('Already synced (marker comment present). Skipping.'); + return; + } + + const isUrgent = issue.labels.some(l => l.name === 'urgent'); + const priority = isUrgent ? 1 : 3; // 1=Urgent, 3=Medium + + const description = [ + `**Source**: [${repo}#${issue.number}](${issue.html_url})`, + '', + '---', + '', + issue.body || '_(no body provided)_', + '', + '---', + '', + `_Auto-synced from GitHub by [linear-sync workflow](https://github.com/${repo}/actions)._` + ].join('\n'); + + const mutation = ` + mutation IssueCreate($input: IssueCreateInput!) { + issueCreate(input: $input) { + success + issue { id identifier url } + } + } + `; + + const response = await fetch('https://api.linear.app/graphql', { + method: 'POST', + headers: { + 'Authorization': process.env.LINEAR_API_KEY, + 'Content-Type': 'application/json', + 'x-apollo-operation-name': 'IssueCreate' + }, + body: JSON.stringify({ + query: mutation, + variables: { + input: { + title: issue.title, + description: description, + teamId: process.env.LINEAR_TEAM_ID, + projectId: process.env.LINEAR_PROJECT_ID, + priority: priority + } + } + }) + }); + + const data = await response.json(); + + if (!response.ok || data.errors || !data?.data?.issueCreate?.success) { + const errMsg = 'Linear API error: ' + JSON.stringify(data, null, 2); + core.error(errMsg); + + try { + await github.rest.issues.createLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + name: 'sync-failed', + color: 'D93F0B', + description: 'Linear sync workflow failed for this issue' + }); + } catch (e) { /* exists already */ } + + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + labels: ['sync-failed'] + }); + + throw new Error(errMsg); + } + + const linearIssue = data.data.issueCreate.issue; + core.info(`Created ${linearIssue.identifier} -> ${linearIssue.url}`); + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + body: `🔗 Linear: [${linearIssue.identifier}](${linearIssue.url})\n\n_Auto-created by linear-sync workflow._` + }); From bee6f1d4a0750fa54718baf769d81b9a3a682579 Mon Sep 17 00:00:00 2001 From: 0xVox Date: Wed, 13 May 2026 01:59:47 -0400 Subject: [PATCH 04/12] docs(templates): align security_tracker Slack reference to actual channel Update the disclosure-hygiene checkbox to reference #p-evermind-dash (the actual Slack channel linked to the EverMind-Dash Linear project) instead of the placeholder #bots. --- .github/ISSUE_TEMPLATE/security_tracker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/security_tracker.yml b/.github/ISSUE_TEMPLATE/security_tracker.yml index 10844bf1..2f2c96c8 100644 --- a/.github/ISSUE_TEMPLATE/security_tracker.yml +++ b/.github/ISSUE_TEMPLATE/security_tracker.yml @@ -105,7 +105,7 @@ body: required: true - label: The upstream PR or advisory link is correct and reachable. required: true - - label: A maintainer has been pinged in Slack #bots or via Linear EVE if Severity is Critical or High. + - label: A maintainer has been pinged in Slack #p-evermind-dash or via Linear EVE if Severity is Critical or High. - type: checkboxes id: closure attributes: From 63be3787b70630f92916da3957fd9cfae0f1ece1 Mon Sep 17 00:00:00 2001 From: 0xVox Date: Wed, 13 May 2026 02:03:39 -0400 Subject: [PATCH 05/12] fix(linear-sync): prevent duplicate Linear issues from multi-label events Two compounding fixes to avoid creating multiple Linear issues from a single GitHub issue creation: 1. concurrency group keyed on issue.number with cancel-in-progress=false serializes runs per issue. Second run will see the first run's comment and skip via existing idempotency check. 2. Tighten 'labeled' event filter to only fire when the added label is pr-mirror itself, not any other label. Eliminates the four extra runs that gh issue create --label A --label B ... triggers (one issues.opened + four issues.labeled = 5 events for a 4-label create). Reproduction: gh issue create with 4 labels including pr-mirror was firing the workflow 5 times concurrently. Idempotency check has a ~5s race window before the first run posts its bot comment, so 2-3 runs created duplicate Linear issues before the rest skipped. Verified via Issue #4 sync producing both EVE-3 and EVE-4. --- .github/workflows/linear-sync.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/linear-sync.yml b/.github/workflows/linear-sync.yml index 82b01e7c..c2af07de 100644 --- a/.github/workflows/linear-sync.yml +++ b/.github/workflows/linear-sync.yml @@ -8,9 +8,15 @@ permissions: issues: write contents: read +concurrency: + group: linear-sync-issue-${{ github.event.issue.number }} + cancel-in-progress: false + jobs: sync: - if: contains(github.event.issue.labels.*.name, 'pr-mirror') + if: | + contains(github.event.issue.labels.*.name, 'pr-mirror') && + (github.event.action == 'opened' || github.event.label.name == 'pr-mirror') runs-on: ubuntu-latest steps: - name: Mirror GitHub issue to Linear From fe80ca1fd86f64ac27664aa58b41da73b3b2d00c Mon Sep 17 00:00:00 2001 From: 0xVox <35294173+Fearvox@users.noreply.github.com> Date: Wed, 13 May 2026 02:29:51 -0400 Subject: [PATCH 06/12] ci(watch): add overnight fork patrol Adds the fork overnight patrol workflow, Linear-aware tracking issue creation, and docs guard support for coming-soon use-case placeholders. Verified with local script checks and passing Docs CI. --- .github/scripts/overnight-watch.mjs | 371 ++++++++++++++++++++++++ .github/workflows/docs.yml | 3 + .github/workflows/overnight-watch.yml | 56 ++++ docs/fork-playground/overnight-watch.md | 54 ++++ 4 files changed, 484 insertions(+) create mode 100755 .github/scripts/overnight-watch.mjs create mode 100644 .github/workflows/overnight-watch.yml create mode 100644 docs/fork-playground/overnight-watch.md diff --git a/.github/scripts/overnight-watch.mjs b/.github/scripts/overnight-watch.mjs new file mode 100755 index 00000000..5fc2b1c4 --- /dev/null +++ b/.github/scripts/overnight-watch.mjs @@ -0,0 +1,371 @@ +#!/usr/bin/env node + +import { execFileSync } from "node:child_process"; +import { mkdtempSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; + +const config = { + repoOwner: process.env.REPO_OWNER || "Fearvox", + repoName: process.env.REPO_NAME || "EverOS", + upstreamRepo: process.env.UPSTREAM_REPO || "EverMind-AI/EverOS", + watchBranch: + process.env.WATCH_BRANCH || "codex-watch-overnight-2026-05-13", + ownerTimezone: process.env.OWNER_TIMEZONE || "America/Los_Angeles", + linearTeamId: + process.env.LINEAR_TEAM_ID || "233391d6-ec9e-4aa8-b534-16a221b8119a", + linearProjectId: + process.env.LINEAR_PROJECT_ID || "39aa3865-345c-4313-9dc0-ab3b509c5d21", + createTrackingIssue: + (process.env.CREATE_TRACKING_ISSUE || "false").toLowerCase() === "true", + githubToken: process.env.GITHUB_TOKEN || process.env.GH_TOKEN || "", + linearApiKey: process.env.LINEAR_API_KEY || "", +}; + +const repoSlug = `${config.repoOwner}/${config.repoName}`; +const recentWindowHours = Number(process.env.WATCH_WINDOW_HOURS || 24); +const since = new Date(Date.now() - recentWindowHours * 60 * 60 * 1000); +const now = new Date(); + +function run(command, args, options = {}) { + const result = execFileSync(command, args, { + encoding: "utf8", + stdio: ["ignore", "pipe", options.inheritStderr ? "inherit" : "pipe"], + env: { + ...process.env, + GH_TOKEN: config.githubToken || process.env.GH_TOKEN, + }, + }); + return result.trim(); +} + +function tryRun(command, args, fallback = "") { + try { + return run(command, args); + } catch (error) { + return fallback; + } +} + +function ghJson(endpoint) { + const output = run("gh", [ + "api", + "-H", + "Accept: application/vnd.github+json", + endpoint, + ]); + return JSON.parse(output); +} + +function ensureRemote(name, url) { + const remotes = tryRun("git", ["remote"]).split("\n").filter(Boolean); + if (!remotes.includes(name)) { + run("git", ["remote", "add", name, url]); + } +} + +function fetchGitState() { + ensureRemote("upstream", `https://github.com/${config.upstreamRepo}.git`); + tryRun("git", ["fetch", "origin", "--prune"], ""); + tryRun("git", ["fetch", "upstream", "main", "--prune"], ""); + + const forkHead = tryRun("git", ["rev-parse", "--short", "origin/main"], "unknown"); + const upstreamHead = tryRun( + "git", + ["rev-parse", "--short", "upstream/main"], + "unknown", + ); + const counts = tryRun( + "git", + ["rev-list", "--left-right", "--count", "origin/main...upstream/main"], + "0\t0", + ) + .split(/\s+/) + .map((value) => Number(value)); + + const watchBranchSha = tryRun( + "git", + ["ls-remote", "--heads", "origin", config.watchBranch], + "", + ) + .split(/\s+/)[0] + ?.slice(0, 12); + + return { + forkHead, + upstreamHead, + forkAhead: counts[0] || 0, + forkBehind: counts[1] || 0, + watchBranchSha: watchBranchSha || "", + }; +} + +function fetchGitHubState() { + const runs = ghJson( + `/repos/${repoSlug}/actions/runs?per_page=50&status=completed`, + ).workflow_runs || []; + const failedRuns = runs + .filter((runInfo) => new Date(runInfo.created_at) >= since) + .filter((runInfo) => + ["failure", "cancelled", "timed_out"].includes(runInfo.conclusion), + ) + .slice(0, 10); + + const upstreamPulls = ghJson( + `/repos/${config.upstreamRepo}/pulls?state=open&sort=updated&direction=desc&per_page=30`, + ) + .filter((pull) => new Date(pull.updated_at) >= since) + .slice(0, 10); + + const forkPulls = ghJson( + `/repos/${repoSlug}/pulls?state=open&sort=updated&direction=desc&per_page=30`, + ) + .filter((pull) => new Date(pull.updated_at) >= since) + .slice(0, 10); + + return { failedRuns, upstreamPulls, forkPulls }; +} + +function lineForPull(pull) { + return `- #${pull.number} ${pull.title} (${pull.user.login}, updated ${pull.updated_at})`; +} + +function lineForRun(runInfo) { + return `- ${runInfo.name}: ${runInfo.conclusion} (${runInfo.html_url})`; +} + +function renderReport(gitState, githubState) { + const findings = []; + + if (!gitState.watchBranchSha) { + findings.push(`Watch branch is not on origin: ${config.watchBranch}`); + } + if (gitState.forkBehind > 0) { + findings.push(`Fork main is behind upstream/main by ${gitState.forkBehind} commit(s).`); + } + if (githubState.failedRuns.length > 0) { + findings.push( + `${githubState.failedRuns.length} completed workflow run(s) failed in the last ${recentWindowHours}h.`, + ); + } + + const verdict = findings.length > 0 ? "FLAG" : "PASS"; + const localNow = now.toLocaleString("en-US", { + timeZone: config.ownerTimezone, + hour12: false, + }); + + return { + verdict, + body: [ + `# Overnight Fork Watch: ${verdict}`, + "", + `Generated: ${now.toISOString()} (${config.ownerTimezone}: ${localNow})`, + `Repository: ${repoSlug}`, + `Upstream: ${config.upstreamRepo}`, + `Watch branch: \`${config.watchBranch}\``, + "", + "## Drift", + "", + `- origin/main: \`${gitState.forkHead}\``, + `- upstream/main: \`${gitState.upstreamHead}\``, + `- fork ahead: ${gitState.forkAhead}`, + `- fork behind: ${gitState.forkBehind}`, + `- watch branch on origin: ${ + gitState.watchBranchSha ? `yes (\`${gitState.watchBranchSha}\`)` : "no" + }`, + "", + "## Findings", + "", + findings.length ? findings.map((item) => `- ${item}`).join("\n") : "- None.", + "", + `## Fork Workflow Failures (${recentWindowHours}h)`, + "", + githubState.failedRuns.length + ? githubState.failedRuns.map(lineForRun).join("\n") + : "- None.", + "", + `## Upstream PRs Updated (${recentWindowHours}h)`, + "", + githubState.upstreamPulls.length + ? githubState.upstreamPulls.map(lineForPull).join("\n") + : "- None.", + "", + `## Fork PRs Updated (${recentWindowHours}h)`, + "", + githubState.forkPulls.length + ? githubState.forkPulls.map(lineForPull).join("\n") + : "- None.", + "", + "## Operator Notes", + "", + "- This issue is safe for public tracking: no local paths, host/IP values, or secrets are included.", + "- A GitHub issue created by `GITHUB_TOKEN` does not trigger secondary workflows, so this watch mirrors to Linear directly when `LINEAR_API_KEY` is available.", + ].join("\n"), + }; +} + +function ensureLabel(name, color, description) { + tryRun("gh", [ + "label", + "create", + name, + "--repo", + repoSlug, + "--color", + color, + "--description", + description, + ]); +} + +function issueHasLinearMarker(issueNumber) { + const comments = ghJson(`/repos/${repoSlug}/issues/${issueNumber}/comments?per_page=100`); + return comments.some((comment) => comment.body.includes("Linear:")); +} + +async function mirrorToLinear(issueNumber, title, body) { + if (!config.linearApiKey || issueHasLinearMarker(issueNumber)) { + return; + } + + const mutation = ` + mutation IssueCreate($input: IssueCreateInput!) { + issueCreate(input: $input) { + success + issue { id identifier url } + } + } + `; + + const response = await fetch("https://api.linear.app/graphql", { + method: "POST", + headers: { + Authorization: config.linearApiKey, + "Content-Type": "application/json", + "x-apollo-operation-name": "IssueCreate", + }, + body: JSON.stringify({ + query: mutation, + variables: { + input: { + title, + description: [ + `**Source**: https://github.com/${repoSlug}/issues/${issueNumber}`, + "", + "---", + "", + body, + ].join("\n"), + teamId: config.linearTeamId, + projectId: config.linearProjectId, + priority: 3, + }, + }, + }), + }); + + const data = await response.json(); + if (!response.ok || data.errors || !data?.data?.issueCreate?.success) { + ensureLabel("sync-failed", "D93F0B", "Linear sync workflow failed for this issue"); + tryRun("gh", [ + "issue", + "edit", + String(issueNumber), + "--repo", + repoSlug, + "--add-label", + "sync-failed", + ]); + throw new Error(`Linear API error: ${JSON.stringify(data)}`); + } + + const linearIssue = data.data.issueCreate.issue; + const marker = `Linear: [${linearIssue.identifier}](${linearIssue.url})\n\n_Auto-created by overnight-watch._`; + run("gh", ["issue", "comment", String(issueNumber), "--repo", repoSlug, "--body", marker]); +} + +function findExistingIssue(title) { + const issues = JSON.parse( + run("gh", [ + "issue", + "list", + "--repo", + repoSlug, + "--state", + "open", + "--label", + "overnight-watch", + "--json", + "number,title", + "--limit", + "20", + ]), + ); + return issues.find((issue) => issue.title === title); +} + +async function createOrUpdateTrackingIssue(report) { + if (!config.createTrackingIssue || report.verdict === "PASS") { + return; + } + + ensureLabel("overnight-watch", "1D76DB", "Automated overnight fork watch"); + ensureLabel("tracking", "5319E7", "Long-lived tracking item"); + ensureLabel("pr-mirror", "0E8A16", "Mirrored into Linear or Slack tracking"); + + const date = now.toISOString().slice(0, 10); + const title = `[watch] Overnight fork patrol: ${date}`; + const existing = findExistingIssue(title); + const tempDir = mkdtempSync(join(tmpdir(), "everos-watch-")); + const bodyFile = join(tempDir, "body.md"); + writeFileSync(bodyFile, report.body); + + if (existing) { + run("gh", [ + "issue", + "comment", + String(existing.number), + "--repo", + repoSlug, + "--body-file", + bodyFile, + ]); + await mirrorToLinear(existing.number, title, report.body); + return; + } + + const created = run("gh", [ + "issue", + "create", + "--repo", + repoSlug, + "--title", + title, + "--body-file", + bodyFile, + "--label", + "overnight-watch", + "--label", + "tracking", + "--label", + "pr-mirror", + ]); + const match = created.match(/\/issues\/(\d+)/); + if (match) { + await mirrorToLinear(Number(match[1]), title, report.body); + } +} + +async function main() { + const gitState = fetchGitState(); + const githubState = fetchGitHubState(); + const report = renderReport(gitState, githubState); + console.log(report.body); + await createOrUpdateTrackingIssue(report); +} + +main().catch((error) => { + console.error(error.message); + process.exit(1); +}); diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index a8eec180..aa74ce5f 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -103,6 +103,9 @@ jobs: banner_match = re.search(r"\[!\[[^\]]*\]\([^)]+\)\]\(([^)]+)\)", cell) primary_match = re.search(r"^\[(?:Code|Plugin|Live Demo)\]\(([^)]+)\)", cell, flags=re.M) + if "Coming soon" in cell and not primary_match: + continue + if not banner_match: failures.append(f"{path}: {title}: missing linked banner") elif not primary_match: diff --git a/.github/workflows/overnight-watch.yml b/.github/workflows/overnight-watch.yml new file mode 100644 index 00000000..3a0e8489 --- /dev/null +++ b/.github/workflows/overnight-watch.yml @@ -0,0 +1,56 @@ +name: Fork overnight watch + +on: + schedule: + # 02:13 America/Los_Angeles during daylight time. GitHub cron is UTC. + - cron: "13 9 * * *" + workflow_dispatch: + inputs: + create_tracking_issue: + description: "Open/update a tracking issue when the watch verdict is FLAG" + required: false + type: boolean + default: true + watch_branch: + description: "Fork playground branch to verify on origin" + required: false + type: string + default: "codex-watch-overnight-2026-05-13" + +permissions: + actions: read + contents: read + issues: write + pull-requests: read + +concurrency: + group: overnight-watch-${{ github.ref }} + cancel-in-progress: false + +jobs: + watch: + if: github.repository == 'Fearvox/EverOS' + runs-on: ubuntu-latest + env: + REPO_OWNER: ${{ vars.REPO_OWNER || 'Fearvox' }} + REPO_NAME: ${{ vars.REPO_NAME || 'EverOS' }} + UPSTREAM_REPO: EverMind-AI/EverOS + WATCH_BRANCH: ${{ inputs.watch_branch || vars.WATCH_BRANCH || 'codex-watch-overnight-2026-05-13' }} + OWNER_TIMEZONE: ${{ vars.OWNER_TIMEZONE || 'America/Los_Angeles' }} + LINEAR_TEAM_ID: ${{ vars.LINEAR_TEAM_ID || '233391d6-ec9e-4aa8-b534-16a221b8119a' }} + LINEAR_PROJECT_ID: ${{ vars.LINEAR_PROJECT_ID || '39aa3865-345c-4313-9dc0-ab3b509c5d21' }} + LINEAR_API_KEY: ${{ secrets.LINEAR_API_KEY }} + GH_TOKEN: ${{ github.token }} + GITHUB_TOKEN: ${{ github.token }} + CREATE_TRACKING_ISSUE: ${{ inputs.create_tracking_issue || github.event_name == 'schedule' }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Run overnight watch + run: node .github/scripts/overnight-watch.mjs diff --git a/docs/fork-playground/overnight-watch.md b/docs/fork-playground/overnight-watch.md new file mode 100644 index 00000000..379fd21b --- /dev/null +++ b/docs/fork-playground/overnight-watch.md @@ -0,0 +1,54 @@ +# Overnight Fork Watch + +This fork can move fast, but the upstream feed should stay boring and auditable. +The overnight watch is a small GitHub Actions patrol for `Fearvox/EverOS`. + +## What It Checks + +- `origin/main` drift against `EverMind-AI/EverOS` `upstream/main`. +- Whether the active playground branch exists on the fork: + `codex-watch-overnight-2026-05-13`. +- Failed, cancelled, or timed-out fork workflow runs in the last 24 hours. +- Upstream and fork pull requests updated in the last 24 hours. + +## Tracking Behavior + +The workflow prints a public-safe report on every run. If the verdict is `FLAG`, +it opens or updates a GitHub issue labeled: + +- `overnight-watch` +- `tracking` +- `pr-mirror` + +Issues created by `GITHUB_TOKEN` do not trigger secondary workflows. Because of +that, the watch mirrors the tracking issue to Linear directly when +`LINEAR_API_KEY` is available. The target Linear team/project are: + +- Team: `233391d6-ec9e-4aa8-b534-16a221b8119a` +- Project: `39aa3865-345c-4313-9dc0-ab3b509c5d21` + +A `FLAG` verdict does not fail the watch workflow by itself. Runtime errors +still fail the workflow, but expected drift or downstream failures are reported +through the tracking issue so the watch does not poison its own next run. + +## Manual Run + +```bash +REPO_OWNER=Fearvox \ +REPO_NAME=EverOS \ +WATCH_BRANCH=codex-watch-overnight-2026-05-13 \ +OWNER_TIMEZONE=America/Los_Angeles \ +LINEAR_TEAM_ID=233391d6-ec9e-4aa8-b534-16a221b8119a \ +LINEAR_PROJECT_ID=39aa3865-345c-4313-9dc0-ab3b509c5d21 \ +CREATE_TRACKING_ISSUE=false \ +node .github/scripts/overnight-watch.mjs +``` + +Set `CREATE_TRACKING_ISSUE=true` only when you want the local run to mutate +GitHub issues. + +## Public-Surface Hygiene + +Reports intentionally avoid local absolute paths, host/IP values, token names +beyond the required GitHub secret names, and operator-only commands. They should +be safe to show in Discord or a screen share. From a1f4a4586e0fc1ad0438a4553b33978fbdfc281e Mon Sep 17 00:00:00 2001 From: 0xVox Date: Wed, 13 May 2026 05:49:45 -0400 Subject: [PATCH 07/12] chore: add MUW agent review instructions --- .github/copilot-instructions.md | 42 +++++++++++++++++++++++++++++++++ AGENTS.md | 11 +++++++++ 2 files changed, 53 insertions(+) create mode 100644 .github/copilot-instructions.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 00000000..182b6691 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,42 @@ +# Copilot and Codex Review Instructions + +When reviewing pull requests in this repository, use the MUW review contract. +Start every review with this block: + +```text +VERDICT: PASS / FLAG / BLOCK +VERDICT_SUMMARY: three lines or fewer; what passed, what is risky, and the next action +EVIDENCE: +``` + +Use the verdicts this way: + +- `PASS`: the pull request objective is met and the evidence is sufficient. +- `FLAG`: useful progress, but a non-blocking issue, missing evidence, or follow-up remains. +- `BLOCK`: the objective is unmet, unsafe, unverifiable, or materially wrong. + +Report findings first, ordered by severity. For each actionable finding, include: + +- Severity +- File/path +- Evidence from the actual diff, status check, command output, or linked issue +- Why it matters +- Fix guidance or the next verification required + +Review method: + +1. Identify the promised objective from the PR title, body, linked issue, and changed files. +2. Inspect the real diff and available checks before making a success claim. +3. Compare evidence against the objective; do not accept `done` from a summary alone. +4. Verify the smallest real path that proves the claim. +5. Keep evidence concise, reproducible, and repository-relative. + +EverOS-specific checks: + +- For `methods/EverCore/`, preserve async I/O, tenant scoping, and existing module boundaries. +- For prompts, keep EN/ZH variants aligned when both exist. +- For docs and community files, preserve the README reader journey and keep root uncluttered. +- For `.github/workflows/docs.yml`, keep the workflow lightweight and dependency-free unless the PR explicitly changes that contract. +- Do not expose secrets, credential paths, raw tokens, private host values, or operator-only commands in review text. + +For clean reviews, still return the MUW block with the evidence checked and any residual test gap. Keep the final review concise; prefer one clear judgment over a long menu of weak suggestions. diff --git a/AGENTS.md b/AGENTS.md index 2707448d..90793f32 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -71,3 +71,14 @@ uv run pyright # Type check, if pyright is installed variants. - Prefer existing repo patterns and component boundaries before adding new abstractions. + +## GitHub Agent Review Contract + +- GitHub Copilot, Codex, and other review agents should follow + `.github/copilot-instructions.md`. +- Start PR reviews with the MUW block: + `VERDICT: PASS / FLAG / BLOCK`, `VERDICT_SUMMARY:`, and `EVIDENCE:`. +- Do not mark a PR `PASS` from author summary alone; inspect the actual diff, + linked issue, and available checks first. +- Report actionable findings first, ordered by severity, with file/path, + evidence, impact, and fix guidance. From 0ae77fcf813bfe5be8417e9c418e3d43399c5aa4 Mon Sep 17 00:00:00 2001 From: 0xVox Date: Wed, 13 May 2026 13:24:31 -0400 Subject: [PATCH 08/12] chore: align Codex review guidelines header --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 90793f32..d5b6b160 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -72,7 +72,7 @@ uv run pyright # Type check, if pyright is installed - Prefer existing repo patterns and component boundaries before adding new abstractions. -## GitHub Agent Review Contract +## Review guidelines - GitHub Copilot, Codex, and other review agents should follow `.github/copilot-instructions.md`. From 5d42427162cdcd28a41656f1b8f49d44bb54c980 Mon Sep 17 00:00:00 2001 From: 0xVox Date: Wed, 13 May 2026 13:28:44 -0400 Subject: [PATCH 09/12] chore: add MUW review custom agent --- .github/agents/muw-review.md | 50 ++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .github/agents/muw-review.md diff --git a/.github/agents/muw-review.md b/.github/agents/muw-review.md new file mode 100644 index 00000000..84237833 --- /dev/null +++ b/.github/agents/muw-review.md @@ -0,0 +1,50 @@ +--- +name: MUW Review +description: Review pull requests and repo changes using the MUW PASS/FLAG/BLOCK contract. +--- + +# MUW Review Agent + +You are a review-only agent for Fearvox/EverOS. Use this agent when the user asks +for a pull request review, workflow review, evidence check, or closeout check. + +Default behavior: + +- Do not edit files, push commits, or create a pull request unless the user + explicitly asks for fixes. +- Inspect the real pull request diff, linked issue, available checks, and + repository instructions before making a success claim. +- Prefer a concise GitHub comment or session summary over a long essay. + +Start every review with: + +```text +VERDICT: PASS / FLAG / BLOCK +VERDICT_SUMMARY: three lines or fewer; what passed, what is risky, and the next action +EVIDENCE: +``` + +Verdicts: + +- `PASS`: the objective is met and evidence is sufficient. +- `FLAG`: useful progress, but a non-blocking issue, missing evidence, or follow-up remains. +- `BLOCK`: the objective is unmet, unsafe, unverifiable, or materially wrong. + +Findings: + +- List findings first, ordered by severity. +- For each finding, include severity, file/path, evidence, why it matters, and + required fix or next verification. +- If the review is clean, still include the evidence checked and residual test gap. + +EverOS focus: + +- Preserve async I/O, tenant scoping, and existing module boundaries in + `methods/EverCore/`. +- Keep EN/ZH prompt variants aligned when both exist. +- Treat broken links, failing docs checks, stale setup commands, missing + `.env.example` files, and unclear issue templates as DX bugs. +- Keep `.github/workflows/docs.yml` lightweight and dependency-free unless the + task explicitly changes that contract. +- Do not expose secrets, credential paths, raw tokens, private host values, or + operator-only commands in public comments. From 226df866e4252b82c421be49d02360ccbb3ddf3f Mon Sep 17 00:00:00 2001 From: 0xVox Date: Wed, 13 May 2026 13:34:17 -0400 Subject: [PATCH 10/12] revert: remove MUW review custom agent --- .github/agents/muw-review.md | 50 ------------------------------------ 1 file changed, 50 deletions(-) delete mode 100644 .github/agents/muw-review.md diff --git a/.github/agents/muw-review.md b/.github/agents/muw-review.md deleted file mode 100644 index 84237833..00000000 --- a/.github/agents/muw-review.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -name: MUW Review -description: Review pull requests and repo changes using the MUW PASS/FLAG/BLOCK contract. ---- - -# MUW Review Agent - -You are a review-only agent for Fearvox/EverOS. Use this agent when the user asks -for a pull request review, workflow review, evidence check, or closeout check. - -Default behavior: - -- Do not edit files, push commits, or create a pull request unless the user - explicitly asks for fixes. -- Inspect the real pull request diff, linked issue, available checks, and - repository instructions before making a success claim. -- Prefer a concise GitHub comment or session summary over a long essay. - -Start every review with: - -```text -VERDICT: PASS / FLAG / BLOCK -VERDICT_SUMMARY: three lines or fewer; what passed, what is risky, and the next action -EVIDENCE: -``` - -Verdicts: - -- `PASS`: the objective is met and evidence is sufficient. -- `FLAG`: useful progress, but a non-blocking issue, missing evidence, or follow-up remains. -- `BLOCK`: the objective is unmet, unsafe, unverifiable, or materially wrong. - -Findings: - -- List findings first, ordered by severity. -- For each finding, include severity, file/path, evidence, why it matters, and - required fix or next verification. -- If the review is clean, still include the evidence checked and residual test gap. - -EverOS focus: - -- Preserve async I/O, tenant scoping, and existing module boundaries in - `methods/EverCore/`. -- Keep EN/ZH prompt variants aligned when both exist. -- Treat broken links, failing docs checks, stale setup commands, missing - `.env.example` files, and unclear issue templates as DX bugs. -- Keep `.github/workflows/docs.yml` lightweight and dependency-free unless the - task explicitly changes that contract. -- Do not expose secrets, credential paths, raw tokens, private host values, or - operator-only commands in public comments. From 35864fbcfb073d3823289411acc567bcfc4d576b Mon Sep 17 00:00:00 2001 From: 0xVox Date: Wed, 13 May 2026 15:18:26 -0400 Subject: [PATCH 11/12] chore: add MUW review comment lane --- .github/MUW_REVIEW_LANE.md | 58 +++++ .github/scripts/muw-review-lane.mjs | 325 ++++++++++++++++++++++++++++ 2 files changed, 383 insertions(+) create mode 100644 .github/MUW_REVIEW_LANE.md create mode 100644 .github/scripts/muw-review-lane.mjs diff --git a/.github/MUW_REVIEW_LANE.md b/.github/MUW_REVIEW_LANE.md new file mode 100644 index 00000000..77f01618 --- /dev/null +++ b/.github/MUW_REVIEW_LANE.md @@ -0,0 +1,58 @@ +# MUW Review Lane + +Use this lane when GitHub's native Codex review is useful but its fixed review +wrapper is too loose for MUW closeout work. + +The lane has three steps: + +1. Collect PR evidence. +2. Ask Codex to produce an exact MUW verdict from the generated prompt. +3. Post the verdict back to the PR with an idempotency marker. + +## Collect Evidence + +```bash +node .github/scripts/muw-review-lane.mjs collect --pr 24 --repo Fearvox/EverOS +``` + +The command prints paths like: + +```text +context=/tmp/muw-review-pr-24/pr-24-context.md +prompt=/tmp/muw-review-pr-24/pr-24-prompt.md +metadata=/tmp/muw-review-pr-24/pr-24-metadata.json +``` + +Give the prompt file to Codex. The context bundle includes PR metadata, changed +files, status checks, recent comments, existing reviews, and a redacted patch. + +## Post Verdict + +Save the Codex verdict to a file, then post it: + +```bash +node .github/scripts/muw-review-lane.mjs post \ + --pr 24 \ + --repo Fearvox/EverOS \ + --body-file /tmp/muw-review-pr-24/verdict.md +``` + +`post` refuses bodies that do not contain: + +```text +VERDICT: +VERDICT_SUMMARY: +EVIDENCE: +``` + +It also adds a hidden marker containing the PR head SHA. Re-running `post` for +the same head is a no-op unless `--force` is provided. + +## Why Not Native Review + +- GitHub's `@codex review` endpoint is useful, but it wraps responses in the + native Codex review shell. +- GitHub Agent tasks are mutation-oriented and may create draft PRs even for a + review-only prompt. +- This lane keeps review evidence gathering and comment publishing mechanical, + while leaving the verdict judgment to Codex. diff --git a/.github/scripts/muw-review-lane.mjs b/.github/scripts/muw-review-lane.mjs new file mode 100644 index 00000000..98d57ff3 --- /dev/null +++ b/.github/scripts/muw-review-lane.mjs @@ -0,0 +1,325 @@ +#!/usr/bin/env node + +import { execFileSync } from "node:child_process"; +import { mkdirSync, readFileSync, writeFileSync } from "node:fs"; +import { join, resolve } from "node:path"; +import { tmpdir } from "node:os"; + +const DEFAULT_REPO = process.env.GH_REPO || "Fearvox/EverOS"; +const DEFAULT_PATCH_BYTES = 120_000; +const MARKER = "muw-review-lane:v1"; + +function usage(exitCode = 0) { + const text = ` +Usage: + node .github/scripts/muw-review-lane.mjs collect --pr [--repo owner/name] [--out ] + node .github/scripts/muw-review-lane.mjs post --pr --body-file [--repo owner/name] [--force] + +Collect creates a redacted PR evidence bundle and a Codex prompt. +Post publishes a MUW-formatted issue comment with an idempotency marker. +`; + process.stderr.write(text.trimStart()); + process.exit(exitCode); +} + +function parseArgs(argv) { + const [command, ...rest] = argv; + if (!command || command === "--help" || command === "-h") usage(0); + + const options = { command, repo: DEFAULT_REPO, force: false }; + for (let index = 0; index < rest.length; index += 1) { + const arg = rest[index]; + if (arg === "--repo") options.repo = rest[++index]; + else if (arg === "--pr") options.pr = Number(rest[++index]); + else if (arg === "--out") options.out = rest[++index]; + else if (arg === "--body-file") options.bodyFile = rest[++index]; + else if (arg === "--patch-bytes") options.patchBytes = Number(rest[++index]); + else if (arg === "--force") options.force = true; + else throw new Error(`Unknown argument: ${arg}`); + } + + if (!["collect", "post"].includes(command)) usage(1); + if (!Number.isInteger(options.pr) || options.pr <= 0) { + throw new Error("--pr must be a positive pull request number"); + } + return options; +} + +function run(command, args, options = {}) { + return execFileSync(command, args, { + encoding: "utf8", + input: options.input, + env: process.env, + stdio: ["pipe", "pipe", options.inheritStderr ? "inherit" : "pipe"], + maxBuffer: 20 * 1024 * 1024, + }).trim(); +} + +function gh(args, options = {}) { + return run("gh", args, options); +} + +function ghJson(args) { + return JSON.parse(gh(args)); +} + +function redact(value) { + return String(value ?? "") + .replace(/github_pat_[A-Za-z0-9_]+/g, "[REDACTED_GITHUB_TOKEN]") + .replace(/gh[pousr]_[A-Za-z0-9_]+/g, "[REDACTED_GITHUB_TOKEN]") + .replace(/sk-[A-Za-z0-9_-]{20,}/g, "[REDACTED_API_KEY]") + .replace(/xox[baprs]-[A-Za-z0-9-]+/g, "[REDACTED_SLACK_TOKEN]") + .replace(/(Authorization:\s*Bearer\s+)[A-Za-z0-9._~+/=-]+/gi, "$1[REDACTED_TOKEN]") + .replace(/(token=)[A-Za-z0-9._~+/=-]+/gi, "$1[REDACTED_TOKEN]"); +} + +function truncate(value, maxBytes) { + const text = redact(value); + const bytes = Buffer.byteLength(text, "utf8"); + if (bytes <= maxBytes) return text; + return `${text.slice(0, maxBytes)}\n\n[TRUNCATED: ${bytes - maxBytes} bytes omitted]`; +} + +function summarizeChecks(items = []) { + if (!items.length) return "- No status checks reported."; + return items + .map((item) => { + const name = item.name || item.context || item.workflowName || item.__typename; + const state = item.conclusion || item.state || item.status || "unknown"; + const url = item.detailsUrl || item.targetUrl || ""; + return `- ${name}: ${state}${url ? ` (${url})` : ""}`; + }) + .join("\n"); +} + +function summarizeFiles(files = []) { + if (!files.length) return "- No changed files reported."; + return files + .map((file) => `- ${file.path} (+${file.additions}/-${file.deletions})`) + .join("\n"); +} + +function summarizeReviews(reviews = []) { + if (!reviews.length) return "- No reviews yet."; + return reviews + .map((review) => { + const author = review.author?.login || "unknown"; + const body = truncate(review.body || "", 700).replace(/\n/g, " "); + return `- ${review.submittedAt || "unknown"} ${author} ${review.state}: ${body}`; + }) + .join("\n"); +} + +function summarizeComments(comments = []) { + if (!comments.length) return "- No issue comments yet."; + return comments + .slice(-20) + .map((comment) => { + const author = comment.author?.login || "unknown"; + const body = truncate(comment.body || "", 700).replace(/\n/g, " "); + return `- ${comment.createdAt || "unknown"} ${author}: ${body}`; + }) + .join("\n"); +} + +function collect(options) { + const outDir = resolve( + options.out || join(tmpdir(), `muw-review-pr-${options.pr}`), + ); + mkdirSync(outDir, { recursive: true }); + + const fields = [ + "number", + "title", + "url", + "author", + "baseRefName", + "headRefName", + "headRefOid", + "isDraft", + "body", + "labels", + "mergeStateStatus", + "statusCheckRollup", + "files", + "commits", + "comments", + "reviews", + ].join(","); + + const pr = ghJson([ + "pr", + "view", + String(options.pr), + "--repo", + options.repo, + "--json", + fields, + ]); + const patch = gh([ + "pr", + "diff", + String(options.pr), + "--repo", + options.repo, + "--patch", + ]); + + const patchBytes = options.patchBytes || DEFAULT_PATCH_BYTES; + const contextPath = join(outDir, `pr-${options.pr}-context.md`); + const promptPath = join(outDir, `pr-${options.pr}-prompt.md`); + const metadataPath = join(outDir, `pr-${options.pr}-metadata.json`); + + const context = [ + `# MUW Review Context: ${options.repo}#${pr.number}`, + "", + `- Title: ${pr.title}`, + `- URL: ${pr.url}`, + `- Author: ${pr.author?.login || "unknown"}`, + `- Draft: ${pr.isDraft}`, + `- Base: ${pr.baseRefName}`, + `- Head: ${pr.headRefName}`, + `- Head SHA: ${pr.headRefOid}`, + `- Merge state: ${pr.mergeStateStatus || "unknown"}`, + `- Labels: ${(pr.labels || []).map((label) => label.name).join(", ") || "none"}`, + "", + "## PR Body", + "", + truncate(pr.body || "_No body._", 12_000), + "", + "## Files", + "", + summarizeFiles(pr.files), + "", + "## Checks", + "", + summarizeChecks(pr.statusCheckRollup), + "", + "## Existing Reviews", + "", + summarizeReviews(pr.reviews), + "", + "## Recent Comments", + "", + summarizeComments(pr.comments), + "", + "## Patch", + "", + "```diff", + truncate(patch, patchBytes), + "```", + "", + ].join("\n"); + + const prompt = [ + "You are reviewing a GitHub pull request using the MUW review contract.", + "", + "Read the context file listed below. Return only a GitHub-ready comment body.", + "Do not include Markdown fences around the whole answer.", + "", + "Required shape:", + "", + "VERDICT: PASS / FLAG / BLOCK", + "VERDICT_SUMMARY: three lines or fewer; what passed, what is risky, and the next action", + "EVIDENCE:", + "", + "Rules:", + "- Do not mark PASS from author summary alone.", + "- Ground claims in files, checks, comments, or patch evidence.", + "- Findings first, ordered by severity.", + "- For each finding include severity, file/path, evidence, why it matters, and fix guidance.", + "- If clean, include evidence checked and residual risk/test gap.", + "- Keep the answer concise and public-safe.", + "", + `Context file: ${contextPath}`, + "", + ].join("\n"); + + writeFileSync(contextPath, context); + writeFileSync(promptPath, prompt); + writeFileSync( + metadataPath, + `${JSON.stringify( + { + repo: options.repo, + pr: pr.number, + headRefOid: pr.headRefOid, + contextPath, + promptPath, + }, + null, + 2, + )}\n`, + ); + + process.stdout.write( + [ + `context=${contextPath}`, + `prompt=${promptPath}`, + `metadata=${metadataPath}`, + `head=${pr.headRefOid}`, + ].join("\n") + "\n", + ); +} + +function markerFor(options, headRefOid) { + return ``; +} + +function validateMuwBody(body) { + const missing = ["VERDICT:", "VERDICT_SUMMARY:", "EVIDENCE:"].filter( + (needle) => !body.includes(needle), + ); + if (missing.length) { + throw new Error(`Body is missing required MUW field(s): ${missing.join(", ")}`); + } +} + +function existingMarkerComment(options, marker) { + const [owner, repo] = options.repo.split("/"); + const comments = ghJson([ + "api", + `/repos/${owner}/${repo}/issues/${options.pr}/comments?per_page=100`, + ]); + return comments.find((comment) => String(comment.body || "").includes(marker)); +} + +function post(options) { + if (!options.bodyFile) throw new Error("--body-file is required for post"); + const body = redact(readFileSync(resolve(options.bodyFile), "utf8")).trim(); + validateMuwBody(body); + + const pr = ghJson([ + "pr", + "view", + String(options.pr), + "--repo", + options.repo, + "--json", + "headRefOid,url", + ]); + const marker = markerFor(options, pr.headRefOid); + const existing = existingMarkerComment(options, marker); + if (existing && !options.force) { + process.stdout.write( + `skip=existing-comment\nurl=${existing.html_url}\nhead=${pr.headRefOid}\n`, + ); + return; + } + + const comment = `${marker}\n${body}\n`; + const url = gh( + ["pr", "comment", String(options.pr), "--repo", options.repo, "--body", comment], + { inheritStderr: true }, + ); + process.stdout.write(`posted=${url}\nhead=${pr.headRefOid}\n`); +} + +try { + const options = parseArgs(process.argv.slice(2)); + if (options.command === "collect") collect(options); + else if (options.command === "post") post(options); +} catch (error) { + process.stderr.write(`muw-review-lane: ${error.message}\n`); + process.exit(1); +} From 2734a8257cad3443b548b117b39f8532404633e3 Mon Sep 17 00:00:00 2001 From: 0xVox <35294173+Fearvox@users.noreply.github.com> Date: Wed, 13 May 2026 20:12:05 -0400 Subject: [PATCH 12/12] docs: add MUW response for latest PR review --- .github/MUW_REVIEW_REPLY.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/MUW_REVIEW_REPLY.md diff --git a/.github/MUW_REVIEW_REPLY.md b/.github/MUW_REVIEW_REPLY.md new file mode 100644 index 00000000..fd7af4d0 --- /dev/null +++ b/.github/MUW_REVIEW_REPLY.md @@ -0,0 +1,24 @@ +VERDICT: FLAG +VERDICT_SUMMARY: The PR adds a comprehensive MUW review lane, tracker templates, and automation wiring, but one default target points to the wrong repository and makes the core script unsafe by default. Workflow-level verification evidence is not attached in this branch, so rollout should be held until that default is corrected and one end-to-end dry run is captured. +EVIDENCE: + +1) Severity: High +- File/path: `.github/scripts/muw-review-lane.mjs` +- Evidence: `DEFAULT_REPO` is set to `Fearvox/EverOS` even though this repository remote is `EverMind-AI/EverOS`. +- Why it matters: Running the script without `--repo` can collect/post to the wrong project, creating data leakage risk and invalid review artifacts. +- Fix guidance: Change default to `EverMind-AI/EverOS` (or require explicit `--repo`) and add a guard that confirms current git remote matches the target repo before posting. + +2) Severity: Medium +- File/path: `.github/workflows/overnight-watch.yml`, `.github/workflows/linear-sync.yml`, `.github/workflows/sync-upstream.yml` +- Evidence: New automation workflows are introduced, but this branch does not provide a successful run artifact, dry-run log, or fixture-based script test proving safe behavior. +- Why it matters: These workflows can post comments/sync state automatically; missing proof increases risk of noisy or incorrect cross-system updates. +- Fix guidance: Attach one successful dry run per workflow (or script-level unit test evidence) in PR checks/comments before merge. + +3) Severity: Low +- File/path: `.github/ISSUE_TEMPLATE/pr_tracker.yml`, `.github/ISSUE_TEMPLATE/security_tracker.yml` +- Evidence: Templates are detailed and useful, but they introduce mandatory operational fields without a short onboarding note in CONTRIBUTING/docs. +- Why it matters: Contributors may submit incomplete triage data, reducing template effectiveness. +- Fix guidance: Add a short “how to use tracker templates” section in contributor docs with one minimal example. + +Residual verification gap: +- Confirm no credentials appear in generated context bundles after redaction by running the script against a test PR and scanning artifacts.