mirror of
https://github.com/garrytan/gstack.git
synced 2026-10-04 10:26:52 +02:00
* fix(freeze): hook reads the same state root /freeze writes — fails closed under GSTACK_HOME (#1459, #1509) check-freeze.sh resolved its state dir as ${CLAUDE_PLUGIN_DATA:-$HOME/.gstack} while every writer (/freeze, /guard, /unfreeze, /investigate) resolves through bin/gstack-paths, GSTACK_HOME first. With GSTACK_HOME set, /freeze wrote freeze-dir.txt under GSTACK_HOME, the hook read $HOME/.gstack, found no file, and allowed everything — a deny-tier boundary failing open. One resolver now: gstack_hook_state_root() in careful/bin/hook-extract.sh (already sourced by both check-freeze.sh and check-careful.sh) implements the exact gstack-paths chain, including the CLAUDE_PLUGIN_ROOT guard that keeps a CLAUDE_PLUGIN_DATA leaked from another plugin from redirecting our state. check-freeze.sh and gstack_hook_log_fire both call it; nothing spawns gstack-paths from a hook. Tests: the GSTACK_HOME deny regression, GSTACK_HOME-over-CLAUDE_PLUGIN_DATA precedence, plugin-root guard both ways, and a byte-parity check against bin/gstack-paths across six env combinations. Existing freeze tests now pass CLAUDE_PLUGIN_ROOT like a real plugin install would. Idea from PR #1509 (@NikhileshNanduri); implemented natively against the shared resolver rather than a second fallback chain. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(relink): never delete or link over a skill gstack does not own (#2119) gstack-relink runs on every ./setup. Its cleanup did `rm -rf` on any same-name entry whose SKILL.md was a symlink, with no readlink check, and its link step did `mkdir -p` then `ln -snf` onto any existing SKILL.md — on Linux that replaces a user's real file with a symlink into gstack (macOS refused by accident). setup's Windows mode-flip cleanup deleted any real dir whose name matched a gstack skill. A personal `qa` skill, or a fork installed under another path, was destroyed by the installer of a tool it never asked for. Ownership is now proven, never assumed. An entry is ours when it is a symlink resolving into INSTALL_DIR or RENDER_DIR, a real dir whose SKILL.md is such a symlink, or a real dir carrying the .gstack-owned marker setup now writes for Windows copy installs (legacy copies count when byte-identical to the source or carrying gen-skill-docs' AUTO-GENERATED header). Anything else — including an entry whose readlink fails — is foreign: left untouched, reported on stderr, and listed in relink's summary line. The same rule replaces setup's Windows name-match deletion; setup:1040 and gstack-uninstall:204 already gated on readlink, so this closes the last unguarded deleter of the class. Tests: foreign real dir in flat mode, foreign flat entry on a prefix flip, foreign directory symlink, RENDER_DIR-targeted entry (ours), marker-carrying copy (ours), marker-less copy (foreign); the Windows cleanup test now proves provenance three ways and keeps the user's own same-name skill. Idea and two regression cases from PR #2119 (@smblight); implemented on the destination entry, not only the symlink target. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(setup): Chromium bootstrap is best-effort and bounded — skills always register (#1900, #1901, #1902, #913, #2233) setup runs under `set -e`, and the Chromium bootstrap in section 2 sat ahead of skill registration in section 4 with a bare `bunx playwright install chromium`, an unbounded download, and an explicit `exit 1` after the post-install launch probe. On an offline, proxied, or AppArmor-restricted box the user ended with ZERO skills registered and a re-run that died at the same line; a wedged download hung setup indefinitely. Every browser failure now records a reason code in _PW_FAIL_REASON and setup continues: skipped (GSTACK_SKIP_PLAYWRIGHT=1, #913), chromium-install, chromium-install-timeout (the download is bounded by the existing _wait_with_deadline helper, default 600s, env GSTACK_PLAYWRIGHT_INSTALL_TIMEOUT, process tree killed via _kill_tree), chromium-install-locked (another setup holds the lock: this one registers skills and re-probes next time instead of exiting), windows-no-node, windows-node-modules, post-install-launch (with the GSTACK_CHROMIUM_NO_SANDBOX=1 hint for Ubuntu 24.04's userns policy, #2157). The daemon font refresh is skipped when Chromium is unavailable. The final summary names the skills that need the browser (/qa, /qa-only, /design-review, /browse, make-pdf, /pair-agent) and the fix for the recorded reason, and logs the reason code (never a path) through gstack-telemetry-log when telemetry is on. Tests: static invariants over the anchor-sliced block (no exit, every reason code, deadline helper, trap chaining, guarded refresh, summary contents) plus an integration harness that executes the real block with a stubbed probe and installer: install failure, hang killed at the deadline with the tree kill recorded, non-numeric knob fallback, live lock (continues, installer not run, lock preserved), stale lock reclaimed, post-install probe failure, and the skip flag. Credit @DavidMiserak (PR #1900) for the best-effort shape; re-implemented on the current block. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(designs): preserve the time-attack fork-port residual evaluation The read-only evaluation of what remains portable from time-attack/gstack (583 raw candidates, 415 canonical, 287 with a residual, 48 adversarially refuted, 14 standing) lived only on a throwaway VM. This records the report, the lite residual index, the absorbed/superseded ledger, the refuter verdicts, and SHAS.md with the fork tip, upstream HEAD, merge-base, and a sha256 per file, so every scheduled fix in this wave series traces to its evidence. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs: file the fork-port residual deferrals and document the Chromium bootstrap knobs TODOS.md gains the seven items the CEO and eng reviews of the fork-port residual plan deliberately deferred (shared ownership helper, config-key reader tripwire, "pre-existing" vocabulary, opt-in reply_language, .auth.json writer removal, the fork-derived-change rule for CONTRIBUTING, hook slug parity audit), each with rationale, and updates the two residual bullets for PR #2232 and PR #2233 with their dispositions. README's Troubleshooting section explains the best-effort Chromium bootstrap and its three knobs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(relink): canonicalize link targets before the ownership check Pre-landing review finding: the ownership gate compared readlink output textually against INSTALL_DIR and RENDER_DIR, so two shapes of gstack's OWN entries read as foreign and were left behind on a mode flip — a legacy relative link (`gstack/qa/SKILL.md`, resolved against $PWD instead of the link's directory) and an entry linked against the real path of a symlinked install dir (~/.claude/skills/gstack -> checkout). Both now resolve: relative targets anchor at the link's directory, the directory part is canonicalized with pwd -P (the basename stays verbatim so a dangling managed target is not misread), and both spellings of each root are accepted. Two regression tests. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(telemetry): one-shot setup events never sweep other sessions' pending markers gstack-telemetry-log finalizes every .pending-<session> marker that is not the caller's own as outcome:unknown and deletes it. setup's onboarding events (_setup_welcome, _setup_playwright) have no session of their own, so a Chromium bootstrap failure during a live skill session recorded a false unknown for that session and removed its marker. New --no-sweep flag skips the stale-marker pass; both setup call sites use it (the synthetic --session-id did not prevent the sweep). Surfaced by the Codex adversarial pass. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(hooks): partial upgrades fail closed for freeze and fall back for careful A hook script and its sourced helper can be copied at different times. With an older careful/bin/hook-extract.sh that lacks gstack_hook_state_root: - check-freeze.sh now emits a deny ("fail closed, re-run ./setup or /unfreeze") instead of dying under set -e with no decision JSON. - check-careful.sh falls back to ${GSTACK_HOME:-$HOME/.gstack} so project rules under the plain chain still load and a decision is always emitted (a warn hook must never break on a stale helper). gstack_hook_state_root prints its root without a trailing newline and both callers capture it with a printf-x sentinel, so a GSTACK_HOME ending in a newline round-trips byte-for-byte with the writer's %q form. gstack_hook_log_fire stays on ${GSTACK_HOME:-$HOME/.gstack}/analytics, the same two-step chain every other analytics writer and reader uses, so the usage log remains one file under a plugin install. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(setup): never link over, copy over, or reap a skill gstack does not own (#2119) The relink gate alone left three destructive sites open: - link_claude_skill_dirs runs BEFORE relink on every ./setup and used `ln -snf` (Linux replaces a user's real SKILL.md with a symlink into gstack) or, on Windows, rm -rf + cp followed by a marker that made the user's directory "ours" on the next flip. It and _install_alias_skill_md now consult _claude_entry_is_ours first and skip loudly. - cleanup_prefixed_claude_symlinks kept a bare name-match deletion and a `*gstack*` substring match. Symlink arms use anchored `gstack/` segment patterns; the Windows real-file arm proves provenance (marker, byte-identity with our source, or the full two-line gen-skill-docs banner within the first 40 lines, never a one-line substring another generator could emit). cleanup_old_claude_symlinks uses the same banner rule. - gstack-relink's fast path judged absolute targets before canonicalizing, so `/x/gstack/../foreign/SKILL.md` counted as ours; dot-segment targets now canonicalize first. Its banner rule matches setup's. The `.gstack-owned` marker records the owning payload's realpath. Entries skipped by setup or relink are listed in the final setup summary. Chromium bootstrap refinements from the pre-landing review: an INT/TERM trap kills the installer's process tree; the Windows npm chain no longer masks an install failure; GSTACK_SKIP_PLAYWRIGHT=1 is reported as a choice rather than a failure and sends no telemetry; the timeout knob is normalized (0, 000, non-numeric, or more than nine digits fall back to the 600s default instead of killing on the first poll or never killing). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs: README Chromium note outside the CLAUDE.md fence; report banner stripped; deferrals name the four gate sites - README: the Chromium troubleshooting paragraph sat inside the CLAUDE.md snippet code fence, so copy-paste put it into users' CLAUDE.md. Moved to the troubleshooting list. - docs/designs/fork-port-residual-2026-09/REPORT.md: the scratch-run preamble banner is gone; SHAS.md re-hashed. - TODOS: the ownership-gate deferral names the four sites and the marker-path idea for the fork-with-banner residual. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(todos): the bootstrap block coverage gap is pinned except the quarantine helper Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(setup,relink): ownership proof has two strengths; weak proof never deletes a directory or discards a differing file The first #2119 gate treated a byte-identical or banner-bearing real-file SKILL.md as full ownership, so a prefix flip could rm -rf a user's directory (their own qa skill started from a gstack SKILL.md, plus my-templates/) and the link pass could replace their customized file with a symlink. Two strengths now: - STRONG: the .gstack-owned marker (we created the directory), or a directory holding nothing but symlinks and the marker (deleting it loses no data). Only strong proof removes a directory whole. - WEAK: byte-identity with our source or the two-line gen-skill-docs banner on a real file. Weak proof covers that SKILL.md and our runtime-asset links only; a differing file is moved to ${GSTACK_HOME:-~/.gstack}/backups/skills/<ts>/<skill>/ before we link over it, and setup/relink print one summary line naming what moved. The marker is written on every platform now (path-independent proof for Windows copies and for checkouts whose path carries no gstack segment), but only for a directory gstack creates: a directory we merely link into (unclaimed, or a legacy install) never becomes deletable whole. A directory with no SKILL.md at all is unclaimed: the link pass may add our file, the cleanup pass has nothing to remove. Also from the review passes: the banner check reads 8192 bytes, not 40 lines (investigate, office-hours, plan-ceo-review and design-consultation carry the banner past line 40 and were left "foreign" on pre-marker Windows installs); a link into a checkout named without a gstack segment (git worktree add ../gstack-<branch>) is ours when that tree carries setup + VERSION + bin/; relink's fast path is gone so both files canonicalize before judging; relink's root alias (_gstack-command) is gated and stamped like every other entry; relink reports the bare entry name with setup's wording and setup dedupes when forwarding (_run_relink_quiet); the summary names the browser skills as examples. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(setup): Chromium-install lock reclaim is atomic and pid-validated; abandoned locks expire; the tree kill walks /proc without pgrep - A pid file holding "", "-1" or "0" counted as a live holder (kill -0 -1 signals every process and succeeds), locking Chromium out for good. A pid must be a positive integer; anything else is stale. - Two setups judging the same lock stale raced on rm -rf + mkdir and the loser deleted the winner's fresh lock. The stale dir is renamed first (atomic), so exactly one reclaims. - A lock dir with no pid file (killed between mkdir and echo) was never reclaimed; it now expires once older than the install bound. - _kill_tree needed pgrep; debian-slim and git-bash ship none, so the bound killed only the wrapper subshell and the installer kept running. Without pgrep the children are found by walking /proc/*/stat. - The timeout knob is normalized in one place with one comment; the trap's exit 130 is the only exit the block may contain. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(freeze): an unexpected non-zero death denies via an EXIT backstop instead of exiting with no decision set -e plus a failing pipeline (a tool on PATH exiting non-zero, a deleted cwd) ended the deny-tier hook with no JSON, which Claude Code treats as non-blocking: the edit outside the boundary proceeded. The EXIT trap now prints a deny for any non-zero exit that happens before a decision was written; every deliberate output sets _FREEZE_DECIDED first so a late failure never prints a second object. Tests also pin careful's state-root precedence (GSTACK_HOME over CLAUDE_PLUGIN_DATA, plugin data when CLAUDE_PLUGIN_ROOT names gstack) and the specific "out of date" deny for a helper without gstack_hook_state_root. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * refactor(telemetry): guard the stale-marker sweep with an if, not a break inside the loop Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(todos): the ownership gate lives in six sites, and the cleanup arms inline their own chain Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * test: the two remaining linker harnesses extract the ownership helpers; the marker is the one allowed dotfile setup-claude-skill-assets and user-render-out-dir-install slice link_claude_skill_dirs out of setup without the helpers it now calls, so the extracted function died with "command not found" (or, inside an if, degraded into "foreign, skipped"). Both harnesses now carry the full helper set and the globals. The hidden-files census allows .gstack-owned, which the linker writes for directories it creates rather than copying from the skill source. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(setup,relink): weak proof never costs the user a file — assets, flips, failed backups, foreign dir links, alias markers Third review cycle on the ownership model, every item reproduced against a fixture before the fix: - Runtime assets (sections/, templates/, checklist.md, ...) were refreshed with rm -rf regardless of who owned the directory, so an unclaimed or weakly-owned directory lost the user's same-named real files. Real assets are now replaced only in a directory gstack created or strongly owns (marker, or SKILL.md symlink into gstack), plus the legacy Windows real-copy shape; elsewhere they are kept and reported. Symlinks are never content and are always refreshed. - The prefix-flip cleanup deleted a customized banner-bearing SKILL.md that the link pass would have backed up. Both cleanups now compare the file against the source (raw, or with its name: line rewritten to the entry name, which is how alias and prefixed copies legitimately differ) and move a differing file to the backup root. - A failed backup (unwritable root) returned success and the caller linked over the file anyway. It now fails, and the entry is left untouched and reported. - A foreign DIRECTORY symlink whose target had no SKILL.md fell through to the "unclaimed directory" rule and was replaced by a real directory. A symlink that does not resolve into gstack is foreign, full stop. - The alias installers stamped .gstack-owned into pre-existing directories; they now follow the same created-or-already-marked rule. - A directory counts as "only links" only when every link resolves into gstack: a user's own symlink makes it mixed, so their link survives. - The gstack-tree heuristic requires bin/gstack-relink, not just a VERSION file, a setup script and a bin/ directory. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(setup): lock reclaim hands a fresh lock back; a live holder past the bound is stale; /proc walk strips through the last paren - Reclaim renamed the lock by path after judging it stale, so a second setup that had already reclaimed and re-created it lost its fresh lock and two installers ran. After the rename the moved directory's pid is re-read: a new live holder, or a fresh lock whose pid is not written yet, is moved straight back. - A pid file whose process is alive but whose lock is older than the install bound is stale too (the holder is past its own deadline, or the pid was recycled to an unrelated long-lived process); it was locked forever. - The /proc fallback stripped the comm field to the FIRST ") ", so a comm containing ") " hid a child from the kill. proc(5) says the last paren. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(freeze): mark the decision written after the helper prints, not before If gstack_hook_decision ever failed between the flag and its output the backstop would have stayed silent; setting the flag after the print keeps the deny backstop armed until a decision is actually on stdout. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * chore: bump version and changelog (v1.80.0.0) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs: update project documentation for v1.80.0.0 README troubleshooting + manual uninstall cover the skill ownership gate (.gstack-owned marker, ~/.gstack/backups/skills/<ts>/, foreign same-name skills left untouched). CLAUDE.md and CONTRIBUTING carry the ownership and best-effort Chromium bootstrap invariants for people editing setup and gstack-relink. PROJECT_STRUCTURE gains careful/, freeze/, guard/, unfreeze/, gstack-upgrade/, gstack-relink, and the setup/relink/hook test files. TESTING_INTERNALS documents the anchor-sliced setup harness convention. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(setup): the final summary reports customized SKILL.md files moved to the backup root The linker moved a weakly-proven, customized SKILL.md aside before linking over it but never said so; only relink printed a "Moved N" line, and by the time relink runs the file is already a symlink. The summary now names each moved file and where it went, next to the foreign-entry report. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * test: run assembled setup harness scripts from a temp file, not `bash -c` argv (Windows MSYS2 8 KB truncation) windows-free-tests (run 33907177851) failed in test/setup-alias-name-uniqueness.test.ts with bash: -c: line 178: unexpected EOF while looking for matching `' The harness slices functions out of `setup` and passed the joined script as one `bash -c` argv element. The ownership gate grew that script from 6.7 KB to 15.7 KB, and on Windows bash is an MSYS2 program: when its parent is a non-MSYS process (bun), msys-2.0.dll's build_argv() runs any argument containing `?*["'(){}` through globify()/glob(), which copies the pattern into a fixed `Char patbuf[8192]` and silently stops after 8192 - MB_CUR_MAX (8186 chars under C.UTF-8); GLOB_NOCHECK then returns the truncated text as the argument. Character 8186 lands inside the single-quoted sed token on line 178. Rebuilding the exact script with CI path shapes and cutting it at 8186-8190 characters reproduces the identical message locally; cmd.exe's 8191-UTF-16 cap and CreateProcess's 32767 do not fit the evidence. Fix: test/helpers/bash-script.ts writes the script to a temp file and runs `bash <path>` — a short glob-free argument that never enters globify. Every setup harness that assembled a script for `bash -c` (11 files, 22 sites) uses it; timeouts and env are preserved verbatim, spawn/timeout errors are appended to stderr, temp cleanup is best-effort. `spawnSync('bash', [<Windows absolute path>])` already passes on windows-latest in setup-help, uninstall-windows-copies and the migration tests. The Windows-curated list is byte-identical before and after. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs(test-free-shards): the rerun-refresh harness spawns bash <tempfile> via test/helpers/bash-script.ts, not bash -c Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
1 line
206 KiB
JSON
1 line
206 KiB
JSON
[{"id":"s9-skills-trivial-change-fast-path","title":"Trivial-change fast path in every dispatcher (one probe, no modules, no ceremony)","kind":"judgment-rule","refs":["3a8e1e90","a1470997"],"xref":"MISSING","residual":"Everything material is absent. Fork mechanism (0aca1f77:skills/{plan,qa,review,ship,debug}/SKILL.md 'Trivial-change fast path' sections + references/FAST-PATH.m\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":7,"fit":6,"port":"re-implement","cc":"~2-3 hours","files":["review/SKILL.md.tmpl","scripts/resolvers/review-army.ts"],"basis":"cross-reference MISSING"},{"id":"s9-skills-base-detection-local-only","title":"Shared BASE-DETECTION for local-only repos / non-origin remotes","kind":"fix","refs":["0e355635","10ee8530"],"xref":"PARTIAL","residual":"Fork mechanism (0aca1f77:skills/plan/references/BASE-DETECTION.md, byte-identical in qa/review/ship; test/skill-base-detection.test.ts): (a) resolve `<remote>` \u2026","rec":"TAKE","prio":"P1","val":7,"fit":9,"port":"adapt","cc":"~3-4 hours","files":["scripts/resolvers/utility.ts (generateBaseBranchDetect :21-60; generateQAMethodology :111-112)","scripts/resolvers/design.ts (:83 literal main)"],"basis":"cross-reference PARTIAL"},{"id":"s9-skills-verification-contract","title":"/plan Verification: line contract (VERIFICATION-CONTRACT.md)","kind":"judgment-rule","refs":["7da6b8f6","34c17af6"],"xref":"MISSING","residual":"The entire authoring-side contract: (1) a `Verification:` line in the plan-review family's output (plan-eng-review, plan-ceo-review, autoplan; office-hours/spec\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":7,"fit":7,"port":"re-implement","cc":"~3-4 hours","files":["plan-eng-review/sections/review-sections.md.tmpl (new 'Verification' output section after test diagram)","plan-eng-review/SKILL.md.tmpl"],"basis":"cross-reference MISSING"},{"id":"s9-skills-qa-never-probe-run-test-command","title":"/qa resolves project-owned test command from CLAUDE.md or asks; never probe-runs npm test","kind":"judgment-rule","refs":["a1470997","8f046e15"],"xref":"PARTIAL","residual":"The judgment rule itself is absorbed (read CLAUDE.md first \u2192 AskUserQuestion \u2192 persist to `## Testing`; never execute a candidate to 'check' it; never install a\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":4,"fit":9,"port":"adapt","cc":"~20 minutes","files":["test/skill-e2e-qa-ask-contract.test.ts (new, gate; adapted from fork 8f046e15)","test/helpers/touchfiles-data.ts"],"basis":"cross-reference PARTIAL"},{"id":"s9-skills-ship-hardcoded-test-lanes","title":"/ship Step 5/6 carries another project's commands (bin/test-lane, Rails, Ruby eval runner) \u2014 hardcode purge 8b\u2026","kind":"fix","refs":["8bc0a04f","d72133e1"],"xref":"MISSING","residual":"Fork replacement (0aca1f77:skills/ship/references/sections/ship/tests.md Step 5/6; legacy/ship.md:697-705 '#1102 overlay'): Step 5 \u2014 'Determine the project's te\u2026","rec":"TAKE","prio":"P1","val":8,"fit":10,"port":"adapt","cc":"~1-1.5 hours","files":["ship/sections/tests.md.tmpl (:9-21 Step 5, :44-113 Step 6)","ship/SKILL.md.tmpl (:381 evidence check label scheme)"],"basis":"cross-reference MISSING"},{"id":"s8-codediff-diff-scope-generic-prompt-globs","title":"gstack-diff-scope drops foreign Rails PROMPTS globs (944dcab2)","kind":"fix","refs":["944dcab2"],"xref":"MISSING","residual":"The glob replacement itself, in full: delete the five Rails-specific arms at bin/gstack-diff-scope:113-117 and replace with project-agnostic `*prompt*` and `*ev\u2026","rec":"TAKE","prio":"P2","val":3,"fit":9,"port":"adapt","cc":"10 minutes","files":["bin/gstack-diff-scope","test/diff-scope.test.ts"],"basis":"cross-reference MISSING"},{"id":"s8-codediff-taste-direction-aware-confidence","title":"gstack-taste-update direction-aware confidence for rejected prefs (#1776/#1777 code fix)","kind":"fix","refs":["944dcab2"],"xref":"MISSING","residual":"The entire fix: one-line change at bin/gstack-taste-update:201 plus tests. Fork test (944dcab2:test/taste-engine.test.ts, 'repeated rejections raise rejected-bu\u2026","rec":"TAKE","prio":"P1","val":6,"fit":10,"port":"cherry-pick","cc":"5-10 minutes","files":["bin/gstack-taste-update","test/taste-engine.test.ts"],"basis":"cross-reference MISSING"},{"id":"s3-judgment-build-scale-classification","title":"Build-scale classification (15 vectors \u2192 session/hobby/project/product/venture) (#886)","kind":"judgment-rule","refs":["fork PR #18 (merge c3dbec14, branch time-attack/planfix, v1.61.0.0)","fork PR #25 (merge 655e8239)"],"xref":"MISSING","residual":"Everything: (1) the fifteen-vector classifier text + 'highest tier wins / unknown vectors default low / never run a questioning round to classify' rules; (2) th\u2026","rec":"TAKE_PARTIAL","prio":"P1","val":7,"fit":6,"port":"re-implement","cc":"~2-3 hours","files":["scripts/resolvers/build-scale.ts (new {{BUILD_SCALE}} section resolver) + scripts/resolvers/index.ts","office-hours/SKILL.md.tmpl (Phase 1 step 5 mode answer \u2192 tier; 'Here's what I understand' output carries Scale line)"],"basis":"cross-reference MISSING"},{"id":"s3-judgment-time-constraint-caps-scale","title":"User-stated time constraint is a ceiling binding every chained skill","kind":"judgment-rule","refs":["fork PR #25 (merge 655e8239, commit d36338b5, branch time-attack/planslow)","5757efc6"],"xref":"MISSING","residual":"All three pieces: (1) the ceiling rule \u2014 an explicit user time constraint ('hackathon demo', a stated hour count, 'before my flight') caps scale at `session`; a\u2026","rec":"TAKE","prio":"P1","val":7,"fit":9,"port":"adapt","cc":"~20-30 min","files":["scripts/resolvers/preamble/generate-completeness-section.ts or a new generate-time-box.ts wired into preamble.ts tier>=2 list (the one-sentence directive)","office-hours/SKILL.md.tmpl:100-113 (capture the stated time box alongside the Hackathon/demo answer, not just the mode)"],"basis":"cross-reference MISSING"},{"id":"s9-skills-zero-question-budget-autonomy-dial","title":"Chain-wide question budget (scale-keyed 5/8/12 \u2192 zero default; /plan-tune autonomy dial is the only source)","kind":"judgment-rule","refs":["412f88bf","cef07a89"],"xref":"MISSING","residual":"Everything in the candidate is absent from upstream HEAD: (1) any chain-wide question counter or budget; (2) handoffs carrying scale / time box / questions-alre\u2026","rec":"TAKE_PARTIAL","prio":"P1","val":8,"fit":4,"port":"re-implement","cc":"~2-4h for the portable slice (one preamb\u2026","files":["scripts/resolvers/preamble/generate-question-budget.ts (new; or a paragraph appended in generate-ask-user-format.ts)","scripts/resolvers/preamble.ts (register the section after generateAskUserFormat, tier >= 2)"],"basis":"cross-reference MISSING"},{"id":"s9-skills-ask-only-uninferable","title":"SHARED-JUDGMENT clause 10: ask only what cannot be inferred; state defaults; never re-confirm a handoff","kind":"judgment-rule","refs":["5757efc6","cef07a89"],"xref":"MISSING","residual":"The general cross-skill clause is entirely absent: 'ask only what cannot be inferred after consulting prompt, repo, platform convention; infer the rest; state e\u2026","rec":"TAKE_PARTIAL","prio":"P1","val":7,"fit":7,"port":"re-implement","cc":"~30-45 min for the directive, tests, fix\u2026","files":["scripts/resolvers/preamble/generate-infer-first.ts (new: 'Ask only what cannot be inferred' directive, subordinate to explicit STOP gates; skipped when explainLevel is terse like the evidence directive)","scripts/resolvers/preamble.ts:107-115 (register alongside generateEvidenceDirective, tier >= 2)"],"basis":"cross-reference MISSING"},{"id":"s3-judgment-self-contained-questions","title":"Self-contained questions (#879): render referenced content as assistant text before asking","kind":"judgment-rule","refs":["fork PR #21 (merge c0a5d02e, branch time-attack/questions)","upstream issue #879 (OPEN; last comment 2026-07-15 by time-attack: 'The visibility bug remains, while #1116 is stale')"],"xref":"MISSING","residual":"Both layers: (1) the generalized rule (fork overlay GSTACK2_FIX_879, targets every skill) \u2014 before any AskUserQuestion or prose decision brief that asks the use\u2026","rec":"TAKE","prio":"P0","val":9,"fit":9,"port":"adapt","cc":"~30 min","files":["scripts/resolvers/preamble/generate-ask-user-format.ts (new 'Self-contained questions' paragraph in the Format section + a self-check bullet 'the content this question refers to is visible as assistant text above')","office-hours/SKILL.md.tmpl:214-222 (print PREMISES as assistant text, then confirm)"],"basis":"cross-reference MISSING"},{"id":"s3-judgment-plan-empty-target-fast-path","title":"/plan empty-target (greenfield) fast path via one ls -A probe","kind":"judgment-rule","refs":["fork PR #22 (merge b3e9c584, commit fa729353, branch time-attack/planfixe)","49b86878"],"xref":"MISSING","residual":"The whole fast path: (1) one cheap `ls -A` probe of the target directory BEFORE any reference/section read, Context Recovery, design-doc discovery, decision-sto\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":7,"port":"re-implement","cc":"~1 hour","files":["bin/gstack-skill-start (new cheap `REPO_EMPTY: yes|no` STATUS line next to FIRST_TASK)","scripts/resolvers/preamble/generate-context-recovery.ts or preamble.ts (one sentence: if REPO_EMPTY, say so in the first line and skip codebase-input phases)"],"basis":"cross-reference MISSING"},{"id":"s5-beta-build-handoff-go","title":"'Say go and I'll start building' handoff at /plan exit + mid-plan interrupt","kind":"feature","refs":["0aca1f77"],"xref":"MISSING","residual":"Everything: (a) the one-line exit build offer ('say **go** and I'll start building \u2014 or **keep planning**'); (b) 'go'/'build'/host plan-mode approval = affirmat\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":6,"port":"re-implement","cc":"~30-45 min","files":["office-hours/SKILL.md.tmpl","office-hours/sections/phase-2a-startup-diagnostic.md.tmpl"],"basis":"cross-reference MISSING"},{"id":"s3-judgment-session-start-code-intelligence-offer","title":"Session-start code-intelligence indexing offer (gstack-code-intelligence suggest)","kind":"feature","refs":["fork PR #23 (merge f9734a34, branch time-attack/index, v1.62.0.0)","4f646a5c"],"xref":"PARTIAL","residual":"The skill-side trigger and prose: (1) a once-per-invocation `gstack-code-intelligence suggest --json 2>/dev/null || true` step 'before substantive specialist wo\u2026","rec":"TAKE_PARTIAL","prio":"P1","val":6,"fit":8,"port":"adapt","cc":"~1-2 hours","files":["bin/gstack-skill-start (cheap `CODE_INTEL_OFFER: true|false|n/a` STATUS via `gstack-code-intelligence suggest --json`, interactive sessions only)","scripts/resolvers/code-intelligence-offer.ts (new {{CODE_INTELLIGENCE_OFFER}} or a tier>=3 preamble paragraph in scripts/resolvers/preamble.ts) + scripts/resolvers/index.ts"],"basis":"cross-reference PARTIAL"},{"id":"s8-codediff-update-check-repo-from-origin","title":"update-check/team-init derive repo slug from install's git origin (94e46742)","kind":"feature","refs":["94e46742","ddd54fd6"],"xref":"PARTIAL","residual":"Portable core still absent: (1) in bin/gstack-update-check, resolve REPO_SLUG from `git -C $GSTACK_DIR remote get-url origin` \u2192 `gstack-config get update_repo` \u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":7,"port":"adapt","cc":"45-60 minutes","files":["bin/gstack-update-check","bin/gstack-team-init"],"basis":"cross-reference PARTIAL"},{"id":"s8-codediff-browse-welcome-offline-fonts","title":"welcome.html system font stack \u2014 no Google Fonts/Fontshare egress (e1cd3096)","kind":"security","refs":["e1cd3096","e40cf170"],"xref":"MISSING","residual":"The whole change (fork e40cf170 / e1cd3096:browse/src/welcome.html, +9/-7): remove the two <link> tags at :7-8, add `--font-sans` (system UI stack) and `--font-\u2026","rec":"TAKE","prio":"P1","val":6,"fit":9,"port":"cherry-pick","cc":"10-15 minutes including the tripwire","files":["browse/src/welcome.html","test/egress-receipt-wiring.test.ts (or a new test/welcome-no-remote-assets.test.ts)"],"basis":"cross-reference MISSING"},{"id":"s8-codediff-iosqa-drop-resolve6-unicast-dns","title":"ios-qa: drop dns.resolve6 fallback leaking device hostname to unicast DNS","kind":"security","refs":["e1cd3096","a96b0458"],"xref":"MISSING","residual":"Entire change (fork a96b0458): delete `legacyResolve6` (devicectl.ts:52-66), the `legacyResolve` option (:230,:234) and step 3 (:244-246), leaving `return getDe\u2026","rec":"TAKE","prio":"P1","val":6,"fit":9,"port":"cherry-pick","cc":"15 minutes","files":["ios-qa/daemon/src/devicectl.ts","ios-qa/daemon/src/tunnel-bootstrap.ts"],"basis":"cross-reference MISSING"},{"id":"s4-fleet-codex-consent-and-redact-at-sink","title":"Outside-voice dispatch: redact scan-at-sink + per-repo Codex consent (overlays 9108/9109, 86864ce4)","kind":"security","refs":["86864ce4","bef056ca"],"xref":"MISSING","residual":"Everything in the fork's overlays 9108/9109 is missing. (a) Scan-at-sink before every outside-voice dispatch carrying repo content: review.ts sites :373,:537,:5\u2026","rec":"TAKE_PARTIAL","prio":"P1","val":8,"fit":9,"port":"adapt","cc":"~1.5-2 hours for scan-at-sink everywhere\u2026","files":["scripts/resolvers/redact-doc.ts","scripts/resolvers/review.ts"],"basis":"cross-reference MISSING"},{"id":"s7-docs-method-regression-pr2370-stdin-prompt-dispatch","title":"Codex/claude prompt over stdin, not argv (#2370 second half)","kind":"fix","refs":["evals/parity/regressions/pr-2370.json","docs/gstack-2/SKILL-CONTENT-CHECKLIST/README.md item 1"],"xref":"PARTIAL","residual":"Codex half is MISSING: two argv-cat dispatch sites \u2014 codex/sections/review-mode.md.tmpl:87 (custom-instructions review, prompt file contains the entire branch d\u2026","rec":"TAKE","prio":"P1","val":7,"fit":9,"port":"adapt","cc":"15-20 min","files":["codex/sections/review-mode.md.tmpl (line 87: `codex exec -s read-only - -c ... < \"$_PROMPT_FILE\" 2>\"$TMPERR\"`)","scripts/resolvers/review.ts (line 373, office-hours second opinion: `codex exec - -C ... < \"$CODEX_PROMPT_FILE\"`)"],"basis":"cross-reference PARTIAL"},{"id":"s1-prewave-setup-deploy-render-key-bytes","title":"setup-deploy: RENDER_API_KEY presence check instead of echoing 4 bytes (#1078/#1096)","kind":"security","refs":["fork PR #8 (b9d48195)","upstream issue #1096 (OPEN)"],"xref":"MISSING","residual":"Everything: (1) the template line at setup-deploy/SKILL.md.tmpl:104 (8-line change, regenerate SKILL.md); (2) the 33-line executable regression test that runs t\u2026","rec":"TAKE","prio":"P1","val":6,"fit":10,"port":"cherry-pick","cc":"10 min","files":["setup-deploy/SKILL.md.tmpl","setup-deploy/SKILL.md (regenerate via bun run gen:skill-docs)"],"basis":"cross-reference MISSING"},{"id":"s8-codediff-telemetry-log-input-integrity","title":"gstack-telemetry-log: missing-flag-value guard + categorical normalization (49bce83b)","kind":"fix","refs":["49bce83b","b79f41ee"],"xref":"PARTIAL","residual":"(1) Missing-value guard `--*) [ $# -ge 2 ] || exit 0 ;;` before the flag case (fork ref:49bce83b bin/gstack-telemetry-log). (2) skill_run categorical normalizat\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":4,"fit":8,"port":"adapt","cc":"15-20 min","files":["bin/gstack-telemetry-log","bin/gstack-telemetry-sync"],"basis":"cross-reference PARTIAL"},{"id":"s8-codediff-make-pdf-cjk-script-aware-stack","title":"make-pdf script-aware CJK font stack (#2012, 39f9030e)","kind":"fix","refs":["39f9030e"],"xref":"PARTIAL","residual":"Everything script-aware: `export type CjkVariant = 'sc'|'jp'|'kr'`, `detectCjkVariant(text)` (kana U+3040\u201330FF \u2192 jp; hangul U+AC00\u2013D7AF + jamo U+1100\u201311FF \u2192 kr;\u2026","rec":"TAKE","prio":"P2","val":6,"fit":9,"port":"cherry-pick","cc":"15 min","files":["make-pdf/src/print-css.ts","make-pdf/src/render.ts"],"basis":"cross-reference PARTIAL"},{"id":"s8-codediff-iosqa-session-cache-warm-start","title":"ios-qa session-cache.ts: persist rotated bearer across daemon restarts (#1796)","kind":"fix","refs":["e023fedc","549586cb (Autonomy AI, LLC / Bmathews721)"],"xref":"PARTIAL","residual":"(a) Persisted rotated-bearer warm start: session-cache.ts, `BootstrapOptions.sessionCachePath`, `BootstrapResult.warmStart`, probe-then-reuse before the boot-to\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":6,"port":"adapt","cc":"2-3 hours (logic is small; the cost is r\u2026","files":["ios-qa/daemon/src/session-cache.ts (new, from fork ref:origin/main)","ios-qa/daemon/src/tunnel-bootstrap.ts (warm probe before readBootToken; persist after rotate; keep relaunch-once path)"],"basis":"cross-reference PARTIAL"},{"id":"s7-docs-method-content-checklist-unported-issue-items","title":"SKILL-CONTENT-CHECKLIST item 7: /careful per-segment prose (#2039) \u2014 fork-hook specific","kind":"doc","refs":["docs/gstack-2/SKILL-CONTENT-CHECKLIST/README.md items 7-9","origin/main:docs/gstack-2/SKILL-CONTENT-CHECKLIST/README.md item 7"],"xref":"PARTIAL","residual":"Item 7: none (NOT_APPLICABLE \u2014 the fork's per-segment wording documents the FORK's tokenizer; upstream chose whole-command matching + anchored whitelist for #20\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":3,"fit":6,"port":"re-implement","cc":"10 min","files":["ios-qa/SKILL.md.tmpl (lines 123-124, 138-139, 255: replace 'install the SPM dependency' with the concrete `.package(path: \"DebugBridge\")` / Xcode 'Add Local Package' wiring line; keep upstream voice)","ios-qa/SKILL.md (regenerated)"],"basis":"cross-reference PARTIAL"},{"id":"gap5-hygiene-ios-qa-local-package-wording-1735","title":"#1735 ios-qa local DebugBridge package wording residue (e676a910) + first-run template fixes","kind":"doc","refs":["origin/main:docs/gstack-2/SKILL-CONTENT-CHECKLIST/README.md item 9","origin/main:docs/gstack-2/SKILL-CONTENT-CHECKLIST/03-ios-qa-module-instruction-SOURCE.patch"],"xref":"PARTIAL","residual":"(1) Three wording hunks from fork e676a910 still missing: ios-qa/SKILL.md.tmpl:123-124 should say 'generate the local DebugBridge package and wire it into Packa\u2026","rec":"TAKE_PARTIAL","prio":"P1","val":7,"fit":9,"port":"adapt","cc":"~10 min for wording/regen; +30 min for s\u2026","files":["ios-qa/SKILL.md.tmpl","ios-qa/SKILL.md (regen)"],"basis":"cross-reference PARTIAL"},{"id":"s1-prewave-skill-bash-fence-syntax-test","title":"Free test: bash -n (+ portability lint) over every ```bash fence in generated SKILL.md","kind":"test-infra","refs":["fork PR #5 (5826cdfd)","2d8d05fc"],"xref":"PARTIAL","residual":"(1) `bash -n` syntax pass over every ```bash block with placeholder normalization \u2014 catches `2/dev/null`, unclosed quotes/heredocs, stray parens that a fence-pa\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":9,"port":"adapt","cc":"20-30 min","files":["test/generated-docs-fences.test.ts (extend generatedDocs() to depth<=3 incl. openclaw/skills + browser-skills; add bash -n per-block test)","test/helpers/skill-parser.ts (add exported extractBashBlocks + normalizePlaceholders so TODOS.md:2415 ship-version-sync can reuse it)"],"basis":"cross-reference PARTIAL"},{"id":"gap5-hygiene-benchmark-production-boundary","title":"Boundary tripwire: bin/ and lib/ must never import test/ helpers (benchmark CLI)","kind":"test-infra","refs":["9919c4cd","36f972f2"],"xref":"MISSING","residual":"Everything. Portable piece A (small): move test/helpers/{benchmark-runner,benchmark-judge,pricing,providers/*} \u2192 lib/model-benchmark/, leave re-export shims in \u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":9,"port":"adapt","cc":"~15-20 min (piece A)","files":["bin/gstack-model-benchmark","lib/model-benchmark/benchmark-runner.ts (moved from test/helpers)"],"basis":"cross-reference MISSING"},{"id":"s4-fleet-persona-fleet-harness","title":"Persona-fleet hostile-user harness methodology (evals/fleet METRICS/ABANDONMENT, deferred in TODOS)","kind":"methodology","refs":["3ebde802","6565c194"],"xref":"MISSING","residual":"Deferred, not built. Sub-ideas in the fork docs that the TODO text does NOT carry and would be lost if the TODO is the only record: (1) every recorded metric is\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":6,"fit":6,"port":"methodology-only","cc":"Enrichment: ~10 min. Four safety E2Es: ~\u2026","files":["TODOS.md (P2 persona-fleet entry :269-285 \u2014 append the ten rules as a 'Lessons the fork paid for' sub-list)","docs/designs/ (optional decision record PERSONA_FLEET_METRICS.md capturing METRICS/ABANDONMENT rules in upstream voice)"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-askuserquestion-compact-payload-1241","title":"AskUserQuestion payload caps: brief in markdown, compact tool payload (#1241 / QUESTION-FORMAT.md)","kind":"judgment-rule","refs":["f708f508 (Jayesh Betala / jbetala7)","upstream PR #1241 OPEN (jbetala7); issue #1208 OPEN"],"xref":"MISSING","residual":"All of fork f708f508 (author Jayesh Betala / @jbetala7, 2026-06-17): the one-sentence two-part contract at Format, the 4-bullet 'Tool payload rules' block, the \u2026","rec":"TAKE","prio":"P1","val":8,"fit":8,"port":"cherry-pick","cc":"~15 min + eval run","files":["scripts/resolvers/preamble/generate-ask-user-format.ts","test/resolver-ask-user-format.test.ts"],"basis":"cross-reference MISSING"},{"id":"gap6-s15-hostadv-ui-launch-cell-method","title":"Host-adversarial harness with per-host adapters (codex/claude/cursor/pi UI-launch cells)","kind":"test-infra","refs":["bb681bec","70739826"],"xref":"PARTIAL","residual":"Portable, host-neutral pieces upstream lacks: (a) a `permissionMode?: 'plan'` option on runSkillTest in test/helpers/session-runner.ts that omits `--dangerously\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":7,"port":"re-implement","cc":"~30 min","files":["test/helpers/session-runner.ts (permissionMode option; optionally join tool_result into toolCalls[].output)","test/helpers/read-events.ts (new: extractReadEvents joining tool_use->tool_result by tool_use_id)"],"basis":"cross-reference PARTIAL"},{"id":"s8-codediff-memory-ingest-default-secret-gate","title":"memory-ingest default-ON redact-engine scan over staged bytes (8201a56c)","kind":"security","refs":["8201a56c"],"xref":"MISSING","residual":"The entire change (ref:8201a56c bin/gstack-memory-ingest.ts, test/gstack-memory-ingest.test.ts): import `{ scan, exitCodeFor }` from lib/redact-engine; CliArgs \u2026","rec":"TAKE","prio":"P1","val":7,"fit":8,"port":"adapt","cc":"45 min","files":["bin/gstack-memory-ingest.ts (import scan/exitCodeFor/applyRedactions; CliArgs noScanSecrets/ackMedium; parseArgs + env; help; gate in preparePages before staging; rewrite :29 header and :1380-1394 policy comment)","test/gstack-memory-ingest.test.ts (default refuses HIGH, MEDIUM redacted/acked, --no-scan-secrets admits all)"],"basis":"cross-reference MISSING"},{"id":"s8-codediff-make-pdf-preview-offline-gate","title":"make-pdf preview blocks remote <img> behind --allow-network (8fae162d)","kind":"security","refs":["8fae162d"],"xref":"MISSING","residual":"The whole change (ref:8fae162d make-pdf/src/diagram-prepass.ts, make-pdf/src/orchestrator.ts, make-pdf/test/diagram-prepass.test.ts): `export function blockRemo\u2026","rec":"TAKE","prio":"P1","val":6,"fit":10,"port":"cherry-pick","cc":"10 min","files":["make-pdf/src/diagram-prepass.ts (export blockRemoteImages reusing IMG_TAG_RE/SRC_RE/buildBlockedRemotePlaceholder)","make-pdf/src/orchestrator.ts (preview(): gate rendered.html unless opts.allowNetwork === true)"],"basis":"cross-reference MISSING"},{"id":"s9-skills-review-small-diff-sweep-hole","title":"/review: six checklist categories delegated to subagents that small diffs skip \u2014 coverage hole","kind":"judgment-rule","refs":["80a15040","46973af5"],"xref":"MISSING","residual":"The entire fix is missing: (1) remove the 'handled by parallel subagents, NOT this checklist' escape hatch from review/checklist.md:10; (2) add a Pass 3 SWEEP s\u2026","rec":"TAKE","prio":"P0","val":9,"fit":9,"port":"adapt","cc":"~30-45 min for prose + free test + regen\u2026","files":["review/checklist.md:10 (delete the 'handled by parallel subagents, NOT this checklist' line), :82 (Dead Code note), new '### Pass 3 \u2014 SWEEP' section adapted from 0aca1f77:skills/review/references/artifacts/review/checklist.md:127-160, :127-136 severity table (add SWEEP column / Access Control under CRITICAL)","review/SKILL.md.tmpl:127-131 (Step 4 names Pass 3 categories and the 'run yourself when no specialist covered it' rule), :292 (log honesty note)"],"basis":"cross-reference MISSING"},{"id":"s5-beta-brain-sync-hermetic-test","title":"brain-sync test hermetic: stubbed gh/glab/gbrain, fake HOME (51093791)","kind":"test-infra","refs":["51093791"],"xref":"PARTIAL","residual":"(1) PATH-head fail-fast stubs for gh, glab, gbrain in test/brain-sync.test.ts (fork 51093791: STUB_BIN mkdtemp with `#!/bin/sh\\nexit 1`, prepended to PATH in a \u2026","rec":"TAKE","prio":"P2","val":4,"fit":9,"port":"adapt","cc":"~15 min","files":["test/brain-sync.test.ts"],"basis":"cross-reference PARTIAL"},{"id":"s7-docs-method-egress-audit-method-and-residuals","title":"EGRESS-AUDIT.md per-call-site egress audit method + residuals","kind":"doc","refs":["docs/gstack-2/EGRESS-AUDIT.md","evals/privacy/README.md"],"xref":"PARTIAL","residual":"(a) The audit DOCUMENT/method is missing: upstream has the receipt ledger + sink-list tripwire + `gstack-egress grants`, but no per-call-site table (Call site |\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":7,"port":"re-implement","cc":"2-3 hours (fixes 20 min; doc + tripwire \u2026","files":["browse/src/welcome.html (lines 7-8: drop fonts.googleapis/api.fontshare links, system font stack; keep design)","make-pdf/src/orchestrator.ts (preview(): apply allowNetwork gate / neutralize remote <img> as print path does at :167-175)"],"basis":"cross-reference PARTIAL"},{"id":"s7-docs-method-capability-readiness-doctor","title":"gstack doctor --capability five-state readiness probe (CAPABILITY-READINESS.md)","kind":"tooling","refs":["docs/gstack-2/CAPABILITY-READINESS.md","2e1e52ea"],"xref":"MISSING","residual":"Everything: (1) a non-mutating `bin/gstack-doctor --capability browser|ios|pdf|design|diagram [--json]` CLI; (2) the five-axis report shape \u2014 judgment (always '\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":7,"port":"re-implement","cc":"~1.5-2 hours (bin/gstack-doctor + state-\u2026","files":["bin/gstack-doctor (new; --capability browse|ios|pdf|design|diagram|gbrain|codex|gemini|egress [--json] [--strict])","test/gstack-doctor.test.ts (new; pins the five-state matrix, exit 0/1/2 polarity, ios-on-linux=unsupported, ok only for ready|degraded, hard failure maps to failed)"],"basis":"cross-reference MISSING"},{"id":"gap5-hygiene-codex-ship-qa-only-path","title":"Codex host pathRewrite so /ship can load /qa-only (#1772)","kind":"fix","refs":["0e66478b (origin/backup/pre-isolated-wave-review-2026-07-14)","garrytan/gstack PR #1772 (OPEN since 2026-05-28, by @spacegeologist; files hosts/codex.ts, test/gen-skill-docs.test.ts)"],"xref":"MISSING","residual":"Entire fix is missing: (1) the hosts/codex.ts pathRewrite `${CLAUDE_SKILL_DIR}/../qa-only/SKILL.md` \u2192 `$GSTACK_ROOT/../gstack-qa-only/SKILL.md`; (2) the gen-ski\u2026","rec":"TAKE","prio":"P1","val":6,"fit":9,"port":"adapt","cc":"~30 min","files":["hosts/codex.ts","hosts/factory.ts"],"basis":"cross-reference MISSING"},{"id":"s1-prewave-team-hook-cross-platform-cjs","title":"Team-mode enforcement hook as cross-platform .cjs launcher (#2229 roll-up)","kind":"fix","refs":["e81dc23d","472f1b3d"],"xref":"MISSING","residual":"(1) Shell-neutral launcher: .cjs hook + `node -e` command so required-mode enforcement runs on Windows/PowerShell hosts without Git Bash on PATH (today a missin\u2026","rec":"TAKE_PARTIAL","prio":"P1","val":7,"fit":6,"port":"adapt","cc":"1-2 hours","files":["bin/gstack-team-init (hook body -> .cjs with #2500 multi-root list; launcher command; matcher 'Skill|skill'; rerun migration removing legacy check-gstack.sh and rewriting existing matcher entries)","test/team-mode.test.ts (replace .sh assertions; port fork tests :327-640 incl. win32-gated PowerShell lanes)"],"basis":"cross-reference MISSING"},{"id":"s1-prewave-bug-report-skill","title":"/bug-report skill (upstream PR #2235 OPEN)","kind":"feature","refs":["e9e32c3c","d1a9491e"],"xref":"MISSING","residual":"The entire skill and its wiring: bug-report/SKILL.md.tmpl (+ generated SKILL.md), the redact-doc `retain` argument (independently useful: today every sink's blo\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":7,"fit":5,"port":"adapt","cc":"2-3 hours","files":["scripts/resolvers/redact-doc.ts (add `retain` arg \u2014 take FIRST and independently; also apply to spec/sections/gate-and-file.md.tmpl:47 pre-codex, whose full-form block currently rm's $REDACT_FILE before the downstream write is described)","test/redact-doc-resolver.test.ts"],"basis":"cross-reference MISSING"},{"id":"s1-prewave-terminal-ws-extension-id-pin","title":"Terminal-agent WS pinned to shipped extension ID, fail closed (#2226 roll-up; other #2226 pieces separate)","kind":"security","refs":["7b3f391b","time-attack/harden-pr-env-health-test"],"xref":"MISSING","residual":"For the pin itself (this candidate): (1) import the manifest-derived constant into terminal-agent.ts instead of `process.env.BROWSE_EXTENSION_ID || ''`; (2) mak\u2026","rec":"TAKE","prio":"P1","val":6,"fit":9,"port":"adapt","cc":"15 min","files":["browse/src/extension-identity.ts (new: GSTACK_EXTENSION_ID constant moved here; keep derivation comment + `bun browse/scripts/extension-id.ts` reproduce note)","browse/src/server.ts (re-export GSTACK_EXTENSION_ID from extension-identity.ts)"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-setup-no-browser-flag-654","title":"./setup --no-browser flag with persisted no_browser config (#654)","kind":"feature","refs":["2f4ea487 (Jim McKeeth / jimmckeeth)","bbad1bab (t) setup hunks"],"xref":"MISSING","residual":"Everything: --no-browser (+ --nobrowser/--nobrowse/--no-browse aliases) and --with-browser flags; CLI > saved `no_browser` config precedence with persistence vi\u2026","rec":"TAKE","prio":"P2","val":6,"fit":7,"port":"re-implement","cc":"~1.5 hours","files":["setup","bin/gstack-config"],"basis":"cross-reference MISSING"},{"id":"gap3-setup-windows-powershell-bootstrap","title":"setup.ps1 Windows prerequisite bootstrap (#657 + PS 5.1 fix)","kind":"feature","refs":["bcf48a4a (Jim McKeeth / @jimmckeeth, #657)","73301bf6"],"xref":"MISSING","residual":"The whole 184-line setup.ps1: `#Requires -Version 5.1`; winget presence check with Store guidance; Update-SessionPath (registry PATH refresh); Install-Prereq fo\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":5,"fit":6,"port":"re-implement","cc":"~1 hour plus one windows-latest CI itera\u2026","files":["setup.ps1 (new)","README.md (Windows section ~:529-531)"],"basis":"cross-reference MISSING"},{"id":"gap3-statusline-last-gstack-skill","title":"bin/gstack-statusline Claude Code status bar (#2049 + fork hardening)","kind":"feature","refs":["217335ae (theRealProHacker)","20aece42"],"xref":"MISSING","residual":"Entire feature: bin/gstack-statusline (reads Claude's JSON status payload; --full appends the last gstack skill to dir/branch/model, --skill prints only the ski\u2026","rec":"TAKE","prio":"P2","val":6,"fit":7,"port":"re-implement","cc":"~2 hours","files":["bin/gstack-statusline (new)","bin/gstack-settings-hook"],"basis":"cross-reference MISSING"},{"id":"gap3-benchmark-ollama-adapter","title":"OllamaAdapter for gstack-model-benchmark (#1495)","kind":"feature","refs":["fd4a68cb (SyncroAgency, #1495)","f0307dce (Grok-or-skip judge)"],"xref":"MISSING","residual":"Everything: test/helpers/providers/ollama.ts (fetch to /api/tags for availability, /api/generate for run, GSTACK_OLLAMA_URL/GSTACK_OLLAMA_MODEL overrides, Abort\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":7,"port":"cherry-pick","cc":"30-45 min","files":["test/helpers/providers/ollama.ts","test/helpers/providers/types.ts"],"basis":"cross-reference MISSING"},{"id":"gap3-catalog-trim-external-hosts","title":"gen-skill-docs catalog trim applied to external hosts (#1972)","kind":"fix","refs":["2a3c2643 (hadrien-de-march, #1972)","2a3c2643 (hadrien-de-march)"],"xref":"MISSING","residual":"(1) Drop the `host === 'claude' &&` half of the gate at gen-skill-docs.ts:911 and update the comment; (2) replace test/gen-skill-docs.test.ts:2034-2044 with the\u2026","rec":"TAKE","prio":"P1","val":7,"fit":9,"port":"adapt","cc":"30 min","files":["scripts/gen-skill-docs.ts","test/gen-skill-docs.test.ts"],"basis":"cross-reference MISSING"},{"id":"gap3-terse-render-in-user-installs","title":"Honor explain_level=terse at render time for user installs (#1993)","kind":"feature","refs":["bbbd9cab (maxpetrusenkoagent, #1993)","bbbd9cab (maxpetrusenkoagent)"],"xref":"PARTIAL","residual":"(1) gen-skill-docs.ts: when --explain-level is absent AND --respect-detection is on, read `explain_level: terse` from ${GSTACK_HOME:-~/.gstack}/config.yaml (for\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":4,"fit":6,"port":"re-implement","cc":"1-2 hours","files":["scripts/gen-skill-docs.ts","setup"],"basis":"cross-reference PARTIAL"},{"id":"gap2-skillwave-plan-eng-optimistic-ui-server-gated-1874","title":"plan-eng-review: optimistic UI on server-gated actions check (#1874)","kind":"judgment-rule","refs":["68af5ad6 (Tim Linnet / timlinnet)","upstream PR #1874 OPEN (timlinnet)"],"xref":"MISSING","residual":"The single bullet: '* Server-gated or actuated actions with optimistic UI\u2014does the client await and surface the real result, or assume success? A swallowed reje\u2026","rec":"TAKE","prio":"P2","val":6,"fit":10,"port":"cherry-pick","cc":"5 min","files":["plan-eng-review/sections/review-sections.md.tmpl","plan-eng-review/sections/review-sections.md"],"basis":"cross-reference MISSING"},{"id":"s1-prewave-readme-update-check-disclosure","title":"README privacy disclosure of hourly VERSION fetch + update_check opt-out (#1083)","kind":"doc","refs":["411b6060","upstream PR #1083 (OPEN)"],"xref":"PARTIAL","residual":"The README privacy bullet itself (one line). Upstream still does not tell privacy-conscious readers that (a) a network call to GitHub fires ~hourly even with te\u2026","rec":"TAKE","prio":"P1","val":6,"fit":10,"port":"adapt","cc":"5 min (10 min if also adding the grants \u2026","files":["README.md (Privacy & Telemetry section, ~line 500-508)","bin/gstack-egress (grants array, ~155-190; optional)"],"basis":"cross-reference PARTIAL"},{"id":"s1-prewave-review-loosened-inputs-stale-strings","title":"/review: trace loosened inputs into unchanged consumers + stale user-facing strings (#2141)","kind":"judgment-rule","refs":["2e369533","upstream PR #2141 (OPEN)"],"xref":"MISSING","residual":"Everything: (1) the widened-input clause on Enum & Value Completeness ('\u2014 OR loosens what an input accepts (a newly-accepted MIME type, file extension, or flag;\u2026","rec":"TAKE","prio":"P1","val":7,"fit":10,"port":"cherry-pick","cc":"15 min","files":["review/checklist.md (:63-68 Enum & Value Completeness clause + new bullet; new '#### Stale User-Facing Strings' under Pass 2; severity diagram :125-135)","review/SKILL.md.tmpl (:132 INFORMATIONAL list; :134 heading reference if renamed)"],"basis":"cross-reference MISSING"},{"id":"s2-runtime-scorecard-workflow","title":"OpenSSF Scorecard workflow","kind":"ci","refs":["09492d34",".github/workflows/scorecard.yml"],"xref":"MISSING","residual":"Entire artifact missing: .github/workflows/scorecard.yml (fork 09492d34: branch_protection_rule + weekly cron + push-to-main triggers; top-level contents:read; \u2026","rec":"TAKE","prio":"P2","val":5,"fit":8,"port":"adapt","cc":"~10 min for workflow + tripwire; first-r\u2026","files":[".github/workflows/scorecard.yml (new; refresh SHAs for actions/checkout, ossf/scorecard-action, github/codeql-action/upload-sarif, actions/upload-artifact)","test/workflow-hardening.test.ts (new, or fold into the s2-runtime-workflow-hardening-tripwire-test port: assert ossf/scorecard-action@ present, upload-sarif@ present, publish_results: false, no id-token: write)"],"basis":"cross-reference MISSING"},{"id":"s7-docs-method-workflow-sha-pins-and-permissions","title":"SHA-pin every action + top-level permissions: contents: read in all workflows","kind":"ci","refs":[".github/workflows/version-gate.yml (fork)",".github/workflows/pr-title-sync.yml (fork)"],"xref":"PARTIAL","residual":"(1) 18 tag-only `uses:` refs across 9 workflows (list above) need `@<40-hex> # vN` \u2014 most notably pr-title-sync.yml:43, which runs under pull_request_target wit\u2026","rec":"TAKE","prio":"P1","val":5,"fit":9,"port":"adapt","cc":"~15-20 minutes","files":[".github/workflows/actionlint.yml:26",".github/workflows/free-tests.yml:55,59,70"],"basis":"cross-reference PARTIAL"},{"id":"s7-docs-method-agents-md-cursor-cloud-gotcha","title":"Fork PR #55 AGENTS.md Cursor Cloud notes incl. injected git-signing gotcha","kind":"doc","refs":["time-attack/gstack#55","origin/cursor/setup-dev-environment-2c04"],"xref":"PARTIAL","residual":"(1) Documentation: no Cursor Cloud (or generic 'injected global gitconfig') note anywhere \u2014 the Bun path, Playwright cache path + version-matched reinstall comm\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":8,"port":"re-implement","cc":"~30-40 minutes","files":["test/diff-scope.test.ts:21-31 (route createRepo through test/helpers/scratch-repo.ts gitArgvIn or add -c commit.gpgsign=false -c core.fsmonitor=false)","test/gstack-version-bump.test.ts (5 raw commits)"],"basis":"cross-reference PARTIAL"},{"id":"s7-docs-method-backlog-map-triage-generator","title":"BACKLOG-MAP.json offline issue/PR triage map + generator","kind":"tooling","refs":["docs/gstack-2/BACKLOG-MAP.json","docs/gstack-2/BASELINE.md (Backlog baseline)"],"xref":"MISSING","residual":"The whole artifact is absent, but most of it should stay absent: (a) an offline, deterministic generator (ce37bd36:scripts/gstack2/generate-backlog-map.ts, 810 \u2026","rec":"SKIP","prio":"P3","val":2,"fit":3,"port":"methodology-only","cc":"n/a (if vocabulary only: 5 minutes)","files":["TODOS.md:43-51 (optional: add a disposition tag per queued PR)","CONTRIBUTING.md:531-546 (optional: name the disposition vocabulary in step 1 'Categorize')"],"basis":"cross-reference MISSING"},{"id":"s8-codediff-browse-network-settle-500ms","title":"Cap implicit post-action networkidle wait at 500ms (NETWORK_SETTLE_MS, 5afc7c47)","kind":"fix","refs":["5afc7c47"],"xref":"MISSING","residual":"Everything: the exported constant (fork browse/src/commands.ts:18 `NETWORK_SETTLE_MS = 500`), its use at the three write-command sites and the chain end-of-writ\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":7,"port":"adapt","cc":"20 min","files":["browse/src/commands.ts","browse/src/write-commands.ts"],"basis":"cross-reference MISSING"},{"id":"s8-codediff-browse-watch-memory-bound","title":"Watch mode retains last snapshot + count instead of unbounded array (5afc7c47)","kind":"fix","refs":["5afc7c47"],"xref":"MISSING","residual":"Both sub-pieces: (a) BrowserManager retention change \u2014 `lastWatchSnapshot: string | null` + `watchSnapshotCount`, `stopWatch()` returning `{count, last, duratio\u2026","rec":"TAKE","prio":"P2","val":5,"fit":9,"port":"cherry-pick","cc":"10 min","files":["browse/src/browser-manager.ts","browse/src/meta-commands.ts"],"basis":"cross-reference MISSING"},{"id":"s8-codediff-browse-click-missing-selector-no-second-wait","title":"click on missing selector avoids second 5s auto-wait in error path (a84a6e23)","kind":"fix","refs":["a84a6e23"],"xref":"MISSING","residual":"The whole fix: `optionLocator` extraction, `optionLocator.count().catch(() => 0)`, evaluate only when `optionCount === 1` (fork browse/src/write-commands.ts:358\u2026","rec":"TAKE","prio":"P1","val":7,"fit":9,"port":"cherry-pick","cc":"10 min","files":["browse/src/write-commands.ts","browse/test/commands.test.ts"],"basis":"cross-reference MISSING"},{"id":"s8-codediff-browse-shutdown-revoke-token-first","title":"Daemon shutdown revokes browse.json first and 503s new requests (cb533516)","kind":"security","refs":["cb533516","4a8833cc"],"xref":"MISSING","residual":"(1) `acceptingRequests` gate flipped before the first await and consulted by `validateAuth`; (2) 503 `{error:'Shutting down'}` + `Connection: close` short-circu\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":6,"port":"re-implement","cc":"1.5 hours","files":["browse/src/server.ts","browse/src/cli.ts"],"basis":"cross-reference MISSING"},{"id":"s8-codediff-browse-path-security-dangling-symlink","title":"validateOutputPath fails closed on dangling symlinks (f14445bb)","kind":"security","refs":["f14445bb"],"xref":"MISSING","residual":"The full restructure (fork browse/src/path-security.ts:36-62 in f14445bb): `lstatSync` in its own try (ENOENT only means the output file does not exist), then `\u2026","rec":"TAKE","prio":"P1","val":6,"fit":9,"port":"cherry-pick","cc":"10 min","files":["browse/src/path-security.ts","browse/test/path-validation.test.ts"],"basis":"cross-reference MISSING"},{"id":"s8-codediff-iosqa-proxy-timeout-hardening","title":"ios-qa proxyToDevice: timeout destroys socket, settle guard, 502 on unknown (2c487305)","kind":"fix","refs":["2c487305"],"xref":"MISSING","residual":"Everything: (1) req.on('timeout') that resolves 504 upstream_timeout then req.destroy(); (2) `settled` guard so the post-destroy 'error' event is ignored; (3) r\u2026","rec":"TAKE_PARTIAL","prio":"P1","val":7,"fit":9,"port":"adapt","cc":"~15 minutes","files":["ios-qa/daemon/src/proxy.ts","ios-qa/daemon/test/proxy-classify.test.ts"],"basis":"cross-reference MISSING"},{"id":"s8-codediff-iosqa-devicectl-typed-errors-hwudid","title":"devicectl listDevices typed errors + hardware-UDID matching (2c487305 bridge-reliability roll-up)","kind":"fix","refs":["2c487305"],"xref":"MISSING","residual":"All of it: DeviceListResult typed union with three failure kinds (ENOENT vs non-zero exit with stderr preserved vs malformed JSON / missing identifier), the thr\u2026","rec":"TAKE","prio":"P1","val":7,"fit":8,"port":"adapt","cc":"~25 minutes","files":["ios-qa/daemon/src/devicectl.ts","ios-qa/daemon/src/tunnel-bootstrap.ts"],"basis":"cross-reference MISSING"},{"id":"s8-codediff-iosqa-active-bundle-assertion","title":"x-gstack-expected-bundle-id per-mutation guard, 409 on mismatch (2c487305)","kind":"security","refs":["2c487305"],"xref":"PARTIAL","residual":"Skeptic found missing pieces: Per-mutation bundle guard mechanism is entirely absent from upstream (verified, not disputed): no `x-gstack-expected-bundle-id` he\u2026","rec":null,"prio":null,"val":null,"fit":null,"port":null,"cc":"","files":[],"basis":"xref-absorbed, flipped by skeptic"},{"id":"gap4-s13-ios-xcuitest-physical-device-harness","title":"physical-device-smoke.ts real-iPhone evidence harness","kind":"test-infra","refs":["b6572ebb","7d760ff1"],"xref":"MISSING","residual":"Everything except the bare deploy flow: (1) typed failure taxonomy \u2014 HarnessError with 38 HarnessErrorCode values and setup_gate|safety_refusal|product_failure \u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":7,"port":"adapt","cc":"2-4 hours of CC for the port + free-suit\u2026","files":["ios-qa/scripts/physical-device-smoke.ts (new; from origin/main:ios-qa/scripts/physical-device-smoke.ts, evidence sink and bundle id changed)","test/skill-e2e-ios-device.test.ts (refactor deploy lane to import the harness; move the ~11 pure-TS checks to a free-suite file)"],"basis":"cross-reference MISSING"},{"id":"gap5-hygiene-chromium-path-status-correction","title":"GSTACK_CHROMIUM_PATH honored for headless launch (headed already upstream)","kind":"feature","refs":["e3effb3f","a84a6e23"],"xref":"PARTIAL","residual":"(d) Headless launch() does not honor GSTACK_CHROMIUM_PATH: fork's configuredChromiumExecutable() (trimmed env) feeds executablePath into both launch() (fork bro\u2026","rec":"TAKE","prio":"P1","val":5,"fit":9,"port":"adapt","cc":"20-30 minutes","files":["browse/src/browser-manager.ts (launch(): read+trim GSTACK_CHROMIUM_PATH, spread executablePath, scope heal, guard --load-extension; rewrite :523-527 comment)","browse/src/proxy-config.ts (computeConfigHash: optional browserExecutable, included only when set)"],"basis":"cross-reference PARTIAL"},{"id":"s8-codediff-gstack-home-state-dir-consistency","title":"GSTACK_HOME honored as state root in update-check, telemetry-log, gstack-detach, codex-probe","kind":"fix","refs":["b6572ebb","94e46742"],"xref":"MISSING","residual":"All four fork edits are absent: (1) gstack-update-check STATE_DIR precedence GSTACK_HOME \u2192 GSTACK_STATE_DIR \u2192 ~/.gstack; (2) gstack-telemetry-log same, plus ins\u2026","rec":"TAKE","prio":"P1","val":5,"fit":10,"port":"re-implement","cc":"~10 minutes","files":["bin/gstack-update-check","bin/gstack-telemetry-log"],"basis":"cross-reference MISSING"},{"id":"s9-skills-execution-depth-profiles","title":"Execution depth profiles (readiness/standard/deep) inferred from risk signals (EXECUTION-PROFILES.md)","kind":"judgment-rule","refs":["a1b2b05a","fea43565"],"xref":"MISSING","residual":"All three layers are absent: (a) the depth vocabulary and inference rules \u2014 readiness/standard/deep chosen from product stage, mutation authority, risk/evidence\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":5,"port":"methodology-only","cc":"~30 min if folded into the Pass 3 sweep \u2026","files":["review/checklist.md:28 (output format: when specialists were skipped or scope-gated, the summary line names the categories NOT covered; never an unqualified 'No issues found')","review/SKILL.md.tmpl (summary/Step 4.6 quality score text: reduced-scope run says so; :292 log honesty)"],"basis":"cross-reference MISSING"},{"id":"s8-codediff-codex-sandbox-canary","title":"Codex sandbox canary: empty Codex pass is never a clean review (8abb08e5)","kind":"judgment-rule","refs":["8abb08e5"],"xref":"PARTIAL","residual":"(1) A sandbox/userns failure signature (bwrap|bubblewrap|user namespace|unshare|landlock, plus #1892's 'Could not run the requested commands' shape) classified \u2026","rec":"TAKE_PARTIAL","prio":"P1","val":8,"fit":7,"port":"re-implement","cc":"~45 minutes (+15 min for GSTACK_CODEX_NO\u2026","files":["bin/gstack-codex-probe","scripts/resolvers/constants.ts"],"basis":"cross-reference PARTIAL"},{"id":"s9-skills-pr-mutations-rest","title":"PR title/body mutations via gh api PATCH instead of gh pr edit (#1944; document-release residual)","kind":"fix","refs":["8abb08e5","50eb1028 (Cloverings1 / JonasFocus)"],"xref":"PARTIAL","residual":"(1) /document-release still has NO REST path: release-body.md.tmpl:317 body edit and :377 title edit are bare gh pr edit with warn-and-continue, so on a repo hi\u2026","rec":"TAKE_PARTIAL","prio":"P1","val":7,"fit":9,"port":"adapt","cc":"~15 min","files":["document-release/sections/release-body.md.tmpl:317 (body edit: add REST fallback PATCH from the same scanned temp file), :336-337 (warn-and-continue only after the fallback also fails), :377 (title edit fallback: gh api ... -X PATCH -f title=), :384","document-release/SKILL.md (regenerated)"],"basis":"cross-reference PARTIAL"},{"id":"s9-skills-external-effects-no-blind-retry","title":"EXTERNAL-EFFECTS.md: semantic effect keys, no blind retry, resume reconciliation (pr-1079 roll-up)","kind":"judgment-rule","refs":["8abb08e5","f14445bb"],"xref":"PARTIAL","residual":"(1) Generic semantic-effect-key discipline \u2014 'before each push / PR create-update / merge / deploy / rollback / release / notification, name a stable key and th\u2026","rec":"TAKE_PARTIAL","prio":"P1","val":7,"fit":7,"port":"adapt","cc":"2-3 hours (~10x)","files":["scripts/resolvers/constants.ts","bin/gstack-codex-probe"],"basis":"cross-reference PARTIAL"},{"id":"gap3-makepdf-parser-backed-sanitizer-not-recommended","title":"make-pdf sanitize-html parser-backed sanitizer replacing regex sanitizer","kind":"security","refs":["bd0b2924 (Arpit Jain)","766deb70"],"xref":"PARTIAL","residual":"Skeptic found missing pieces: Entity-obfuscated `javascript:` scheme in `<a href>` (and src/action/formaction) is NOT neutralized by upstream and has NO test. F\u2026","rec":null,"prio":null,"val":null,"fit":null,"port":null,"cc":"","files":[],"basis":"xref-absorbed, flipped by skeptic"},{"id":"s1-prewave-make-pdf-cjk-url-smartypants","title":"smartypants: CJK opening punctuation before quotes (+ URL/NUL carve-out) (absorbed)","kind":"fix","refs":["fork PR #6 (73fcda23)","854533bb (rssprivacy-commits)"],"xref":"PARTIAL","residual":"Code for this candidate is 100% absorbed (v1.64.0.0). What upstream lacks is the regression pins from fork 63cbf40e: (a) 'input NUL bytes cannot forge a carve p\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":3,"fit":9,"port":"adapt","cc":"10 min","files":["make-pdf/test/render.test.ts (add: NUL cannot forge placeholder; fullwidth colon opens quote; PingFang SC precedes Hiragino in CJK_STACK)","TODOS.md (:234 \u2014 remove/adjust the 'CJK stack + smartypants NUL' unpinned note)"],"basis":"cross-reference PARTIAL"},{"id":"gap2-skillwave-autoplan-single-voice-labeling-2023","title":"autoplan single-voice honesty: CONFIRMED-1V labels, never self as outside voice (#2023)","kind":"judgment-rule","refs":["42cad92e, 6a26c6ab (genisis0x)","upstream PR #2023 OPEN (genisis0x)"],"xref":"PARTIAL","residual":"Three things from 42cad92e/6a26c6ab are absent: (1) the CONFIRMED-1V legend semantics \u2014 'only one voice ran (other N/A); the orchestrator concurs with the sole \u2026","rec":"TAKE","prio":"P2","val":5,"fit":9,"port":"re-implement","cc":"15 minutes","files":["autoplan/sections/ceo-phase.md.tmpl (legend :92)","autoplan/sections/eng-phase.md.tmpl (legend :71)"],"basis":"cross-reference PARTIAL"},{"id":"gap2-skillwave-autoplan-scope-detection-counts-2014","title":"autoplan: print scope-detection counts, no silent phase skips (#2014)","kind":"judgment-rule","refs":["7f424e53, 34edb588 (genisis0x)","upstream PR #2014 OPEN (genisis0x)"],"xref":"PARTIAL","residual":"(1) Record and print the per-scope match COUNT in the Phase 0 intake line ('UI scope: yes/no (N matches)'); (2) treat 0-1 matches with plausible hyphenated/syno\u2026","rec":"TAKE","prio":"P2","val":6,"fit":9,"port":"cherry-pick","cc":"10-15 min","files":["autoplan/SKILL.md.tmpl","autoplan/SKILL.md (regenerated)"],"basis":"cross-reference PARTIAL"},{"id":"gap2-skillwave-reviewer-discipline-gate-884","title":"Requested human review is a hard merge gate (#884)","kind":"feature","refs":["69cda419 (Robert Tarabcak / Tarabcak)","e916c04f, 6665b90b (t)"],"xref":"MISSING","residual":"Everything: (a) /ship reviewer resolution (CLAUDE.md 'Default reviewer: @user' \u2192 'Reviewers: @a, @b' \u2192 GitHub-only collaborator auto-detect when 1-2 non-self co\u2026","rec":"TAKE_PARTIAL","prio":"P1","val":7,"fit":8,"port":"adapt","cc":"45-60 min","files":["land-and-deploy/sections/readiness-gate.md.tmpl (new 3.5a-ter hard gate + 'GITHUB REVIEW (human)' rows in the box at :194-221 + blockers line at :223)","land-and-deploy/SKILL.md.tmpl (stop-points list :48-58, hard rules at the bottom)"],"basis":"cross-reference MISSING"},{"id":"gap6-s15-hostadv-untrusted-data-authority-rule","title":"Untrusted-data authority rule: logs/pages/tool output cannot widen mutation boundary (AUTHORITY-POLICY / SHARE\u2026","kind":"judgment-rule","refs":["b6572ebb","origin/main:0aca1f77"],"xref":"PARTIAL","residual":"(1) A generic, always-loaded rule (preamble tier>=2 or per-skill hard rule) that repository text, source comments, diffs, logs, console/network output, error te\u2026","rec":"TAKE_PARTIAL","prio":"P1","val":7,"fit":9,"port":"re-implement","cc":"30-45 min","files":["scripts/resolvers/preamble/generate-untrusted-data-directive.ts (new)","scripts/resolvers/preamble.ts (register after generateEvidenceDirective in the tier>=2 list at :101-108)"],"basis":"cross-reference PARTIAL"},{"id":"gap2-skillwave-design-review-capture-design-system-copy-register-1920","title":"design-review: capture shipped design system first (#1920) + open judgment PR trio 1777/1920/2189","kind":"judgment-rule","refs":["60cb9c5d (Tom / tomdinh24)","upstream PR #1920 OPEN (tomdinh24)"],"xref":"PARTIAL","residual":"(1) The whole #1920 design-review change (fork 60cb9c5d, +33/-4): replace 'Check for DESIGN.md' with the priority-ordered capture (live DOM tokens \u2192 globals.css\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":8,"port":"cherry-pick","cc":"25-35 min","files":["design-review/SKILL.md.tmpl (:57-59 capture block, :174 $D generate brief)","design-review/SKILL.md (regenerated)"],"basis":"cross-reference PARTIAL"},{"id":"s9-skills-match-user-language","title":"Reply in the user's language; keep identifiers/commands original (#679)","kind":"judgment-rule","refs":["b6572ebb","d947d2e1"],"xref":"MISSING","residual":"Everything. No tier of the voice directive, no host config, and no template tells the agent to answer in the user's language. Portable fork hunk (ce7cddce + 466\u2026","rec":"TAKE","prio":"P1","val":8,"fit":9,"port":"cherry-pick","cc":"15 minutes (~20x)","files":["scripts/resolvers/preamble/generate-voice-directive.ts","test/skill-validation.test.ts"],"basis":"cross-reference MISSING"},{"id":"s3-judgment-proportional-planning-per-scale","title":"Per-scale machinery sizing: batch questions, skip research/outside voices, cap review loops at session/hobby","kind":"judgment-rule","refs":["fork PR #18 (merge c3dbec14)","fork PR #25 (merge 655e8239)"],"xref":"MISSING","residual":"Everything material is absent from upstream HEAD: (1) build-scale classification (session/hobby/project/product/venture, time-constraint-as-ceiling, chain inher\u2026","rec":"TAKE_PARTIAL","prio":"P1","val":7,"fit":5,"port":"re-implement","cc":"~4-6 hours (architecture/design ~5x comp\u2026","files":["docs/designs/PACING_UPDATES_V0.md (extend the 'Fold-in from fork port wave 2' section to enumerate the per-scale machinery skips, not just budget accounting)","TODOS.md (P0 PACING_UPDATES_V0 entry at ~1731: add 'scale sizes the machinery' sub-items; note #886 is NOT the tracker)"],"basis":"cross-reference MISSING"},{"id":"s3-judgment-review-rounds-on-decisions-not-ceremony","title":"Review specialists: no target re-confirmation when the handoff names it; obvious in-boundary fixes applied not\u2026","kind":"judgment-rule","refs":["fork PR #25 (merge 655e8239)","fork PR #30 (merge 6ab2b9ae, review tree)"],"xref":"PARTIAL","residual":"(A) Target re-confirmation: plan-eng-review and plan-design-review scope gates (plan-eng-review/SKILL.md.tmpl:40-49, plan-design-review/SKILL.md.tmpl:38-47) sti\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":6,"port":"re-implement","cc":"~1-2 hours for sub-piece A (bug-fix-shap\u2026","files":["plan-eng-review/SKILL.md.tmpl (:40-49 scope gate \u2014 add exception 3: fresh file-anchored handoff artifact naming a plan path)","plan-design-review/SKILL.md.tmpl (:38-47 same exception; consider extracting the duplicated gate into a shared resolver in scripts/resolvers/ since both are inline copies today)"],"basis":"cross-reference PARTIAL"},{"id":"s1-prewave-auth-json-file-write-removal","title":"Stop writing the root token to ~/.gstack/.auth.json (orphaned credential file)","kind":"security","refs":["7b3f391b","upstream PR #2226"],"xref":"MISSING","residual":"The whole change: (1) delete browser-manager.ts:637-654 (the .auth.json write + misleading 'component-baked extension reads it' comment) and the now-dead writeS\u2026","rec":"TAKE","prio":"P1","val":6,"fit":10,"port":"re-implement","cc":"15 min","files":["browse/src/browser-manager.ts (:19 import; :637-654 block)","scripts/build-app.sh (:78-79 stale comment / rm line)"],"basis":"cross-reference MISSING"},{"id":"s1-prewave-local-surface-host-header-check","title":"Reject non-loopback Host header on the whole local listener (DNS rebinding)","kind":"security","refs":["7b3f391b","upstream PR #2226"],"xref":"PARTIAL","residual":"A listener-wide Host gate for surface==='local' (403 before route dispatch when Host is not loopback). The only additional coverage it buys over upstream HEAD i\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":3,"fit":8,"port":"re-implement","cc":"15 min","files":["browse/src/server.ts (makeFetchHandler, ~:1767-1800 \u2014 local-surface Host gate before beforeRoute hook; factor the hostname-parse helper out of :1889-1898 and reuse it)","browse/test/extension-token.test.ts or new browse/test/local-host-gate.test.ts"],"basis":"cross-reference PARTIAL"},{"id":"s1-prewave-manifest-externally-connectable-empty","title":"Extension manifest `externally_connectable: {ids: []}`","kind":"security","refs":["7b3f391b","upstream PR #2226"],"xref":"MISSING","residual":"The single manifest line `\"externally_connectable\": { \"ids\": [] }` (fork ref 7b3f391b:extension/manifest.json) plus, optionally, one assertion in browse/test/ex\u2026","rec":"TAKE","prio":"P3","val":2,"fit":10,"port":"cherry-pick","cc":"2 min (drive-by inside any extension PR)","files":["extension/manifest.json","browse/test/extension-sender-auth.test.ts"],"basis":"cross-reference MISSING"},{"id":"s1-prewave-browse-migrate-legacy-extension","title":"bin/gstack-browse-migrate.ts \u2014 retire path-derived legacy extension IDs from the gstack Chromium profile","kind":"tooling","refs":["7b3f391b","16a63dbe"],"xref":"MISSING","residual":"Entire tool is absent: bin/gstack-browse-migrate.ts (--check/--apply/--profile/--legacy-extension-path/--json; sha256(path)-derived legacy-ID computation; Prefe\u2026","rec":"SKIP","prio":"P3","val":1,"fit":4,"port":"n/a","cc":"20 min for a minimal gstack-upgrade migr\u2026","files":[],"basis":"cross-reference MISSING"},{"id":"s1-prewave-browse-repair-playwright-cache","title":"bin/gstack-browse-repair.ts \u2014 detect and repair a partial/corrupt Playwright Chromium cache at setup","kind":"tooling","refs":["7b3f391b","upstream PR #2226"],"xref":"PARTIAL","residual":"(1) Explicit per-browser health check at setup for BOTH `chromium` (headed) and `chromium-headless-shell`: executable exists + INSTALLATION_COMPLETE present + `\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":6,"port":"re-implement","cc":"30-45 min","files":["setup","browse/src/xprotect-heal.ts"],"basis":"cross-reference PARTIAL"},{"id":"s1-prewave-team-hook-matcher-lowercase-skill","title":"PreToolUse matcher `Skill|skill` so lowercase-tool hosts (Copilot) are enforced","kind":"fix","refs":["d1423cd1","upstream PR #2229"],"xref":"MISSING","residual":"Exactly the fork's d1423cd1 hunk: `const hookMatcher = 'Skill|skill'`; dedup filter accepting both `'Skill'` and `'Skill|skill'` and rewriting `entry.matcher = \u2026","rec":"TAKE","prio":"P2","val":4,"fit":9,"port":"adapt","cc":"10 min","files":["bin/gstack-team-init","test/team-mode.test.ts"],"basis":"cross-reference MISSING"},{"id":"s1-prewave-team-hook-fail-closed-load-errors","title":"Deny (not silently allow) when the enforcement hook itself cannot load","kind":"security","refs":["472f1b3d","d1423cd1"],"xref":"PARTIAL","residual":"(1) A load-failure-tolerant launcher in settings.json: the fork's `node -e` wrapper that emits a structured deny (and never a module-loader stack) when CLAUDE_P\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":7,"port":"adapt","cc":"~1-1.5 hours including 4 tests and the l\u2026","files":["bin/gstack-team-init","test/team-mode.test.ts"],"basis":"cross-reference PARTIAL"},{"id":"s1-prewave-team-claude-md-node-snippet","title":"CLAUDE.md gstack-required snippet checks install via node -e instead of `test -d`","kind":"fix","refs":["e81dc23d","upstream PR #2229"],"xref":"PARTIAL","residual":"Everything shell-portability-related from fork e81dc23d / upstream PR #2229 (still OPEN, branch head d1423cd1) is absent: (1) a non-bash form of the CLAUDE.md v\u2026","rec":"SKIP","prio":"P3","val":2,"fit":3,"port":"n/a","cc":"~30 min, but the port is not recommended","files":[],"basis":"cross-reference PARTIAL"},{"id":"s1-prewave-transcript-ingest-mode-off","title":"memory-ingest honors `transcript_ingest_mode: off` before walking transcripts","kind":"security","refs":["6249074d","time-attack/issue-2140-memory-trust"],"xref":"MISSING","residual":"All of it. Fork 6249074d (== PR #2232 branch, /tmp/ta-wt/memory-trust:bin/gstack-memory-ingest.ts:523-538) adds `transcriptIngestMode()` (regex over `$GSTACK_HO\u2026","rec":"TAKE","prio":"P1","val":7,"fit":9,"port":"adapt","cc":"~30-45 min","files":["bin/gstack-memory-ingest.ts","bin/gstack-gbrain-sync.ts"],"basis":"cross-reference MISSING"},{"id":"s1-prewave-transcript-current-repo-scope","title":"Scope transcript ingest to the current repo's remote (and require explicit trust)","kind":"security","refs":["6249074d","7260b8e2"],"xref":"PARTIAL","residual":"(1) Current-repo scoping: fork `currentRepoRemote()` (canonicalized `git -C $PWD remote get-url origin`, cached) and a `preparePages` skip for any transcript wh\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":6,"port":"re-implement","cc":"~1-2 hours","files":["bin/gstack-memory-ingest.ts","bin/gstack-gbrain-sync.ts"],"basis":"cross-reference PARTIAL"},{"id":"s1-prewave-transcript-source-id-isolation","title":"Import transcripts into a dedicated gbrain source (`--source-id transcripts-<slug>-<hash>`)","kind":"security","refs":["6249074d","upstream PR #2232"],"xref":"MISSING","residual":"All of it: (1) `transcriptSourceId()` \u2192 `transcripts-<repo-slug\u226411>-<sha256(remote||cwd)[:8]>` (fits gbrain's `[a-z0-9-]{1,32}` id rule) (/tmp/ta-wt/memory-trus\u2026","rec":"TAKE","prio":"P1","val":7,"fit":8,"port":"adapt","cc":"~1-2 hours","files":["bin/gstack-memory-ingest.ts","bin/gstack-gbrain-sync.ts"],"basis":"cross-reference MISSING"},{"id":"s1-prewave-setup-probe-deadline","title":"Bounded Playwright launch probe with process-tree kill; Node used for the macOS probe","kind":"fix","refs":["5f9d4d87","93eab0cb"],"xref":"PARTIAL","residual":"The headline (bounded launch probe + process-tree kill + Node for the macOS probe) is absorbed; the rest of fork 5f9d4d87 / PR #2233 is not: (1) the `bunx playw\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":8,"port":"adapt","cc":"~45-60 min","files":["setup","test/setup-playwright-deadline.test.ts"],"basis":"cross-reference PARTIAL"},{"id":"s1-prewave-setup-install-deadline-and-continue","title":"Bound `bunx playwright install chromium` and keep installing skills when Chromium fails","kind":"fix","refs":["5f9d4d87","93eab0cb"],"xref":"PARTIAL","residual":"(1) Deadline on the Chromium DOWNLOAD (`bunx playwright install chromium`, setup:802-808) with an env knob (fork: GSTACK_PLAYWRIGHT_INSTALL_TIMEOUT_SECONDS defa\u2026","rec":"TAKE","prio":"P0","val":9,"fit":9,"port":"re-implement","cc":"30-45 min","files":["setup","test/setup-playwright-deadline.test.ts"],"basis":"cross-reference PARTIAL"},{"id":"s1-prewave-setup-whole-run-lock","title":"Whole-setup mutex (~/.gstack/.setup.lock.d with stale-PID recovery)","kind":"fix","refs":["5f9d4d87","upstream PR #2233"],"xref":"PARTIAL","residual":"A whole-run mutex at `${GSTACK_HOME:-$HOME/.gstack}/.setup.lock.d` (atomic mkdir, pid file, reclaim if holder dead, release only if pid file == $$, chained into\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":3,"fit":7,"port":"adapt","cc":"15 min (best done in the same PR as the \u2026","files":["setup","test/setup-playwright-deadline.test.ts"],"basis":"cross-reference PARTIAL"},{"id":"s1-prewave-hermetic-test-fixes","title":"Hermetic test fixes from #2230 (env-restore leak, machine-state isolation, capability gates)","kind":"test-infra","refs":["e60e9924","25f4e1a6"],"xref":"PARTIAL","residual":"(a) Codex availability probe: gate on `codex --version` exit 0 (with timeout) instead of `which codex` \u2014 ideally as one shared helper since six files repeat the\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":3,"fit":9,"port":"re-implement","cc":"15 min","files":["test/helpers/codex-available.ts","test/codex-e2e.test.ts"],"basis":"cross-reference PARTIAL"},{"id":"s1-prewave-skill-check-honor-skipskills","title":"`bun run skill:check` honors the primary host's `skipSkills`","kind":"tooling","refs":["fork PR #4 (3728f389)"],"xref":"MISSING","residual":"The whole change: import the primary (claude) host config in scripts/skill-check.ts, build `new Set(PRIMARY_HOST.generation.skipSkills ?? [])`, and when a templ\u2026","rec":"TAKE","prio":"P2","val":2,"fit":10,"port":"cherry-pick","cc":"5 min","files":["scripts/skill-check.ts"],"basis":"cross-reference MISSING"},{"id":"s1-prewave-make-pdf-browse-codex-global-paths","title":"make-pdf browse resolution checks ~/.agents and ~/.codex global installs; rejects executable directories","kind":"fix","refs":["fork PR #5 (8b4d871d)"],"xref":"PARTIAL","residual":"Fork's ordered global candidate list `~/.agents/skills/gstack`, `~/.codex/skills/gstack`, then `~/.claude/skills/gstack` (+ listing all three in the error text \u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":6,"port":"re-implement","cc":"45 min","files":["scripts/resolvers/preamble/generate-preamble-bash.ts","setup"],"basis":"cross-reference PARTIAL"},{"id":"s1-prewave-ios-daemon-help","title":"`gstack-ios-qa-daemon --help` prints usage without starting the daemon","kind":"tooling","refs":["fork PR #7 (e55bea58)"],"xref":"MISSING","residual":"Everything in fork e55bea58: (1) a `-h|--help` case in bin/gstack-ios-qa-daemon that prints usage (flags: --tailnet; env: GSTACK_IOS_DAEMON_PORT, GSTACK_IOS_TAR\u2026","rec":"TAKE","prio":"P2","val":4,"fit":9,"port":"adapt","cc":"10-15 min","files":["bin/gstack-ios-qa-daemon","test/ios-qa-daemon-cli.test.ts"],"basis":"cross-reference MISSING"},{"id":"s1-prewave-uninstall-preserve-unowned-codex-dirs","title":"gstack-uninstall: ownership check before deleting ~/.codex/skills/gstack* (and other host arms)","kind":"fix","refs":["fork PR #7 (ad695fbd)"],"xref":"PARTIAL","residual":"Provenance gating for five arms is still missing: ~/.codex/skills/gstack* (:264-268), ~/.factory/skills/gstack* (:274-278), ~/.kiro/skills/gstack* (:284-288), <\u2026","rec":"TAKE_PARTIAL","prio":"P1","val":6,"fit":8,"port":"re-implement","cc":"20-30 min","files":["bin/gstack-uninstall","test/uninstall.test.ts"],"basis":"cross-reference PARTIAL"},{"id":"s1-prewave-conductor-implicit-auq-hook-optin","title":"Stop treating a Conductor workspace as implicit opt-in for the plan-tune/AUQ PreToolUse hooks","kind":"judgment-rule","refs":["fork PR #7 (87b0600f)"],"xref":"PARTIAL","residual":"Skeptic found missing pieces: BEHAVIOR NOT ABSORBED: the fork's actual change \u2014 Conductor is no longer an implicit opt-in for the plan-tune PreToolUse/PostToolU\u2026","rec":null,"prio":null,"val":null,"fit":null,"port":null,"cc":"","files":[],"basis":"xref-absorbed, flipped by skeptic"},{"id":"s1-prewave-readme-uninstall-optional-purge","title":"README manual uninstall: make `rm -rf ~/.gstack` an optional separate step","kind":"doc","refs":["fork PR #7 (a48776a1)"],"xref":"MISSING","residual":"The entire doc change is absent from upstream: (1) an intro sentence before the Option 2 code block \u2014 'Mirrors `gstack-uninstall --keep-state` (preserves `~/.gs\u2026","rec":"TAKE","prio":"P3","val":3,"fit":9,"port":"adapt","cc":"5 min","files":["/home/vercel-sandbox/gstack/README.md"],"basis":"cross-reference MISSING"},{"id":"s2-runtime-workflow-hardening-tripwire-test","title":"Free test that fails CI on mutable action refs / missing permissions / missing concurrency","kind":"test-infra","refs":["09492d34","f14445bb"],"xref":"MISSING","residual":"Four invariants absent from upstream's free suite: (a) every `uses:` ref is a 40-hex SHA across ALL workflows; (b) every workflow declares TOP-LEVEL `permission\u2026","rec":"TAKE","prio":"P1","val":6,"fit":9,"port":"adapt","cc":"~30 min across two bisected commits","files":[".github/workflows/actionlint.yml (checkout@v7 -> SHA)",".github/workflows/free-tests.yml (setup-bun@v2, cache@v6 x2 -> SHA)"],"basis":"cross-reference MISSING"},{"id":"s2-runtime-gen-skill-docs-single-host-fatal","title":"gen-skill-docs: a single-host generation exception must exit nonzero, not warn","kind":"fix","refs":["b6572ebb"],"xref":"MISSING","residual":"The condition at scripts/gen-skill-docs.ts:1150 still has `&& HOST_ARG_VAL === 'all'`; fork b6572ebb drops it so any host failure returns nonzero, and rewrites \u2026","rec":"TAKE","prio":"P1","val":7,"fit":9,"port":"adapt","cc":"~15 min","files":["scripts/gen-skill-docs.ts:1145-1154 (drop `&& HOST_ARG_VAL === 'all'`, rewrite comment, delete the now-false 'Single host dry-run failure already handled above' line)","test/gen-skill-docs.test.ts (new case: single external host with an induced generation exception exits 1 and does not print only WARNING)"],"basis":"cross-reference MISSING"},{"id":"s2-runtime-gen-skill-docs-dry-run-writes","title":"gen-skill-docs --check must not mkdir/write openai.yaml for external hosts","kind":"fix","refs":["b6572ebb"],"xref":"PARTIAL","residual":"Two `!DRY_RUN` guards missing: (1) `if (!DRY_RUN) fs.mkdirSync(outputDir, ...)` at :802 and (2) `&& !DRY_RUN` on the generateMetadata branch at :835 (fork b6572\u2026","rec":"TAKE","prio":"P2","val":4,"fit":9,"port":"adapt","cc":"~10 min","files":["scripts/gen-skill-docs.ts:802 (`if (!DRY_RUN) fs.mkdirSync(outputDir, ...)`)","scripts/gen-skill-docs.ts:835 (`&& !DRY_RUN` on the generateMetadata branch)"],"basis":"cross-reference PARTIAL"},{"id":"s2-runtime-question-pref-hook-slug-mismatch","title":"question-preference hook reads project prefs by cwd basename while the writer keys by gstack-slug owner-repo","kind":"fix","refs":["b6572ebb"],"xref":"MISSING","residual":"Hook still keys project-preference reads by cwd basename while every writer (gstack-question-preference, gstack-question-log \u2014 including the hook's own auto-dec\u2026","rec":"TAKE","prio":"P1","val":8,"fit":8,"port":"re-implement","cc":"~20 min","files":["hosts/claude/hooks/question-preference-hook.ts:300-306 (replace slugFromCwd body with slugFromEnvironment(stateRoot(), cwd), keep 'unknown' for missing cwd; update the comment)","hosts/claude/hooks/question-preference-hook.ts:395 (call site unchanged, but verify stateRoot() is passed)"],"basis":"cross-reference MISSING"},{"id":"s2-runtime-gitattributes-swift-templates-lf","title":".gitattributes: force LF for *.swift, *.h, *.m, *.template","kind":"fix","refs":["d0d770e8"],"xref":"MISSING","residual":"All of it: the four `text eol=lf` lines (*.swift, *.h, *.m, *.template) and a pin test asserting they exist (fork's test lives in test/gstack2-skills.test.ts, a\u2026","rec":"TAKE","prio":"P3","val":3,"fit":9,"port":"adapt","cc":"5 min","files":[".gitattributes","test/gitattributes-eol.test.ts (new; no repo-level .gitattributes pin test exists \u2014 assert the four new patterns plus, cheaply, the existing *.md/*.tmpl/bin/* rules so the file has an owner)"],"basis":"cross-reference MISSING"},{"id":"s2-runtime-linguist-generated-attrs","title":"Mark generated skill output linguist-generated so PR review collapses it","kind":"tooling","refs":["4829cadb"],"xref":"MISSING","residual":"A single .gitattributes stanza upstream lacks: `*/SKILL.md linguist-generated=true` (collapses the 55 template-generated files in GitHub PR review and drops the\u2026","rec":"TAKE","prio":"P3","val":4,"fit":8,"port":"adapt","cc":"5 min","files":[".gitattributes (add: `*/SKILL.md linguist-generated=true` and `contrib/*/SKILL.md linguist-generated=true`, with a comment pointing at skill-docs.yml freshness gate and the CLAUDE.md 'never resolve conflicts on generated SKILL.md' rule)","test/gitattributes-eol.test.ts (same new pin test as the LF candidate \u2014 assert the linguist lines exist and that no hand-written SKILL.md path (browser-skills/**, openclaw/skills/**, test/fixtures/**) is matched; `git check-attr linguist-generated <path>` makes this a 5-line check)"],"basis":"cross-reference MISSING"},{"id":"s2-runtime-find-browse-removal","title":"Drop the dead ~61MB find-browse compiled binary from build/setup","kind":"tooling","refs":["da5ba9c0"],"xref":"MISSING","residual":"The entire removal is still pending upstream. Upstream's version must touch MORE sites than the fork's commit: browse/src/find-browse.ts, browse/bin/find-browse\u2026","rec":"TAKE","prio":"P2","val":6,"fit":8,"port":"re-implement","cc":"30-45 min plus one windows-setup-e2e + m\u2026","files":["browse/src/find-browse.ts (delete)","browse/bin/find-browse (delete; keep browse/bin/remote-slug)"],"basis":"cross-reference MISSING"},{"id":"s4-fleet-fast-path-gate-e2e","title":"Gate-tier E2E pinning the fast path (bounded output, <=3 reference reads, real result not a block)","kind":"test-infra","refs":["8cf30362"],"xref":"MISSING","residual":"The entire test is missing, but it cannot be dropped in: it pins `skills/<skill>/references/` reads on the six-dispatcher tree and presupposes a 'Trivial-change\u2026","rec":"DEFER","prio":"P2","val":6,"fit":5,"port":"re-implement","cc":"~30-45 min once a fast path exists; plus\u2026","files":["test/skill-e2e-proportionality.test.ts (new; four cases: qa single-observation, review typo-only diff, ship one-line README in local-only repo, investigate already-diagnosed off-by-one)","test/helpers/touchfiles-data.ts (four gate-tier entries keyed on <skill>/** + the test file)"],"basis":"cross-reference MISSING"},{"id":"s4-fleet-hardcoded-origin-main-residue","title":"Residual hardcoded `git diff origin/main` in review checklist, greptile triage, office-hours; tripwire coverag\u2026","kind":"fix","refs":["0e355635","8bc0a04f"],"xref":"PARTIAL","residual":"(1) Three live prose sites still hardcode `origin/main`: review/checklist.md:5, review/greptile-triage.md:86, office-hours/SKILL.md.tmpl:87 \u2014 one-line fixes ('t\u2026","rec":"TAKE","prio":"P1","val":7,"fit":10,"port":"adapt","cc":"~20 min for edits + tripwire widening + \u2026","files":["review/checklist.md","review/greptile-triage.md"],"basis":"cross-reference PARTIAL"},{"id":"s4-fleet-context-bill-conditional-tier","title":"context-bill CONDITIONAL tier: references mandated under common conditions counted, not stubbed","kind":"tooling","refs":["e933731c","9606ea63"],"xref":"PARTIAL","residual":"(1) CONDITIONAL tier for upstream's layout: recognize `sections/<name>.md` mentions in STOP-Read lines and the {{SECTION:}}-rendered routing table (ship/SKILL.m\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":8,"port":"re-implement","cc":"~1-2 hours","files":["lib/context-bill.ts (new CONDITIONAL parser for `sections/<name>.md` in STOP-Read clauses and routing tables; TRANSITIVE walk; contentClass mapping for `<skill>/sections/` \u2192 the artifacts/sections divisor; perInvocation stays eager, new conditional totals populated)","test/context-bill.test.ts (:123-135, :335-354, :411 currently pin the tiers as empty \u2014 flip to real assertions)"],"basis":"cross-reference PARTIAL"},{"id":"s4-fleet-decision-search-empty-hint","title":"gstack-decision-search names the project slug and scope on an empty result","kind":"fix","refs":["b4d7abd1"],"xref":"MISSING","residual":"Everything in the fork's decision-search half of b4d7abd1: (1) when `rows` is empty, write one stderr line `gstack-decision-search: no decisions for project \"<s\u2026","rec":"TAKE","prio":"P2","val":5,"fit":9,"port":"adapt","cc":"~10 minutes","files":["bin/gstack-decision-search","test/gstack-decision-bins.test.ts"],"basis":"cross-reference MISSING"},{"id":"s4-fleet-spec-execute-host-neutral-spawn","title":"/spec --execute spawns `claude -p` on every host; adapt to the host CLI","kind":"fix","refs":["8bc0a04f"],"xref":"MISSING","residual":"The fork's whole change (8bc0a04f:skills/plan/references/legacy/spec.md): flag-table cell reworded to 'Spawn an agent in a fresh worktree ... (host-conditional;\u2026","rec":"TAKE","prio":"P1","val":6,"fit":9,"port":"adapt","cc":"~30-45 minutes (resolver + host field + \u2026","files":["spec/SKILL.md.tmpl","spec/sections/gate-and-file.md.tmpl"],"basis":"cross-reference MISSING"},{"id":"s4-fleet-review-precision-answer-key-corpus","title":"Review precision corpus: Django app with answer-keyed 11 seeded non-bugs + 4 planted bugs, canonical findings \u2026","kind":"test-infra","refs":["e000d1af","aacaa5bd"],"xref":"PARTIAL","residual":"(1) test/fixtures/review-precision/{answer-key.json, base/, feature/} \u2014 Django rental/billing corpus: base commit (rentals models + status consumers), feature o\u2026","rec":"TAKE_PARTIAL","prio":"P1","val":7,"fit":8,"port":"adapt","cc":"~1.5-2 hours plus one periodic eval run \u2026","files":["test/skill-e2e-review.test.ts","test/skill-e2e-review-army.test.ts"],"basis":"cross-reference PARTIAL"},{"id":"s4-fleet-tend-bookend-and-validity-preconditions","title":"Fleet sub-idea: machine-written tEnd on every exit path + run validity preconditions + literal jq extraction","kind":"methodology","refs":["3ebde802"],"xref":"MISSING","residual":"All of it, as spec text for the P2 TODO (and eventually the runner): (1) harness writes `{type:'tEnd', ts, run, outcome}` as the LAST line on every exit path \u2014 \u2026","rec":"TAKE","prio":"P2","val":5,"fit":8,"port":"methodology-only","cc":"~10 minutes","files":["TODOS.md:269-285 (extend P2 persona-fleet entry)","docs/designs/ (optional short decision record: fleet run validity + denominators)"],"basis":"cross-reference MISSING"},{"id":"s4-fleet-metric-source-provenance","title":"Fleet sub-idea: every metric carries a `source` (path#Lrange or literal 'self-report'); counted and self-repor\u2026","kind":"methodology","refs":["3ebde802"],"xref":"PARTIAL","residual":"Everything beyond the headline sentence: (1) every recorded metric is `{value, source}` where source is a resolvable `run.jsonl#Lrange` or the literal `self-rep\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":4,"fit":6,"port":"methodology-only","cc":"~10 minutes","files":["TODOS.md:269-285 (same P2 persona-fleet entry)","docs/designs/ (same optional decision record as the tEnd candidate)"],"basis":"cross-reference PARTIAL"},{"id":"s4-fleet-rage-and-verification-metric-families","title":"Fleet sub-idea: rage-event taxonomy and verification family as countable transcript metrics","kind":"methodology","refs":["3ebde802"],"xref":"MISSING","residual":"Everything in the candidate is absent as a metric: (a) rage taxonomy \u2014 wrongAssumptions, unaskedActions, ignoredInstructions, deadEnds, repeatedItself, ceremony\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":7,"port":"re-implement","cc":"1-2 hours","files":["test/helpers/llm-judge.ts","test/helpers/eval-store.ts"],"basis":"cross-reference MISSING"},{"id":"s4-fleet-abandonment-contract-details","title":"Fleet sub-idea: quit mandate text, quit-record schema, forced vs judgment abandonment rates, cap provenance an\u2026","kind":"methodology","refs":["3ebde802"],"xref":"MISSING","residual":"All of: (1) the verbatim quit mandate ('You may quit. Quitting is a valid outcome... If any cap below trips, you MUST stop immediately, write the quit record, a\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":4,"fit":5,"port":"methodology-only","cc":"10-15 minutes for the TODOS append","files":["TODOS.md"],"basis":"cross-reference MISSING"},{"id":"s4-fleet-changelog-trade-honesty","title":"CHANGELOG methodology: state both sides of a trade against the apples-to-apples baseline; mark break-even unve\u2026","kind":"methodology","refs":["91560fe3","773e7aba"],"xref":"MISSING","residual":"A short addition to docs/CHANGELOG_STYLE.md 'The X numbers that matter' rules: (a) when a change speeds one path by slowing another, the table carries BOTH rows\u2026","rec":"TAKE","prio":"P3","val":5,"fit":9,"port":"adapt","cc":"5 minutes","files":["docs/CHANGELOG_STYLE.md"],"basis":"cross-reference MISSING"},{"id":"s4-fleet-codex-mktemp-portable","title":"Portable BSD-safe mktemp in codex/review modules (#2091)","kind":"fix","refs":["8bc0a04f","f9a6033a"],"xref":"PARTIAL","residual":"Skeptic found missing pieces: Stdin prompt dispatch for codex exec (the second rule of fork overlay 2370, fork_ref f9a6033a). Fork: scripts/gstack2/render-legac\u2026","rec":null,"prio":null,"val":null,"fit":null,"port":null,"cc":"","files":[],"basis":"xref-absorbed, flipped by skeptic"},{"id":"s6-branches-browse-record-cdp-screencast","title":"$B record start|stop|status|open \u2014 CDP screencast to mp4 (ffmpeg) or self-contained HTML player","kind":"feature","refs":["76c89d56","cursor/qa-recording-d3d5"],"xref":"MISSING","residual":"Entire feature is absent upstream: browse/src/screencast.ts (start/stop/status/open via CDP Page.startScreencast, per-page WeakMap session cache, JPEG frames to\u2026","rec":"TAKE","prio":"P1","val":8,"fit":8,"port":"adapt","cc":"~1.5-2 hours (adapt two fork modules nea\u2026","files":["browse/src/screencast.ts (new, from fork 76c89d56)","browse/src/screencast-encode.ts (new, from fork 76c89d56; change vp9 fallback ext to .webm)"],"basis":"cross-reference MISSING"},{"id":"s6-branches-record-tunnel-denial-and-scope","title":"record is tunnel-denied (pair-agent) and classified read-scope; competing PR uses control-scope","kind":"security","refs":["76c89d56"],"xref":"MISSING","residual":"Nothing about 'record' exists upstream, so both halves are absent \u2014 but they are very different in weight. (a) Tunnel denial: upstream's closed allowlist (serve\u2026","rec":"TAKE_PARTIAL","prio":"P1","val":4,"fit":9,"port":"adapt","cc":"~10 minutes","files":["browse/src/token-registry.ts (add 'record' to the chosen scope set \u2014 recommend SCOPE_WRITE, not the fork's SCOPE_READ or #2497's SCOPE_CONTROL)","browse/test/dual-listener.test.ts (:109-120 forbidden list + rationale comment)"],"basis":"cross-reference MISSING"},{"id":"s6-branches-record-shutdown-flush","title":"Flush an in-flight recording on daemon shutdown/idle so frames are never orphaned","kind":"fix","refs":["76c89d56"],"xref":"MISSING","residual":"flushRecordingOnShutdown() (fork ref 76c89d56:browse/src/screencast.ts, ~8 lines: if active \u2192 stopRecording({open:false}), swallow errors, null out state) and i\u2026","rec":"TAKE","prio":"P1","val":6,"fit":8,"port":"adapt","cc":"~15-20 minutes","files":["browse/src/server.ts (shutdown(): dynamic import + await flushRecordingOnShutdown() immediately before the detachSession() try at :1667)","browse/src/screencast.ts (flushRecordingOnShutdown with a shutdown-bounded encode path)"],"basis":"cross-reference MISSING"},{"id":"s6-branches-record-caps-and-fallbacks","title":"Recording safety caps: 15-min / 7200-frame ceiling, min frame gap, zero-frame screenshot fallback","kind":"judgment-rule","refs":["76c89d56"],"xref":"MISSING","residual":"All of it (fork ref 76c89d56:browse/src/screencast.ts:29-33 and :151-172, :193-205; screencast-encode.ts:104-129): MAX_DURATION_MS = 15 min and MAX_FRAMES = 720\u2026","rec":"TAKE","prio":"P1","val":7,"fit":9,"port":"adapt","cc":"~20-30 minutes","files":["browse/src/screencast.ts (MAX_DURATION_MS, MAX_FRAMES, MIN_FRAME_GAP_MS, add MAX_BYTES + wall-clock timer, zero-frame screenshot fallback, --fps 1-30 / --quality 1-100 validation)","browse/src/screencast-encode.ts (libx264 \u2192 libvpx-vp9 (.webm) \u2192 player.html chain)"],"basis":"cross-reference MISSING"},{"id":"s6-branches-ios-record-session-poller","title":"iOS walkthrough recorder: detached poller of the ios-qa daemon GET /screenshot \u2192 PNG frames \u2192 mp4/HTML","kind":"feature","refs":["f15883ad"],"xref":"MISSING","residual":"Whole artifact absent: ios-qa/scripts/record-session.ts (fork ref f15883ad, 262 lines: start --daemon URL [--token] [--out] [--fps 1-15] spawns a detached `bun \u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":6,"port":"re-implement","cc":"~1 hour + a real-device smoke test","files":["ios-qa/scripts/record-session.ts (new; import encoder from browse/src/screencast-encode.ts or a new lib/recording-encode.ts; no --token; state keyed by daemon port)","bin/gstack-ios-record (thin wrapper per the bin/lib pattern, optional)"],"basis":"cross-reference MISSING"},{"id":"s6-branches-qa-recording-specialist-judgment","title":"QA 'recording' module rules: start capture before the first interaction, keep screenshots as evidence, never l\u2026","kind":"judgment-rule","refs":["44221ac7"],"xref":"MISSING","residual":"Everything in the module is absent upstream: (a) web-vs-iOS surface parse table incl. 'watch/show me/demo' \u2192 headed and 'fix' \u2192 qa.md-after-start; (b) START REC\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":7,"port":"adapt","cc":"30-45 min for the shared section + pin t\u2026","files":["scripts/resolvers/qa-recording.ts (new shared `{{QA_RECORDING_SECTION}}`, rules b/c/d/e/f rewritten against #2497's .webm surface)","qa-only/SKILL.md.tmpl"],"basis":"cross-reference MISSING"},{"id":"s6-branches-web-data-provider-cli","title":"gstack-web-data CLI + lib/web-data.ts: optional scraping-provider picker with persisted decline","kind":"feature","refs":["08b0850a","042d186c"],"xref":"MISSING","residual":"Whole feature absent: provider registry with `offMachine` flag (lib/web-data.ts:21-71), `detectAvailability` (:138-164), selection store at $GSTACK_HOME/web-dat\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":8,"port":"adapt","cc":"1.5-2 h (adapt lib/web-data.ts + bin + t\u2026","files":["lib/web-data.ts (new; from fork lib/web-data.ts minus `context` provider, with upstream browse-binary resolution and third-party-actions Aside probe)","bin/gstack-web-data (new; status|options|select|recommend, header crediting Sina Matian/time-attack per the gstack-code-intelligence precedent)"],"basis":"cross-reference MISSING"},{"id":"s6-branches-web-data-official-api-first-rule","title":"Judgment rule: an official API for the data source beats every scraping provider and needs no consent question","kind":"judgment-rule","refs":["f0efe76c","857e6d62"],"xref":"MISSING","residual":"Both sentences absent: (1) 'When no choice is stored, first check whether the data source has an official API (for example MediaWiki for Wikipedia) \u2014 an officia\u2026","rec":"TAKE","prio":"P1","val":7,"fit":10,"port":"re-implement","cc":"10-15 min","files":["scrape/SKILL.md.tmpl (Step 1 / 'What this skill does NOT do': multi-page crawl -> first check for an official API; never block; say which fallback you used)","plan-eng-review/sections/review-sections.md ('What already exists' \u2014 add a data-source-API lens: 'does the source have an official API? scraping it is rebuilding')"],"basis":"cross-reference MISSING"},{"id":"s6-branches-web-data-task-taxonomy-and-rankings","title":"Task taxonomy (scrape/crawl/search/batch/hostile/authenticated) with measured bakeoff rankings","kind":"methodology","refs":["08b0850a","d3987bb3"],"xref":"PARTIAL","residual":"Absent upstream: (1) the six-task taxonomy scrape/crawl/search/batch/hostile/authenticated as a decision vocabulary (fork lib/web-data.ts:22-24, TASK_RANKINGS :\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":8,"port":"adapt","cc":"15-20 min prose-only (scrape redirect ta\u2026","files":["scrape/SKILL.md.tmpl (replace the bare 'Multi-page crawls (this is one-shot per call)' with a small routing table: scrape / crawl / search / batch / hostile / authenticated -> where each goes and why)","browse/BROWSER.md (one paragraph near :575 extending the logged-in rule from acting to evidence/scraping)"],"basis":"cross-reference PARTIAL"},{"id":"s6-branches-web-data-windows-test-repairs","title":"Windows test repairs riding on the web-data branch (gstack-paths env repair, vacuous-pass guard, portable sile\u2026","kind":"test-infra","refs":["cbe5dfb9","82b8742f"],"xref":"PARTIAL","residual":"Exactly one line: add `expect(lines.length).toBeGreaterThan(0); // empty output must fail, not pass vacuously` before the for-loop at test/gstack-paths.test.ts:\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":1,"fit":9,"port":"adapt","cc":"2 min","files":["test/gstack-paths.test.ts"],"basis":"cross-reference PARTIAL"},{"id":"s6-branches-windows-dpapi-cookie-fixture","title":"Windows DPAPI cookie test fixture + probe for cookie-import-browser under native Bun and node+bun-polyfill","kind":"test-infra","refs":["fe868994"],"xref":"MISSING","residual":"The Windows end-to-end proof is the residual: no upstream test on any platform exercises cookie-import-browser.ts's win32 branch (getWindowsAesKey \u2192 dpapiDecryp\u2026","rec":"TAKE","prio":"P2","val":6,"fit":7,"port":"adapt","cc":"30-45 min","files":["browse/test/cookie-import-windows-dpapi.test.ts (new; skipIf non-win32; shells to pwsh for ProtectedData::Protect, writes Local State + Network/Cookies via bun:sqlite, calls importCookies('chrome',['127.0.0.1'],'Default') under isolated HOME/USERPROFILE, asserts sha256 of decrypted value)","browse/test/fixtures/protect-dpapi-key.ps1 (new, ~40 lines adapted from fork)"],"basis":"cross-reference MISSING"},{"id":"s6-branches-windows-network-lockdown-ci","title":"Outbound firewall lockdown with evidence record for hermetic Windows CI phases","kind":"ci","refs":["60863a71","fe868994"],"xref":"MISSING","residual":"Everything: upstream has no runtime outbound-network block on any CI lane (Windows or Linux) and no evidence record of one. The portable unit is ~50 lines of Po\u2026","rec":"DEFER","prio":"P3","val":2,"fit":4,"port":"methodology-only","cc":"1-2 hours","files":["TODOS.md (new entry under Windows/CI: 'post-install hermetic Windows probe lane with outbound firewall lockdown; ready-made Enter/Exit-TestNetworkLockdown in fork commit 60863a71/fe868994 .github/windows-gates/common-windows.ps1:225-273')",".github/workflows/windows-setup-e2e.yml (only if/when an offline post-install probe phase is added)"],"basis":"cross-reference MISSING"},{"id":"s6-branches-stealth-patches-apr-2026","title":"Comprehensive anti-bot stealth module (Apr 2026) \u2014 superseded by upstream Layer C, with a few residual nuances","kind":"feature","refs":["46b2e359","8df1c003"],"xref":"PARTIAL","residual":"Superseded in architecture; residual is a short list of point refinements, mostly extended-mode: (a) WebGL \u2014 gate UNMASKED_VENDOR/RENDERER (0x9245/0x9246) on `t\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":8,"port":"re-implement","cc":"1-1.5 hours","files":["browse/src/stealth.ts (AUTOMATION_ARTIFACT_CLEANUP_SCRIPT :410-425 EventTarget-shaped PermissionStatus; :395-402 add document-level cdc_/__webdriver/__selenium sweep; EXTENDED_STEALTH_SCRIPT :270-277 gate on getExtension('WEBGL_debug_renderer_info') + WebGL2RenderingContext + honor env GPU string; :353-357 mediaDevices getUserMedia rejection + placeholder devices; :282-321 `?? null`; wrap extended fns with markNative per :442-445)","browse/src/browser-manager.ts:715-731,756 (decide: stop forcing Macintosh UA on non-darwin headed launches, OR define navigator.platform consistently)"],"basis":"cross-reference PARTIAL"},{"id":"s6-branches-browser-batch-multitab-plan","title":"Plan: POST /batch with parallel-across-tabs execution + /batch-newtab + /batch-close","kind":"feature","refs":["72df88d8","feat/browser-batch-multitab"],"xref":"PARTIAL","residual":"Absorbed: POST /batch itself, 50-command cap, nested-batch rejection, per-command error isolation with per-result status, batch-as-one-rate-limit-request, per-c\u2026","rec":"DEFER","prio":"P2","val":6,"fit":6,"port":"re-implement","cc":"2-3 hours (session-routing refactor + te\u2026","files":["TODOS.md (new P2 entry: 'Parallel /batch across tab groups + POST /batch-newtab + /batch-close; blocked on removing the global switchTab pin in handleCommandInternalImpl (server.ts:1063-1072); TabSession was extracted for this (tab-session.ts:4) but never wired to the HTTP layer')","browse/src/server.ts (handleCommandInternalImpl tab routing :1063-1072/:1290-1300; /batch handler :2733-2760 group-by-tabId + guarded Promise.allSettled; new /batch-newtab and /batch-close routes; per-command timing in envelope :2777-2786)"],"basis":"cross-reference PARTIAL"},{"id":"s6-branches-yc-review-skill","title":"/yc-review \u2014 pull the live YC application via cookie import + in-page GraphQL, review it as a partner","kind":"feature","refs":["7de11aad","feat/yc-review"],"xref":"MISSING","residual":"Entire skill is absent upstream: (1) the two-domain YC cookie import recipe (.ycombinator.com SSO parent cookies + apply.ycombinator.com host-only session cooki\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":5,"fit":3,"port":"methodology-only","cc":"Full skill port: ~1-2 hours (skill scaff\u2026","files":["TODOS.md","office-hours/sections/design-and-handoff.md.tmpl"],"basis":"cross-reference MISSING"},{"id":"s7-docs-method-privacy-data-flow-doc","title":"PRIVACY.md per-capability data-flow table (Default / May leave the machine / Never send) + disable/remove reci\u2026","kind":"doc","refs":["docs/gstack-2/PRIVACY.md","411b6060"],"xref":"MISSING","residual":"A single reviewer-facing page (root PRIVACY.md or docs/PRIVACY.md) containing: (1) a per-capability table with columns Default / May leave the machine / Never s\u2026","rec":"TAKE","prio":"P1","val":8,"fit":8,"port":"re-implement","cc":"~1-1.5 hours (doc + grants extension + t\u2026","files":["PRIVACY.md (new, root; per-capability table Default / May leave the machine / Never send; consent principle stated once; per-boundary sections linking ARCHITECTURE.md; Disable & remove with exact commands)","README.md:500-513 (shorten Privacy & Telemetry to a summary + link to PRIVACY.md; keep the update-check disclosure at README.md:61)"],"basis":"cross-reference MISSING"},{"id":"s7-docs-method-adr-convention","title":"Numbered ADR series (docs/gstack-2/adr/NNNN-*.md) with Status/Date/Scope, decision table, rejected alternative\u2026","kind":"doc","refs":["docs/gstack-2/adr/0001-public-infrastructure-tools.md"],"xref":"PARTIAL","residual":"No numbered short-form decision-record series (docs/adr/NNNN-*.md or equivalent), no index, no fixed Status/Date/Scope header, no REQUIRED 'Rejected alternative\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":3,"fit":5,"port":"methodology-only","cc":"30 min","files":["docs/designs/README.md (new: index of the 22 docs, one line each: title | status | decision | rejected alternative)","ARCHITECTURE.md (add a short 'Settled decisions' table next to '## What's intentionally not here' :440 \u2014 Decision | Rejected | Where the rationale lives; rows: Bun, no cloud browser/bundled Chromium only, localhost-only daemon + token, egress receipts are forensic not a firewall, no tsc yet, no MCP, git-clone+./setup not npx)"],"basis":"cross-reference PARTIAL"},{"id":"s7-docs-method-upgrade-rollback-doc","title":"UPGRADE-AND-ROLLBACK.md: explicit rollback command, last-known-good retention, forward-only state with 'newer \u2026","kind":"doc","refs":["docs/gstack-2/UPGRADE-AND-ROLLBACK.md"],"xref":"PARTIAL","residual":"(1) No user-facing 'how do I go back to v1.78' recipe for git-global, vendored, and team-mode installs (and no tags to check out \u2014 recipe must use the version-b\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":7,"port":"re-implement","cc":"45 min","files":["setup (migration block :1946-1972 \u2014 before the unconditional marker write at :1971, compare LAST_SETUP_VERSION vs CURRENT_VERSION with sort -V; if LAST is newer: print 'state written by newer gstack vLAST; downgrade not supported \u2014 one-way migrations since vCURRENT: <list>; re-upgrade or set GSTACK_ALLOW_DOWNGRADE=1' and skip the marker rewind)","gstack-upgrade/SKILL.md.tmpl (Step 4.75 migration runner :237-264 \u2014 same guard in prose+bash; new short 'Rolling back' step or pointer)"],"basis":"cross-reference PARTIAL"},{"id":"s7-docs-method-static-analysis-disposition-honesty","title":"'Static-analysis disposition' section: record what is NOT gated (no tsc, no formatter, no CODEOWNERS) instead \u2026","kind":"doc","refs":["docs/gstack-2/RELEASE-INTEGRITY.md (Static-analysis disposition)"],"xref":"PARTIAL","residual":"Upstream's ENFORCED set already equals the fork's 'enforced now' list (ShellCheck, actionlint, redaction scan on added lines, generated-freshness, tests, audit)\u2026","rec":"TAKE","prio":"P3","val":4,"fit":8,"port":"methodology-only","cc":"5 min","files":["CONTRIBUTING.md (new '#### What CI does NOT check' under '### CI' at :300-312: no tsc/tsconfig \u2014 Bun transpiles, it does not typecheck, tracked in #2447; no formatter/linter \u2014 golden fixtures under test/fixtures/golden/ and byte-pinned parity corpora would be mechanically rewritten, so any adoption is its own PR; no CODEOWNERS \u2014 single-maintainer repo, review is /review + outside voice, not a GitHub required-reviewer gate)","docs/TESTING_INTERNALS.md (one cross-link line near :45-70 so 'free suite green' readers see it)"],"basis":"cross-reference PARTIAL"},{"id":"s7-docs-method-host-compat-evidence-tiers","title":"Host support labeled by evidence tier (Portable / Verified \u2014 <layer> / Native) with per-host evidence links an\u2026","kind":"doc","refs":["docs/gstack-2/HOST-COMPATIBILITY.md","evals/installation/install-verify-2026-08-09.json"],"xref":"MISSING","residual":"The entire labeling scheme: (1) tier definitions (Portable = renders per spec; Verified \u2014 <layer> must name installer vs UI-launch vs scored cell; Native = adap\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":7,"port":"re-implement","cc":"1 hour","files":["README.md (:104-124 \u2014 add an 'Evidence' column or a per-row footnote tier; keep the 10-agents line but qualify it; needs AskUserQuestion \u2014 promotional copy)","docs/ADDING_A_HOST.md (after '## Validation' :173-181 \u2014 new '## Evidence tiers' section: what the parameterized smoke tests prove and do not prove, what upgrades a host to installer-verified / live-run verified, clean-temp-HOME per-host verification procedure, and what step 6 'Update README.md' :147-149 may claim)"],"basis":"cross-reference MISSING"},{"id":"s7-docs-method-skills-sh-distribution","title":"skills.sh / `npx skills add` distribution: skills.sh.json grouping manifest, STOREFRONT.md listing audit, CI d\u2026","kind":"feature","refs":["skills.sh.json","docs/gstack-2/STOREFRONT.md"],"xref":"MISSING","residual":"Everything: (1) a decision whether the Agent Skills CLI is a supported channel at all (README's git-clone + ./setup path is deliberate \u2014 binaries, asset links, \u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":3,"port":"re-implement","cc":"30 min for the small slice; ~2 days for \u2026","files":["README.md (:104-110 install section \u2014 one sentence: `npx skills add` / skills.sh is not a supported install path; gstack needs ./setup for binaries and host wiring; needs AskUserQuestion \u2014 promotional copy)","SKILL.md.tmpl (root router :1-18 \u2014 add a stray-install self-check: if bin/gstack-config or browse/dist is absent next to this file, tell the user they have a Markdown-only copy and print the git clone + ./setup command instead of routing to skills that do not exist)"],"basis":"cross-reference MISSING"},{"id":"s7-docs-method-routing-scenario-fixtures","title":"Structured routing fixtures: 18 scenarios keyed on stage/surface/authorization/evidence signals (not keywords)\u2026","kind":"test-infra","refs":["docs/gstack-2/SCENARIOS.md","73c48052 (79 scenarios so every module can be judged)"],"xref":"PARTIAL","residual":"(1) Fork-only scenario coverage upstream lacks: plan-ceo-review, plan-devex-review, autoplan, spec, qa-only (report-only vs qa fix), ios-qa, devex-review, canar\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":8,"port":"adapt","cc":"30-45 min + one periodic eval run to val\u2026","files":["test/skill-routing-e2e.test.ts","test/helpers/touchfiles-data.ts"],"basis":"cross-reference PARTIAL"},{"id":"s7-docs-method-nine-dimension-parity-checklist","title":"Deterministic prose-refactor parity oracle: pinned base render hashes + nine behavioral dimensions; live LLM c\u2026","kind":"methodology","refs":["docs/gstack-2/JUDGMENT-PARITY.md","docs/gstack-2/SEMANTIC-PARITY.md"],"xref":"PARTIAL","residual":"(1) No written, general contributor checklist naming the behavioral dimensions a template refactor must account for (fork CONTRIBUTING.md:37-41: questions, pres\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":4,"fit":8,"port":"methodology-only","cc":"10 min","files":["CLAUDE.md","CONTRIBUTING.md"],"basis":"cross-reference PARTIAL"},{"id":"s7-docs-method-bloat-ledger","title":"BLOAT-LEDGER.json: measured eager tokens plus safeCuts / needsABEvidence / doNotCut with tokensSaved and risk","kind":"methodology","refs":["docs/gstack-2/BLOAT-LEDGER.json","docs/gstack-2/CONTEXT-BILL.md"],"xref":"PARTIAL","residual":"(1) No single committed ledger separating proposed cuts into safe / needs-A/B-evidence / do-not-cut with tokensSaved+risk+owner per row \u2014 upstream's equivalents\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":2,"fit":7,"port":"methodology-only","cc":"5 min (same edit as the parity checklist\u2026","files":["CLAUDE.md"],"basis":"cross-reference PARTIAL"},{"id":"s7-docs-method-audit-backlog-ledger","title":"AUDIT-BACKLOG.md convention: unfixed multi-auditor findings as a compact Sev | Area | file:line | Summary | Su\u2026","kind":"methodology","refs":["docs/gstack-2/AUDIT-BACKLOG.md"],"xref":"PARTIAL","residual":"(1) No convention or file for deferred multi-auditor findings as a compact `Sev | Area | file:line | Summary | Suggested fix` table, themed and ranked (fork doc\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":3,"fit":5,"port":"adapt","cc":"10-15 min incl. gen:skill-docs + bun run\u2026","files":["cso/SKILL.md.tmpl","review/SKILL.md.tmpl"],"basis":"cross-reference PARTIAL"},{"id":"s7-docs-method-contributing-evidence-bar-section","title":"CONTRIBUTING 'The evidence bar' section is referenced by upstream's PR template but does not exist upstream; D\u2026","kind":"doc","refs":["CONTRIBUTING.md (fork) lines 76-143",".github/PULL_REQUEST_TEMPLATE.md (fork)"],"xref":"PARTIAL","residual":"(1) CONTRIBUTING.md has no 'The evidence bar' section: missing the 'prove a human ran this' framing, the four acceptable evidence forms (repro, failing test mad\u2026","rec":"TAKE","prio":"P1","val":6,"fit":9,"port":"adapt","cc":"15 min","files":["CONTRIBUTING.md",".github/PULL_REQUEST_TEMPLATE.md"],"basis":"cross-reference PARTIAL"},{"id":"s7-docs-method-issue-templates-and-labels","title":"Issue template fields (observed vs expected, minimal repro, host/OS/version, evidence with secrets removed, ro\u2026","kind":"doc","refs":["CONTRIBUTING.md (fork) lines 47-69"],"xref":"MISSING","residual":"Everything: (1) .github/ISSUE_TEMPLATE issue form(s) asking for observed vs expected, minimal repro, host/OS/gstack VERSION, evidence/transcript with secrets re\u2026","rec":"TAKE","prio":"P1","val":7,"fit":9,"port":"re-implement","cc":"20-30 min","files":[".github/ISSUE_TEMPLATE/bug_report.yml",".github/ISSUE_TEMPLATE/new_surface.yml"],"basis":"cross-reference MISSING"},{"id":"s7-docs-method-devcontainer","title":".devcontainer (digest-pinned oven/bun Debian image, Playwright chromium --with-deps, poppler-utils, fonts, fro\u2026","kind":"tooling","refs":[".devcontainer/devcontainer.json",".devcontainer/Dockerfile"],"xref":"MISSING","residual":"All of it \u2014 a .devcontainer/devcontainer.json + Dockerfile giving contributors/fork-PR authors a one-click environment that runs `bun run test` green. Should be\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":7,"port":"re-implement","cc":"30-45 min (+ one manual Codespaces verif\u2026","files":[".devcontainer/devcontainer.json (image: ghcr.io/garrytan/gstack/ci:<tag> or build from .devcontainer/Dockerfile FROM that image; remoteUser runner; containerEnv PLAYWRIGHT_BROWSERS_PATH=/opt/playwright-browsers)",".devcontainer/post-create.sh (bun install --frozen-lockfile, gen:skill-docs --host all, vendor:xterm, browse/scripts/build-node-server.sh, build:gates to a non-virtiofs path, git identity + safe.directory)"],"basis":"cross-reference MISSING"},{"id":"s7-docs-method-multi-os-static-tree-gate","title":"Cross-OS (macOS/Ubuntu/Windows) lane for static skill-tree + size-budget tests","kind":"ci","refs":[".github/workflows/gstack2-gate.yml"],"xref":"PARTIAL","residual":"A macOS job (free GitHub macos-14/macos-latest) over a curated small file list, mirroring windows-free-tests' curation pattern: the mktemp/gstack-paths portabil\u2026","rec":"TAKE","prio":"P1","val":7,"fit":9,"port":"re-implement","cc":"30 min (+ a few PR cycles to baseline fl\u2026","files":[".github/workflows/macos-free-tests.yml (new; macos-14; bun 1.3.13; `bun run test:macos`)","scripts/test-free-shards.ts (add --macos-only curation beside WINDOWS_FRAGLE_PATTERNS/KNOWN_WINDOWS_SAFE :119-261: mktemp-portability, regression-issue2091-bsd-mktemp, regression-pr1169-mktemp-fallbacks, gstack-paths tests, claude-provider-keychain (darwin branch :117-138), catalog-budget, context-budget-ratchet, skill-size-budget, skill-validation, setup-help, a ./setup --host claude smoke into temp HOME per setup-windows-fallback precedent)"],"basis":"cross-reference PARTIAL"},{"id":"s7-docs-method-ios-qa-ab-scorecard-method","title":"Controlled QA-skill A/B scorecard: frozen 10-category rubric with mandatory minima, seeded-defect weighted rec\u2026","kind":"methodology","refs":["evals/ios-qa-ab/README.md","evals/ios-qa-ab/final-scorecard.md"],"xref":"PARTIAL","residual":"(1) severity-weighted recall + explicit precision + a mandatory FP gate (a single High false positive fails regardless of total) in outcomeJudge/judgePassed and\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":7,"port":"adapt","cc":"45-60 min for (1)+(6) plus one ~$1 gate \u2026","files":["test/helpers/llm-judge.ts:156-195 (outcomeJudge: return per-finding false_positives with severity; add precision)","test/helpers/eval-store.ts:280-287 (judgePassed: severity-weighted recall, precision floor, hard fail on any High false positive)"],"basis":"cross-reference PARTIAL"},{"id":"s7-docs-method-install-matrix-evidence-artifacts","title":"Committed install-verification artifacts: per-host per-file sha256 parity, project/global/selected/removal cas\u2026","kind":"test-infra","refs":["evals/installation/install-matrix.json","evals/installation/install-verify-2026-08-09.json"],"xref":"PARTIAL","residual":"(a) A free test that runs `./setup --host <h>` (or the extracted install functions) for every install-target host into a temp HOME and asserts, for every instal\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":8,"port":"re-implement","cc":"45-60 min (+ one gate baseline run)","files":["test/setup-install-parity.test.ts (new, free: for each HOST_ROOTS builder in IS_WINDOWS=0/1, walk installed tree; symlinks -> realpath under ROOT; regular files -> sha256 == source or rendered out-dir expectation; selected-skill install; uninstall leaves zero gstack-owned entries) \u2014 reuse HOST_ROOTS from test/setup-runtime-lib-command.test.ts:100-150","test/uninstall-windows-copies.test.ts:88-141 (extend content check beyond toContain('name: ship'))"],"basis":"cross-reference PARTIAL"},{"id":"s7-docs-method-test-evidence-ledger-and-status-gates","title":"STATUS.md gate ledger ('DONE prohibited until each P0 gate has evidence') + TEST-EVIDENCE.md run receipts, 'fi\u2026","kind":"methodology","refs":["docs/gstack-2/STATUS.md","docs/gstack-2/TEST-EVIDENCE.md"],"xref":"PARTIAL","residual":"Thin, and mostly not something the fork itself built. (1) No single generic per-run invariant on the `claude -p`/Agent-SDK path that a paid test's child reached\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":3,"fit":8,"port":"re-implement","cc":"30-45 min","files":["test/helpers/session-runner.ts","test/helpers/eval-store.ts"],"basis":"cross-reference PARTIAL"},{"id":"s5-beta-ablation-instrument","title":"Per-module ablation instrument: scripts/ablate.ts + test/skill-baseline (arms, deterministic scoring, resumabl\u2026","kind":"test-infra","refs":["2e505007","32a7585b"],"xref":"PARTIAL","residual":"Upstream's arm benchmark is a whole-skill A/B on 3 tasks with an LLM judge; it does not answer the per-section 'does this 11KB earn its tokens' question. Missin\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":7,"port":"adapt","cc":"~3-5 hours for a first landable slice (c\u2026","files":["scripts/ablate.ts (new)","test/helpers/ablation/score.ts (new, from fork score.ts)"],"basis":"cross-reference PARTIAL"},{"id":"s5-beta-answer-keys","title":"Five pre-registered answer keys (codex-decorrelation, health-trending, office-hours, review-parity, ship-consi\u2026","kind":"methodology","refs":["55fe6f73"],"xref":"PARTIAL","residual":"Three of the five keys are entirely absent and unmentioned upstream: office-hours (question pressure vs flattery, consistency-across-trials axis), review-parity\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":4,"fit":7,"port":"methodology-only","cc":"~1 hour for docs + TODOS; ~2-3 hours per\u2026","files":["docs/designs/EVAL_ANSWER_KEYS.md (new decision record: shared structure \u2014 score the surface's OWN quoted claim vs a bare control, pre-registered KEEP/CUT/VOID falsifiers in both directions, ceiling-void rule, explicit 'what this verdict does NOT license' scope table)","docs/designs/answer-keys/{codex-decorrelation,health-trending,office-hours,review-parity,ship-consistency}.md (new, paths re-targeted)"],"basis":"cross-reference PARTIAL"},{"id":"s5-beta-human-era-anchors","title":"Retire file-count and human-day proxies (>15 files REDUCTION, 8-file complexity gate, <5-file auto-approve, 1-\u2026","kind":"judgment-rule","refs":["412f88bf"],"xref":"MISSING","residual":"Everything in the candidate: (1) eng complexity gate still keyed on '>8 files / >2 classes' rather than unjustified structure (plan-eng-review:128,147 and the t\u2026","rec":"TAKE_PARTIAL","prio":"P1","val":7,"fit":7,"port":"re-implement","cc":"~30-45 min including gen:skill-docs + bu\u2026","files":["plan-eng-review/SKILL.md.tmpl (:128 complexity check, :147 STOP trigger)","plan-ceo-review/SKILL.md.tmpl (:301, :310 complexity copies; :399 '>15 files \u2192 REDUCTION'; optionally :378-381 ratio \u2192 ETHOS pointer)"],"basis":"cross-reference MISSING"},{"id":"s5-beta-capability-priors","title":"Dated, sourced 'Capability priors' rule: never narrow scope by asserting an LLM can't do something; spike it i\u2026","kind":"judgment-rule","refs":["412f88bf"],"xref":"PARTIAL","residual":"The plan-time LLM-capability rule itself: (1) the explicit prohibition on narrowing scope, inserting human-review stages, or steering to a 'safer' variant by as\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":6,"port":"adapt","cc":"~30 min for resolver + regen + budget re\u2026","files":["scripts/resolvers/preamble/generate-evidence-directive.ts (add plan-specialist branch) or new scripts/resolvers/preamble/generate-capability-priors.ts","scripts/resolvers/preamble.ts (wire the new block for plan skills only)"],"basis":"cross-reference PARTIAL"},{"id":"s5-beta-hung-child-stall-guards","title":"E2E runners: bounded idle-stall + wall clock with real abort, PTY idle watchdog, direct spawns, leak-proof sem\u2026","kind":"test-infra","refs":["82d8b0c2"],"xref":"PARTIAL","residual":"(1) agent-sdk-runner: idle-stall ceiling + wall clock with a real AbortController abort (fork's boundedStream + ChildStallError, terminal/never-retried, env kno\u2026","rec":"TAKE_PARTIAL","prio":"P1","val":5,"fit":8,"port":"adapt","cc":"~1.5-2 hours including a free-suite run;\u2026","files":["test/helpers/agent-sdk-runner.ts (boundedStream + ChildStallError, Semaphore.acquire(timeoutMs) \u2192 'token'|'timeout', abortController in sdkOpts, env GSTACK_SDK_TIMEOUT_MS / GSTACK_SDK_IDLE_TIMEOUT_MS, per-call opts.timeoutMs/idleTimeoutMs)","test/helpers/claude-pty-runner.ts (async judgePtyState via Bun.spawn + kill timer; idle watchdog lastDataAt/idleTimeoutMs default 120s; ClaudePtySession.stallReason(); surface in runPlanSkillObservation/Counting/FloorCheck summaries)"],"basis":"cross-reference PARTIAL"},{"id":"s5-beta-bws-fail-fast-missing-binary","title":"bws E2E: fail fast in beforeAll when browse/dist/browse is missing instead of spending on a dead path","kind":"test-infra","refs":["02c9f6c7"],"xref":"MISSING","residual":"The fail-fast guard: in test/skill-e2e-bws.test.ts beforeAll (after setupBrowseShims, before the pre-warm spawnSync) `if (!fs.existsSync(browseBin)) throw new E\u2026","rec":"TAKE","prio":"P2","val":3,"fit":9,"port":"cherry-pick","cc":"~5-10 min for the beforeAll throw; ~20 m\u2026","files":["test/skill-e2e-bws.test.ts (beforeAll: throw with build command when !fs.existsSync(browseBin))","scripts/test-paid-shards.ts (optional class-level preflight alongside preflightAnthropicApi)"],"basis":"cross-reference MISSING"},{"id":"s5-beta-claude-md-always-loaded-diet","title":"Repo CLAUDE.md cut from 56KB to 17KB by moving CHANGELOG style out and deleting derivable sections","kind":"doc","refs":["5b60b65a"],"xref":"PARTIAL","residual":"Getting under the 40k-char threshold that #2096 reports (needs ~5.7KB more). Largest single move the fork made that upstream has not: relocate the full 9.2KB 'C\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":7,"port":"methodology-only","cc":"~15-20 min including bun run test and wc\u2026","files":["CLAUDE.md (:407-558 'CHANGELOG + VERSION style' body \u2192 3-line pointer; optionally 'AI effort compression' \u2192 pointer to ETHOS.md table; optionally trim 'SKILL.md workflow' duplication with CONTRIBUTING.md)","docs/CHANGELOG_STYLE.md (absorb the full section; reconcile with its existing 'Moved verbatim' header)"],"basis":"cross-reference PARTIAL"},{"id":"s5-beta-judge-slice-throwing-guards","title":"LLM-judge tests: slice helpers must throw on a missing heading instead of judging an empty string","kind":"test-infra","refs":["8dfbff93"],"xref":"PARTIAL","residual":"(1) One unguarded slice remains: the 'setup block' judge test at test/skill-llm-eval.test.ts:168-171 slices browse/SKILL.md between '## SETUP' and '## Core QA P\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":2,"fit":9,"port":"re-implement","cc":"5 min","files":["test/skill-llm-eval.test.ts"],"basis":"cross-reference PARTIAL"},{"id":"s5-beta-headed-handoff-displayless-skip","title":"Skip headed handoff integration tests on displayless Linux","kind":"test-infra","refs":["12b800ee"],"xref":"PARTIAL","residual":"No test-level guard: on a Linux box with no DISPLAY/WAYLAND_DISPLAY and without xvfb-run or sandbox-doctor, the three 'handoff integration' tests in browse/test\u2026","rec":"TAKE","prio":"P2","val":3,"fit":9,"port":"adapt","cc":"10 min","files":["browse/test/handoff.test.ts","browse/src/xvfb.ts"],"basis":"cross-reference PARTIAL"},{"id":"s8-codediff-browse-userns-sandbox-probe","title":"Linux userns sysctl probe + 'No usable sandbox' relaunch-once fallback for Chromium (#2157/#2101)","kind":"fix","refs":["4a8833cc"],"xref":"MISSING","residual":"Everything in the fork's change: (1) linuxUsernsSandboxBlockReason(readSysctl) reading /proc/sys/kernel/apparmor_restrict_unprivileged_userns==1 and /proc/sys/k\u2026","rec":"TAKE","prio":"P1","val":8,"fit":8,"port":"adapt","cc":"~30-45 min with gstack (adapt hunks, com\u2026","files":["browse/src/browser-manager.ts (shouldEnableChromiumSandbox :88-99; add linuxUsernsSandboxBlockReason, warnSandboxUnavailableOnce, isNoUsableSandboxError; relaunch-once inside the doLaunch closures at :528, :744, :1821)","browse/test/browser-manager-unit.test.ts (add the fork's 8 cases after the existing 9 at :54-120, plus a static tripwire that all three launch sites wire the fallback)"],"basis":"cross-reference MISSING"},{"id":"s8-codediff-browse-watch-snapshot-inflight","title":"Guard overlapping watch-mode snapshots with an in-flight flag","kind":"fix","refs":["5afc7c47"],"xref":"MISSING","residual":"The whole 5-line guard: `let snapshotInFlight = false` captured by the interval closure, early-return when set, set before handleSnapshot, cleared in finally. A\u2026","rec":"TAKE","prio":"P2","val":4,"fit":10,"port":"cherry-pick","cc":"~5-10 min","files":["browse/src/server.ts:1195-1208 (declare `let snapshotInFlight = false` before setInterval; early-return when set; set before handleSnapshot; clear in finally)","browse/test/watch.test.ts (optional static tripwire asserting the guard is present in the watch-interval source)"],"basis":"cross-reference MISSING"},{"id":"s8-codediff-browse-startup-timeout-names-errorlog","title":"Startup-timeout error names the missing error-log path and how to capture stderr (#2085 residual)","kind":"fix","refs":["4a8833cc"],"xref":"PARTIAL","residual":"The message itself. Upstream's timeout error still gives no pointer. The correct port is an ADAPTED string, not the fork's text: name the absent `browse-startup\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":7,"fit":9,"port":"re-implement","cc":"~15 min","files":["browse/src/cli.ts:596-605 (replace the bare timeout throw: name errorLogPath as absent, name daemonLogPath(), append a bounded tail of browse-daemon.log when present)","browse/test/ (a unit test for the ensureServer timeout branch asserting both paths appear in the message and that a present daemon log's tail is included; pattern after existing ensureServer/daemon tests such as browse/test/daemon-mismatch-refuse.test.ts)"],"basis":"cross-reference PARTIAL"},{"id":"s8-codediff-browse-confighash-includes-chromium-path","title":"Daemon-mismatch configHash includes the selected Chromium executable","kind":"fix","refs":["a84a6e23"],"xref":"MISSING","residual":"None of the fork's delta exists upstream: (a) executable folded into the D2 hash, (b) generalized mismatch message text ('browser provider, proxy, or headed mod\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":4,"fit":6,"port":"re-implement","cc":"~45 min","files":["browse/src/cli.ts (ServerState :120-136 add chromiumExecutable; extractGlobalFlags :1145 surface env.GSTACK_CHROMIUM_PATH as a separate field, not in the hash; ensureServer D2 block :687-703 add the asymmetric caller-set-and-differs refusal with a generalized disconnect hint; pass BROWSE_CHROMIUM_PATH in extraEnv near :465-468)","browse/src/server.ts (:3186 state write: record the resolved executable the daemon actually launched with)"],"basis":"cross-reference MISSING"},{"id":"s8-codediff-memory-ingest-slug-repo-gstack-home-relative","title":"memory-ingest derives slug_repo relative to GSTACK_HOME (custom roots + Windows separators)","kind":"fix","refs":["b6572ebb"],"xref":"MISSING","residual":"The 3-line replacement: import `relative as pathRelative` from path; `const rel = pathRelative(GSTACK_HOME, path).split(/[\\\\/]/); if (rel[0] === 'projects' && r\u2026","rec":"TAKE","prio":"P2","val":6,"fit":10,"port":"cherry-pick","cc":"~15 min","files":["bin/gstack-memory-ingest.ts (:57 import `relative as pathRelative`; :820-823 replace the literal /\\/\\.gstack\\/projects\\// regex with the GSTACK_HOME-relative segment check; header comment ~:21-24 `$GSTACK_HOME/projects/<slug>/...`)","test/gstack-memory-ingest.test.ts (custom GSTACK_HOME root attribution case; win32-separator case)"],"basis":"cross-reference MISSING"},{"id":"s8-codediff-gbrain-exec-strip-caller-database-url","title":"buildGbrainEnv strips the caller's DATABASE_URL when gbrain config has no database_url (PGLite engine)","kind":"fix","refs":["5fad7b07"],"xref":"MISSING","residual":"Entire fork behavior is missing: when gbrain config lacks database_url, strip DATABASE_URL and GBRAIN_DATABASE_URL from the child env, announce '[gbrain-exec] s\u2026","rec":"TAKE","prio":"P1","val":7,"fit":8,"port":"adapt","cc":"20-30 min","files":["lib/gbrain-exec.ts","test/build-gbrain-env.test.ts"],"basis":"cross-reference MISSING"},{"id":"s8-codediff-memory-helpers-yaml-manifest-parse","title":"parseSkillManifest uses Bun.YAML.parse instead of hand-rolled regex over the frontmatter block","kind":"fix","refs":["5fad7b07"],"xref":"PARTIAL","residual":"Present upstream: filter: blocks parsed (regex), item shape validation (id/kind/render_as), all six real manifests parse correctly. Missing: (a) real-YAML seman\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":3,"fit":8,"port":"adapt","cc":"15-20 min","files":["lib/gstack-memory-helpers.ts","test/gstack-memory-helpers.test.ts"],"basis":"cross-reference PARTIAL"},{"id":"s8-codediff-make-pdf-render-sentinel-invariant","title":"make-pdf render(): strip U+0000 at pipeline entry and throw if a smartypants placeholder sentinel survives (#2\u2026","kind":"fix","refs":["39f9030e"],"xref":"PARTIAL","residual":"Missing from upstream: (1) \u0000 exclusion in CODE_ZONE_RE and TAG_RE (`[^>\u0000]*` / `[^\u0000]*?` / `<[^>\u0000]+>`) \u2014 this is what actually closes the class; upstream fixed on\u2026","rec":"TAKE","prio":"P1","val":6,"fit":9,"port":"adapt","cc":"30-45 min","files":["make-pdf/src/smartypants.ts","make-pdf/src/render.ts"],"basis":"cross-reference PARTIAL"},{"id":"s8-codediff-brain-cache-gstack-config-hardcoded-path","title":"brain-cache shells out to a hardcoded ~/.claude/skills/gstack/bin/gstack-config (#1882 class)","kind":"fix","refs":["b6572ebb"],"xref":"MISSING","residual":"Entire fix missing. Fork's exact line (ref:b6572ebb bin/gstack-brain-cache:555-562) is `join(process.env.GSTACK_BIN || join(GSTACK_HOME, 'bin'), 'gstack-config'\u2026","rec":"TAKE","prio":"P1","val":6,"fit":10,"port":"adapt","cc":"10-15 min","files":["bin/gstack-brain-cache","bin/gstack-brain-context-load.ts"],"basis":"cross-reference MISSING"},{"id":"s8-codediff-slug-detached-head-branch","title":"gstack-slug maps detached HEAD to BRANCH=unknown instead of the literal 'HEAD'","kind":"fix","refs":["b6572ebb"],"xref":"MISSING","residual":"The whole fix: map `git rev-parse --abbrev-ref HEAD` == 'HEAD' to empty \u2192 'unknown' in bin/gstack-slug (one line), optionally normalize scripts/resolvers/review\u2026","rec":"TAKE","prio":"P1","val":6,"fit":10,"port":"adapt","cc":"~10 minutes","files":["bin/gstack-slug (lines 274-276: treat RAW_BRANCH == 'HEAD' as empty before sanitize \u2192 falls to 'unknown')","test/gstack-slug-sanitize.test.ts or test/branch-slug-hygiene.test.ts (new case: git init + detached checkout \u2192 BRANCH=unknown, never BRANCH=HEAD)"],"basis":"cross-reference MISSING"},{"id":"s8-codediff-gbrain-local-status-remote-classification","title":"gbrain-local-status classifies remote/thin-client engines as remote-ok | unreachable | unauthenticated","kind":"fix","refs":["5fad7b07"],"xref":"PARTIAL","residual":"(1) Typed failure-text classification of the LOCAL probe: fork's AUTH_PATTERNS (`unauthorized|authentication failed|invalid (api[ _-])?(token|key)|invalid crede\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":7,"port":"adapt","cc":"~30 minutes","files":["lib/gbrain-local-status.ts (LocalEngineStatus union :53-61; classifier :484-489 \u2014 insert classifyFailureText between broken-db and the config.json check)","bin/gstack-gbrain-sync.ts:778-790 (two new remediation strings: 'brain rejected credentials \u2014 rotate the Supabase/gbrain token' / 'brain endpoint unreachable \u2014 check network/DNS')"],"basis":"cross-reference PARTIAL"},{"id":"s8-codediff-browse-absorbed-batch","title":"Browse daemon fixes already in upstream (verified per identifier)","kind":"fix","refs":["4a8833cc","2aa255b7"],"xref":"PARTIAL","residual":"Everything enumerated (a)-(k) and the nine tests are absorbed. Four material items from the SAME fork commits are not: (1) 4a8833cc's #2157/#2101 kernel-capabil\u2026","rec":"TAKE_PARTIAL","prio":"P1","val":7,"fit":9,"port":"adapt","cc":"~1.5 hours total (sandbox 45 min, sweep \u2026","files":["browse/src/browser-manager.ts (:87-99 shouldEnableChromiumSandbox \u2192 add linuxUsernsSandboxBlockReason/warnSandboxUnavailableOnce/isNoUsableSandboxError; relaunch-once fallback at every chromium.launch site; windowsHide:true at :719-721)","browse/test/browser-manager-unit.test.ts (port fork 4a8833cc cases: apparmor_restrict_unprivileged_userns=1 \u2192 false, unprivileged_userns_clone=0 \u2192 false, missing knob \u2192 true, env override still wins, launch() relaunch-once)"],"basis":"cross-reference PARTIAL"},{"id":"s8-codediff-iosqa-absorbed-batch","title":"ios-qa daemon/template fixes already in upstream (verified per identifier)","kind":"fix","refs":["2c487305","e023fedc"],"xref":"PARTIAL","residual":"All enumerated (a)-(h) are absorbed. Residual from the same fork commits: (1) 2c487305's coordinate-mutation bundle guard \u2014 proxy sets `x-gstack-expected-bundle\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":8,"port":"adapt","cc":"~1 hour (proxy 15 min, bundle guard 30 m\u2026","files":["ios-qa/daemon/src/proxy.ts (DeviceTunnel.bundleId?, timeoutMs, settled finish(), req.on('timeout') + destroy, res.on('aborted'), 502 upstream_error, isCoordinateMutation header)","ios-qa/daemon/src/index.ts (thread bundleId from GSTACK_IOS_TARGET_BUNDLE_ID into the DeviceTunnel)"],"basis":"cross-reference PARTIAL"},{"id":"s8-codediff-bin-lib-absorbed-batch","title":"bin/ and lib/ fixes already in upstream (verified per identifier)","kind":"fix","refs":["cca23b2d","f29966d9"],"xref":"PARTIAL","residual":"Items (a)-(c) and (e)-(m) are absorbed. Item (d) is NOT: `transcript_ingest_mode=off` is a setup-time survey answer that no binary honors \u2014 a user who picked 'E\u2026","rec":"TAKE_PARTIAL","prio":"P1","val":8,"fit":8,"port":"adapt","cc":"~45 minutes (off-gate 10 min, canary 30 \u2026","files":["bin/gstack-memory-ingest.ts (:234 default sources \u2014 read transcript_ingest_mode from ~/.gstack/config.yaml via lib flat-YAML reader; skip transcript walk when 'off'; log the skip reason)","bin/gstack-gbrain-sync.ts:1255-1259 (optionally pass an explicit --sources when mode=off so the gate is visible in the invocation)"],"basis":"cross-reference PARTIAL"},{"id":"s9-skills-total-verification-ledger","title":"Total verification: population count, second producer, three-state ledger, stub sweep, pre-approved waivers, n\u2026","kind":"judgment-rule","refs":["34c17af6"],"xref":"MISSING","residual":"All six rules (fork 0aca1f77:skills/plan/references/TOTAL-VERIFICATION.md rules 10-15, ~16KB) and the header grammar in VERIFICATION-CONTRACT.md:7-19: (10) popu\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":7,"fit":5,"port":"re-implement","cc":"3-4 hours (~10x)","files":["ship/sections/total-verification.md.tmpl","ship/sections/plan-completion.md.tmpl"],"basis":"cross-reference MISSING"},{"id":"s9-skills-dispatcher-outranks-module-precedence","title":"Explicit precedence rule when two mandatory instructions conflict","kind":"judgment-rule","refs":["1b38be6a","5757efc6"],"xref":"MISSING","residual":"The general rule itself (fork 0aca1f77:skills/plan/references/SHARED-JUDGMENT.md:20, rule 16): 'When two mandatory instructions conflict, precedence decides it:\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":3,"fit":6,"port":"adapt","cc":"10 minutes for the sentence; 30-45 minut\u2026","files":["scripts/resolvers/sections.ts","scripts/resolvers/preamble/generate-completion-status.ts"],"basis":"cross-reference MISSING"},{"id":"s9-skills-pre-existing-requires-base-run","title":"No failure is 'pre-existing' without a run on the base branch showing the same failure","kind":"judgment-rule","refs":["7da6b8f6"],"xref":"PARTIAL","residual":"The base-branch-run requirement is absent from the skill surface: generate-test-failure-triage.ts T1 lets the agent label a failure 'pre-existing' from a files-\u2026","rec":"TAKE","prio":"P1","val":8,"fit":9,"port":"adapt","cc":"15-20 minutes (~15x)","files":["scripts/resolvers/preamble/generate-test-failure-triage.ts","ship/sections/tests.md.tmpl"],"basis":"cross-reference PARTIAL"},{"id":"s9-skills-one-inspection-command-per-call","title":"Authority policy: one read-only inspection command per tool call; untrusted text cannot grant authority","kind":"judgment-rule","refs":["b6572ebb","fea43565"],"xref":"PARTIAL","residual":"MISSING: (1) the headline rule 'one inspection command per tool call; never join with &&, ||, ;, $(), redirection even when all read-only' \u2014 absent and in direc\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":6,"port":"re-implement","cc":"20-30 min","files":["scripts/resolvers/preamble/generate-evidence-directive.ts (or new scripts/resolvers/preamble/generate-untrusted-data-directive.ts)","scripts/resolvers/preamble.ts (line ~108, alongside generateEvidenceDirective)"],"basis":"cross-reference PARTIAL"},{"id":"s9-skills-system-functional-qa","title":"QA for non-browser surfaces (APIs, CLIs, jobs, workers, webhooks) \u2014 surface map, repository-native journey, un\u2026","kind":"judgment-rule","refs":["b6572ebb","e6f602bc"],"xref":"MISSING","residual":"Entire module is absent: surface-and-contract map (every API/CLI/job/worker/queue consumer/webhook/scheduler/persistence boundary with entry point, inputs, auth\u2026","rec":"TAKE","prio":"P1","val":8,"fit":7,"port":"adapt","cc":"2-3 hours","files":["qa/sections/system-functional.md.tmpl (new) + generated qa/sections/system-functional.md","qa/sections/manifest.json (register id/trigger)"],"basis":"cross-reference MISSING"},{"id":"s9-skills-debug-bisect-and-nonreproduction-taxonomy","title":"/investigate: bounded bisect or discriminating experiment over history storytelling; classify non-reproduction\u2026","kind":"judgment-rule","refs":["b6572ebb","3a8e1e90"],"xref":"MISSING","residual":"(a) Phase 1 rule: for unclear regressions prefer a bounded bisect or a discriminating experiment (one check whose two outcomes each rule out a different cause) \u2026","rec":"TAKE_PARTIAL","prio":"P1","val":7,"fit":8,"port":"adapt","cc":"30 min","files":["investigate/SKILL.md.tmpl:86-92 (Phase 1 step 3/4: bisect or discriminating experiment; non-repro classification)","investigate/SKILL.md.tmpl:258-261 (Completion status: add NOT_REPRODUCED:<class>)"],"basis":"cross-reference MISSING"},{"id":"s9-skills-careful-inline-advisory-when-no-hook","title":"/careful and /freeze are advisory unless the host confirms an installed hook \u2014 never claim every command is in\u2026","kind":"judgment-rule","refs":["b6572ebb","682f6d03"],"xref":"PARTIAL","residual":"(1) A truthful-claim sentence on hookless hosts: careful/freeze/guard body still says 'Every bash command will be checked' / 'will be **blocked**' after gen-ski\u2026","rec":"TAKE","prio":"P2","val":5,"fit":8,"port":"re-implement","cc":"30 min","files":["careful/SKILL.md.tmpl:29-31 (interception claim \u2192 host-conditional resolver)","freeze/SKILL.md.tmpl:47,69 and guard/SKILL.md.tmpl:56 (same treatment for 'will be blocked')"],"basis":"cross-reference PARTIAL"},{"id":"s9-skills-review-finding-validation-gate","title":"Validate each of the reviewer's own findings (VALIDATED / REJECTED / UNCERTAIN) before Fix-First","kind":"judgment-rule","refs":["d72133e1"],"xref":"PARTIAL","residual":"(1) An explicit self-validation step between Step 4.x and Step 5 for the reviewer's OWN CRITICAL findings: exists in current code (not a diff misread), not alre\u2026","rec":"TAKE_PARTIAL","prio":"P1","val":7,"fit":8,"port":"adapt","cc":"30-45 min","files":["scripts/resolvers/confidence.ts:40-54 (Pre-emit gate: add the three validation checks + VALIDATED/REJECTED/UNCERTAIN mapping)","review/checklist.md:172-183 (Suppressions: add #610 FP-checklist items)"],"basis":"cross-reference PARTIAL"},{"id":"s9-skills-ship-breaking-change-over-linecount","title":"Semantic breaking-change analysis overrides line-count bump heuristics, even for small diffs","kind":"judgment-rule","refs":["b6572ebb"],"xref":"PARTIAL","residual":"(1) A Step 12 pre-classification rule: before settling on MICRO/PATCH, scan the diff for anything a consumer relies on (API response shapes, exported signatures\u2026","rec":"TAKE_PARTIAL","prio":"P1","val":7,"fit":9,"port":"adapt","cc":"~15 min","files":["ship/SKILL.md.tmpl","ship/SKILL.md"],"basis":"cross-reference PARTIAL"},{"id":"s9-skills-ship-smallest-release-convention","title":"Honor the repo's release convention at its smallest size; don't invent VERSION/CHANGELOG for a two-file change","kind":"judgment-rule","refs":["3a8e1e90"],"xref":"MISSING","residual":"Everything: (a) a trigger that classifies a change as trivial from the prompt + diffstat before loading the release apparatus; (b) a Step 12 branch keyed on `ve\u2026","rec":"TAKE_PARTIAL","prio":"P1","val":7,"fit":7,"port":"re-implement","cc":"~45 min","files":["ship/SKILL.md.tmpl","scripts/resolvers/utility.ts"],"basis":"cross-reference MISSING"},{"id":"s9-skills-browser-providers-host-native","title":"Host-native browser provider routing (Claude in Chrome, Codex built-in, Gemini browser_agent, Cursor, Copilot/\u2026","kind":"judgment-rule","refs":["d6ef673e","a84a6e23"],"xref":"MISSING","residual":"All of it is absent, but it splits into two very different port candidates: (A) the provider-routing doc itself (nine host sections, callable-tool-only detectio\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":4,"fit":4,"port":"re-implement","cc":"~30 min","files":["browse/test/fixtures/readiness.html","browse/test/helpers/readiness-server.ts"],"basis":"cross-reference MISSING"},{"id":"s9-skills-eng-review-pre-mortem-and-data-model","title":"/plan-eng-review: pre-mortem before the scope challenge; normalized data model as the default","kind":"judgment-rule","refs":["d72133e1"],"xref":"MISSING","residual":"Both rules entirely: (1) a pre-mortem ('three months later, why did it fail \u2014 top 3 concrete production failure modes: data loss, performance cliff, security ho\u2026","rec":"TAKE_PARTIAL","prio":"P1","val":8,"fit":8,"port":"adapt","cc":"~1 hour, plus one periodic eval run to v\u2026","files":["plan-eng-review/SKILL.md.tmpl","plan-eng-review/sections/review-sections.md.tmpl"],"basis":"cross-reference MISSING"},{"id":"s9-skills-review-claudemd-review-section","title":"/review reads a repo-owned `## Review` section from CLAUDE.md as additive calibration","kind":"judgment-rule","refs":["ec0b8515"],"xref":"MISSING","residual":"The whole rule: before Scope Drift Detection, read a `## Review` section from the project CLAUDE.md and apply it additively (scope rules + intent source of trut\u2026","rec":"TAKE","prio":"P1","val":7,"fit":10,"port":"adapt","cc":"~20 min","files":["scripts/resolvers/review.ts","review/SKILL.md"],"basis":"cross-reference MISSING"},{"id":"s9-skills-open-pr-distillations-misc","title":"Eleven more one-paragraph distillations of still-open upstream community PRs (cso --fix boundary, shai-hulud I\u2026","kind":"judgment-rule","refs":["d72133e1","ec0b8515"],"xref":"PARTIAL","residual":"Per sub-item, what upstream HEAD still lacks: (1) #1053: no `--fix` opt-in or safe-pattern whitelist; more usefully, no sentence resolving the :314 'Fix now' vs\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":8,"port":"adapt","cc":"~45-60 min (~20x)","files":["bin/gstack-taste-update","test/taste-engine.test.ts"],"basis":"cross-reference PARTIAL"},{"id":"gap4-s13-ios-xcuitest-tap-oracle-judgment-rule","title":"Judgment rule: a tap with an unchanged oracle is an interaction failure, not a product defect (retry once elem\u2026","kind":"judgment-rule","refs":["c2ac1f32","time-attack/gstack PR #14"],"xref":"PARTIAL","residual":"The rule as SKILL PROSE (absent in both ios-qa and ios-fix): (a) before recording any finding from a tap, require an oracle change \u2014 the control's /elements val\u2026","rec":"TAKE","prio":"P2","val":7,"fit":9,"port":"re-implement","cc":"15 min for the prose + regen + budget ca\u2026","files":["ios-qa/SKILL.md.tmpl:181-188 (Phase 3 step 7: replace 'Re-screenshot; compare; record finding if buggy.' with the oracle \u2192 one element-anchored trailing-edge retry from the live /elements frame \u2192 BLOCKED-interaction-failure-not-defect ladder; plus 'no element resolves \u2192 BLOCKED/UNSUPPORTED, never a guessed coordinate')","ios-fix/SKILL.md.tmpl:46-49 (Phase 1 step 2: verify the bug state was actually reached via /elements value, /state/snapshot key, or screenshot hash before capturing the -pre fixture; if the tap did not take, report interaction failure rather than 'could not reproduce')"],"basis":"cross-reference PARTIAL"},{"id":"gap4-s13-ios-xcuitest-flow-runner","title":"JSON-driven XCUITest flow runner (GStackFlowRunnerUITests.swift) \u2014 drives any app by bundle id with semantic s\u2026","kind":"feature","refs":["c2ac1f32","time-attack/gstack PR #14"],"xref":"MISSING","residual":"Entire feature: GStackFlowRunnerUITests.swift (263 lines \u2014 v1 flow decode from GSTACK_IOS_QA_FLOW_JSON_BASE64 / GSTACK_IOS_QA_FLOW_PATH, XCUIApplication(bundleI\u2026","rec":"DEFER","prio":"P3","val":5,"fit":3,"port":"methodology-only","cc":"Half a day for the mechanical port and a\u2026","files":["TODOS.md (new P3 entry: 'ios-qa: no-bridge lane for Release/TestFlight/third-party apps \u2014 XCUITest flow runner from time-attack PR #14 / c2ac1f32; decision needed vs tmpl:41; prerequisites: automatic signing, deploymentTarget 17.0, macOS runner lane, semantic-selector contract')","(if adopted later) test/fixtures/ios-qa/FixtureApp/Tests/AdaptiveFixtureUITests/GStackFlowRunnerUITests.swift"],"basis":"cross-reference MISSING"},{"id":"gap4-s13-ios-xcuitest-adaptive-fixture-apps","title":"SwiftUI + UIKit 'QA gallery' fixture apps with hostile-UI cases (nested horizontal scroll, 35-row list, occlud\u2026","kind":"test-infra","refs":["c2ac1f32","time-attack/gstack PR #14"],"xref":"PARTIAL","residual":"Fork's AdaptiveSwiftUIFixtureApp.swift (79 lines), AdaptiveUIKitFixtureApp.swift (85 lines), two Info.plists, AdaptiveFixtureUITests.swift (56 lines) and projec\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":5,"fit":7,"port":"adapt","cc":"30-45 min to add an 'Adversarial' tab (o\u2026","files":["test/fixtures/ios-qa/FixtureApp/Sources/FixtureApp/FixtureAppApp.swift (new tab 'tab-adversarial' with stable accessibility identifiers: harness-occluded / harness-occluder, harness-hscroll + harness-card-N, harness-alert-open / Confirm oracle, harness-sheet-open / Done, harness-disabled, harness-row-N with detail)","test/skill-e2e-ios-device.test.ts (new cases using tapAndWaitForCountIncrement / tapAndWaitForValueChange at :578-640: horizontal swipe scrolls the CONTAINER not the screen (card-11 becomes tappableIn viewport while a vertical-tab element stays put); occluded control does/does-not activate per the decided contract; alert Confirm +10; sheet Done; disabled button no-op with count unchanged)"],"basis":"cross-reference PARTIAL"},{"id":"gap4-s13-ios-xcuitest-physical-device-doc","title":"IOS-PHYSICAL-DEVICE.md: setup-gate table with exact remediations, hardware UDID vs CoreDevice UUID explainer, \u2026","kind":"doc","refs":["7d760ff1","c0f280db"],"xref":"PARTIAL","residual":"Upstream lacks every doc-level piece except the pairing/Developer-Mode/Trust basics: (1) a setup-gates table with one-line remediations \u2014 Full Xcode selected (`\u2026","rec":"TAKE","prio":"P2","val":7,"fit":9,"port":"adapt","cc":"20-30 min doc port; +1 hr if a real iPho\u2026","files":["docs/howto-ios-testing-with-gstack.md","ios-qa/SKILL.md.tmpl"],"basis":"cross-reference PARTIAL"},{"id":"gap4-s13-ios-xcuitest-evidence-schema","title":"Redacted real-device evidence artifact: fingerprint-only device identity, per-iteration check records, refuse-\u2026","kind":"methodology","refs":["c0f280db","b0ea2296"],"xref":"MISSING","residual":"Everything: the `gstack-ios-qa-physical-device` schemaVersion-1 shape (toolchain{developerDir,xcodeVersion,xcodeBuildVersion,xcodegenVersion,devicectlPath,devTo\u2026","rec":"DEFER","prio":"P3","val":4,"fit":6,"port":"methodology-only","cc":"~1 hr inside the harness port; 15 min fo\u2026","files":["ios-qa/SKILL.md.tmpl","docs/howto-ios-testing-with-gstack.md"],"basis":"cross-reference MISSING"},{"id":"gap1-s10-browsewave-flutter-web-snapshot","title":"Flutter Web support for snapshot/accessibility (enable flt-semantics, CSS-selector @refs)","kind":"feature","refs":["d947d2e1","d98e4839"],"xref":"MISSING","residual":"All of it: isFlutterWeb (flutter-view / flt-glass-pane / $isFlutterApp detection), enableFlutterSemantics (click the off-screen flt-semantics-placeholder), scan\u2026","rec":"TAKE","prio":"P2","val":5,"fit":8,"port":"cherry-pick","cc":"30-45 min port + one manual real-Flutter\u2026","files":["browse/src/snapshot.ts (isFlutterWeb, enableFlutterSemantics, scanFlutterSemantics, flutterNodesToAriaYaml, handleSnapshot Flutter branch + index alignment, header comment)","browse/src/read-commands.ts (:376 'accessibility' Flutter redirect)"],"basis":"cross-reference MISSING"},{"id":"gap1-s10-browsewave-default-viewport-and-viewport-auto","title":"BROWSE_VIEWPORT default viewport + `viewport auto|reset|unpin` to unpin without restart","kind":"feature","refs":["d947d2e1","fc58b767"],"xref":"MISSING","residual":"Entire feature pair is absent. Sub-pieces upstream lacks: (a) getDefaultViewport() env parser (BROWSE_VIEWPORT=WxH, clamp 320-7680 x 240-4320, 1280x720 fallback\u2026","rec":"TAKE","prio":"P2","val":6,"fit":8,"port":"cherry-pick","cc":"20-30 min","files":["browse/src/browser-manager.ts","browse/src/write-commands.ts"],"basis":"cross-reference MISSING"},{"id":"gap1-s10-browsewave-cdp-allowlist-geolocation-mouse","title":"CDP allowlist: Emulation.setGeolocationOverride/clearGeolocationOverride + Input.dispatchMouseEvent","kind":"feature","refs":["d947d2e1","b511b058"],"xref":"MISSING","residual":"All three entries are absent: Emulation.setGeolocationOverride (tab/trusted), Emulation.clearGeolocationOverride (tab/trusted, cleanup symmetry with clearDevice\u2026","rec":"TAKE","prio":"P2","val":5,"fit":9,"port":"cherry-pick","cc":"10 min","files":["browse/src/cdp-allowlist.ts","browse/test/cdp-allowlist.test.ts"],"basis":"cross-reference MISSING"},{"id":"gap1-s10-browsewave-record-video","title":"`browse record start|stop|status` \u2014 .webm video evidence via Playwright recordVideo","kind":"feature","refs":["d947d2e1","d87cb066"],"xref":"MISSING","residual":"Upstream has no `record` command at all \u2014 the whole feature (browser-manager recordVideo fields + start/stop/status, meta-command, commands.ts registration, tes\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":7,"fit":7,"port":"adapt","cc":"1.5-2 hours","files":["browse/src/browser-manager.ts","browse/src/meta-commands.ts"],"basis":"cross-reference MISSING"},{"id":"gap1-s10-browsewave-screenshot-clip-equals","title":"screenshot accepts `--clip=x,y,w,h` (equals-sign form)","kind":"fix","refs":["d947d2e1","499f39d3"],"xref":"MISSING","residual":"The 2-line parser change (accept `args[i].startsWith('--clip=')` and slice the value) is absent. Neither the fork nor PR #1563 adds a test; a port should add a \u2026","rec":"TAKE","prio":"P3","val":3,"fit":10,"port":"cherry-pick","cc":"5 min","files":["browse/src/meta-commands.ts","browse/test/commands.test.ts"],"basis":"cross-reference MISSING"},{"id":"gap1-s10-browsewave-prettyscreenshot-path-after-hide","title":"prettyscreenshot keeps its output path when it follows `--hide sel...`","kind":"fix","refs":["d947d2e1","b8856597"],"xref":"MISSING","residual":"Everything in b8856597 is absent: exported PrettyScreenshotOptions interface, isLikelyScreenshotOutputPath() heuristic (leading `/`, `./`, `../`, `~`, or .png/.\u2026","rec":"TAKE","prio":"P2","val":6,"fit":9,"port":"cherry-pick","cc":"15 min","files":["browse/src/write-commands.ts","browse/test/prettyscreenshot-args.test.ts (new)"],"basis":"cross-reference MISSING"},{"id":"gap1-s10-browsewave-launch-overrides-http-credentials","title":"Env-driven Chromium launch overrides (GSTACK_CHROMIUM_ARGS) + origin-scoped HTTP basic-auth credentials","kind":"feature","refs":["d947d2e1","679bad32"],"xref":"MISSING","residual":"Everything: (1) browse/src/launch-overrides.ts module \u2014 parseExtraChromiumArgs (JSON string-array or whitespace list, wrapping-quote strip, blank filtering) and\u2026","rec":"TAKE","prio":"P2","val":6,"fit":8,"port":"adapt","cc":"30 min","files":["browse/src/launch-overrides.ts (new; take fork file at origin/time-attack/gstack head \u2014 fail-closed version)","browse/test/launch-overrides.test.ts (new; 15 tests from 679bad32+b31c43a1, adjust the 2 origin tests to assert undefined when unscoped per 4fd172db)"],"basis":"cross-reference MISSING"},{"id":"gap1-s10-browsewave-extra-extensions","title":"GSTACK_EXTRA_EXTENSIONS: load additional unpacked Chrome extensions alongside the sidebar","kind":"feature","refs":["d947d2e1","9f60de1b"],"xref":"MISSING","residual":"Entire feature: findExtraExtensionPaths() (comma-split GSTACK_EXTRA_EXTENSIONS, require manifest.json, warn+skip invalid entries) merged into both `--disable-ex\u2026","rec":"TAKE","prio":"P3","val":5,"fit":8,"port":"adapt","cc":"20 min","files":["browse/src/launch-overrides.ts (add parseExtraExtensionPaths, or new small helper)","browse/src/browser-manager.ts:630-637 (launchHeaded: join gstack ext + extras; extras-only --load-extension under isCustomChromium())"],"basis":"cross-reference MISSING"},{"id":"gap1-s10-browsewave-vpn-tun-no-proxy","title":"BROWSE_NO_PROXY=1 bypasses system proxy, auto-skipping when a VPN TUN (utun 198.18.x) would break TLS","kind":"feature","refs":["d947d2e1","263529eb"],"xref":"MISSING","residual":"Entire feature: BROWSE_NO_PROXY=1 -> `--proxy-server=direct://` in headless launch(); darwin-only `ifconfig` probe (2s timeout) for a utun interface with inet 1\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":4,"fit":6,"port":"re-implement","cc":"30-45 min","files":["browse/src/proxy-config.ts (BROWSE_NO_PROXY=1|force -> direct:// server; refuse when combined with BROWSE_PROXY_URL/--proxy; optional darwin utun 198.18.x probe)","browse/test/proxy-config.test.ts (new cases: =1, =force, conflict refusal, TUN skip via injected ifconfig output)"],"basis":"cross-reference MISSING"},{"id":"gap1-s10-browsewave-patchright-stealth-backend","title":"Optional patchright backend (GSTACK_STEALTH_BACKEND=patchright) to close the CDP Runtime.Enable leak","kind":"feature","refs":["d947d2e1","fedff3c9"],"xref":"MISSING","residual":"None of the fork's sub-pieces exist upstream: GSTACK_STEALTH_BACKEND=patchright env switch; cached getChromium() dynamic `import('patchright')` with fallback-to\u2026","rec":"SKIP","prio":"P3","val":4,"fit":3,"port":"n/a","cc":"1 hour (plus ongoing per-Playwright-bump\u2026","files":[],"basis":"cross-reference MISSING"},{"id":"gap1-s10-browsewave-chromium-path-setup-probe","title":"setup's Playwright launch probe honors GSTACK_CHROMIUM_PATH (NixOS / custom Chromium)","kind":"fix","refs":["d947d2e1","34aaa03e"],"xref":"MISSING","residual":"BOTH halves of fork commit 34aaa03e are missing (the brief's 'headless already absorbed' premise is incorrect): (1) headless launch(): pass executablePath from \u2026","rec":"TAKE","prio":"P1","val":6,"fit":9,"port":"re-implement","cc":"30 min","files":["browse/src/browser-manager.ts:523-551 (headless launch: executablePath from GSTACK_CHROMIUM_PATH + usesCustomExecutable + fix comment :525-527)","browse/src/browser-manager.ts:1800-1836 (handoff: decide parity; at minimum update comments)"],"basis":"cross-reference MISSING"},{"id":"gap1-s10-browsewave-claude-config-dir","title":"Honor $CLAUDE_CONFIG_DIR in setup's skills dir, binary discovery, and session scan (#349)","kind":"fix","refs":["d947d2e1","094009fe"],"xref":"PARTIAL","residual":"Three of the fork's four hunks are absent: (1) setup installer CLAUDE_SKILLS_DIR (setup:1707) \u2014 the exact item TODOS.md:123-128 leaves open; (2) find-browse glo\u2026","rec":"TAKE","prio":"P2","val":6,"fit":9,"port":"adapt","cc":"30-45 min","files":["setup","browse/src/find-browse.ts"],"basis":"cross-reference PARTIAL"},{"id":"gap1-s10-browsewave-bun-compile-wrapper-fallback","title":"scripts/build.sh falls back to `bun run` wrappers when `bun build --compile` fails (#407 virtiofs/devcontainer\u2026","kind":"fix","refs":["d947d2e1","90633c36"],"xref":"MISSING","residual":"Everything: the build_or_wrap helper (try compile, on failure write a '#!/usr/bin/env bash; SCRIPT_DIR=$(cd $(dirname ${BASH_SOURCE[0]}) && pwd -P); exec bun ru\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":7,"port":"adapt","cc":"30 min","files":["scripts/build.sh","setup"],"basis":"cross-reference MISSING"},{"id":"gap1-s10-browsewave-windows-codex-lazy-server-script","title":"Lazy-resolve SERVER_SCRIPT so Windows Codex layouts without browse/src/server.ts don't crash at CLI load (#797\u2026","kind":"fix","refs":["d947d2e1","0532a2e2"],"xref":"MISSING","residual":"The whole change: 'const SERVER_SCRIPT = IS_WINDOWS ? null : resolveServerScript();' (cli.ts:87) plus 'SERVER_SCRIPT!' at the single POSIX spawn site (cli.ts:56\u2026","rec":"TAKE","prio":"P2","val":5,"fit":9,"port":"cherry-pick","cc":"10-15 min","files":["browse/src/cli.ts","browse/test/config.test.ts (or new static tripwire test)"],"basis":"cross-reference MISSING"},{"id":"gap1-s10-browsewave-bun-pascalcase-connection-codes","title":"sendCommand recognizes Bun's PascalCase fetch error codes (ConnectionRefused/Reset/Closed, 'Unable to connect'\u2026","kind":"fix","refs":["d947d2e1","ab275bb7"],"xref":"PARTIAL","residual":"The condition widening itself is absent: add \"|| err.code === 'ConnectionRefused' || err.message?.includes('Unable to connect')\" (both confirmed on Bun 1.3.10) \u2026","rec":"TAKE","prio":"P2","val":5,"fit":10,"port":"adapt","cc":"15 min","files":["browse/src/cli.ts","browse/src/browse-client.ts"],"basis":"cross-reference PARTIAL"},{"id":"gap1-s10-browsewave-windows-mkdirsecure-eexist","title":"mkdirSecure tolerates Bun-on-Windows EEXIST from recursive mkdirSync (#1601)","kind":"fix","refs":["d947d2e1","05f1efbe"],"xref":"PARTIAL","residual":"The browse half only: mkdirSecure (browse/src/file-permissions.ts:336-347) still lacks the dir-confirmed EEXIST tolerance that upstream already ships as lib/fs-\u2026","rec":"TAKE","prio":"P2","val":6,"fit":10,"port":"re-implement","cc":"15 min","files":["lib/fs-utils.ts","browse/src/file-permissions.ts"],"basis":"cross-reference PARTIAL"},{"id":"gap1-s10-browsewave-cookie-import-cdp-pipe","title":"Windows cookie import over --remote-debugging-pipe (closes the v20 ABE same-user exfiltration window)","kind":"security","refs":["d947d2e1","54286330"],"xref":"MISSING","residual":"Everything is missing. Concretely: (1) `CdpPipeTransport` class (NUL-delimited JSON framing over two Node streams, id-correlated pending map, abortAll on read '\u2026","rec":"TAKE","prio":"P1","val":7,"fit":8,"port":"adapt","cc":"1-2 hours code + tests; Windows verifica\u2026","files":["browse/src/cookie-import-browser.ts (replace :858-999: debugPort spawn, /json/version + /json/list polling, extractCookiesViaCdp WebSocket client \u2192 buildCdpSpawnArgs + node:child_process spawn with stdio ['ignore','pipe','pipe','pipe','pipe'] + windowsHide, chromeProc.on('error'), CdpPipeTransport, cdpSendTimeoutMs/GSTACK_CDP_SEND_TIMEOUT_MS, extractCookiesViaCdpPipe; delete the KNOWN NON-GOAL comment at :843-855)","browse/test/cookie-import-browser.test.ts (add the fork's describe('CdpPipeTransport') 12 tests, describe('extractCookiesViaCdpPipe') 6 tests, describe('buildCdpSpawnArgs') 4 tests \u2014 source: origin/time-attack/gstack:browse/test/cookie-import-browser.test.ts:667-1020)"],"basis":"cross-reference MISSING"},{"id":"gap1-s10-browsewave-cookie-import-decrypt-debug-log","title":"Log per-cookie decrypt failures behind GSTACK_DEBUG=1 instead of silently counting them","kind":"fix","refs":["d947d2e1","f37408d9"],"xref":"MISSING","residual":"The entire change: replace `catch { failed++; }` with `catch (err: any) { failed++; if (debug) console.error(`[cookie-import] decrypt failed for ${row.host_key}\u2026","rec":"TAKE","prio":"P2","val":5,"fit":9,"port":"cherry-pick","cc":"10 minutes","files":["browse/src/cookie-import-browser.ts:281-283 (replace `catch { failed++; }` with a catch that logs `[cookie-import] decrypt failed for ${row.host_key}/${row.name} [${err.code}]: ${err.message}` to stderr when BROWSE_DEBUG is set)","browse/test/cookie-import-browser.test.ts (stub decryptCookieValue to throw, assert stderr line under BROWSE_DEBUG and silence without it)"],"basis":"cross-reference MISSING"},{"id":"gap1-s10-browsewave-codex-subagent-vocabulary","title":"Codex host toolRewrites: translate Claude-only subagent/Agent-tool phrasing in generated skills (#1162)","kind":"fix","refs":["d947d2e1","cdd1c8a5"],"xref":"MISSING","residual":"The whole `toolRewrites` map for codex (13 entries after the 466de5fe trim: \"Claude Code's Agent tool\", the six 'Claude <role> subagent' \u2192 'independent <role> s\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":8,"port":"adapt","cc":"20-30 minutes","files":["hosts/codex.ts (add toolRewrites map \u2014 the fork's trimmed list from origin/time-attack/gstack:hosts/codex.ts:38-58, extended with 'on the Agent call' / 'the Agent call block' / 'never the Skill tool' entries re-authored against HEAD prose)","scripts/resolvers/constants.ts (and/or the four ship/sections/*.md sites) \u2014 gate the Claude-Code-specific 'Foreground required: pass run_in_background: false ... since Claude Code v2.1.198' paragraph on ctx.host !== 'codex', matching the existing review.ts:326 pattern"],"basis":"cross-reference MISSING"},{"id":"gap1-s10-browsewave-remote-control-auq-fallback","title":"REMOTE_CONTROL preamble signal + prose-brief fallback when AskUserQuestion renders unclickable (#459)","kind":"judgment-rule","refs":["d947d2e1","ce7cddce"],"xref":"MISSING","residual":"All of it: (1) a `REMOTE_CONTROL: <value>` STATUS echo \u2014 port target is bin/gstack-skill-start beside the CONDUCTOR_SESSION block at :111-119 (not generate-prea\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":7,"port":"re-implement","cc":"20 minutes","files":["bin/gstack-skill-start (~:119, beside the CONDUCTOR_SESSION echo: `REMOTE_CONTROL: <env GSTACK_REMOTE_CONTROL | gstack-config get remote_control | 0>`, gated on !headless && !spawned)","bin/gstack-config (lookup_default :141-197 add `remote_control) echo \"0\"`; the `list`/`defaults` KEY loops at :454/:471; a warn-and-default 0|1 validation in the `set` block :396-426)"],"basis":"cross-reference MISSING"},{"id":"gap1-s10-browsewave-learnings-limits-config","title":"Configurable learnings search limits: learnings_preamble_limit / learnings_skill_limit (#1514)","kind":"feature","refs":["d947d2e1","ce7cddce"],"xref":"MISSING","residual":"All of it: (1) `learnings_preamble_limit` (default 3) and `learnings_skill_limit` (default 10) in bin/gstack-config lookup_default plus the `list`/`defaults` en\u2026","rec":"TAKE","prio":"P3","val":4,"fit":9,"port":"re-implement","cc":"15 minutes","files":["bin/gstack-config (lookup_default :141-197: `learnings_preamble_limit) echo \"3\"`, `learnings_skill_limit) echo \"10\"`; `list`/`defaults` loops :454/:471; bounded-int validation in `set` :396-426)","scripts/resolvers/learnings.ts (:47 basic-host branch and :62/:64 full branch: read `_LEARN_SKILL_LIMIT=$(gstack-config get learnings_skill_limit 2>/dev/null || echo 10)` and pass `--limit $_LEARN_SKILL_LIMIT`)"],"basis":"cross-reference MISSING"},{"id":"gap1-s10-browsewave-sessions-echo","title":"Preamble echoes the concurrent SESSIONS count so CLAUDE.md rules can read it (#1747 / #1651 Defect A)","kind":"fix","refs":["d947d2e1","f848a916"],"xref":"MISSING","residual":"Everything in the candidate: (1) compute the count in bin/gstack-skill-start right after line 80: `_SESSIONS=$(find \"$_GH/sessions\" -mmin -120 -type f 2>/dev/nu\u2026","rec":"TAKE","prio":"P3","val":3,"fit":9,"port":"re-implement","cc":"5 minutes","files":["bin/gstack-skill-start","test/gstack-skill-start.test.ts"],"basis":"cross-reference MISSING"},{"id":"gap1-s10-browsewave-windows-console-flash-suite","title":"Windows console-flash + watchdog split-brain suite (windowsHide everywhere, signal-0 liveness, trippable respa\u2026","kind":"fix","refs":["d947d2e1","28f0a0de"],"xref":"PARTIAL","residual":"Only the #1784 sub-claim: issue #1784 (Win32_ProcessStartTrace on bun 1.3.11) says `Bun.spawnSync` does NOT honor `windowsHide`, so upstream's five real-Bun col\u2026","rec":"DEFER","prio":"P2","val":5,"fit":5,"port":"cherry-pick","cc":"Verification still needs a human Windows\u2026","files":["browse/src/cli.ts:192-195 (taskkill) and :548 (node -e launcher)","browse/src/config.ts:34,89,164 (git probes)"],"basis":"cross-reference PARTIAL"},{"id":"gap1-s10-browsewave-auto-cookie-persistence","title":"Opt-in auto-cookie persistence: per-workspace lock, mutation-triggered checkpoints, persistent-cookies-only (#\u2026","kind":"feature","refs":["d947d2e1","b3433ecb"],"xref":"PARTIAL","residual":"(1) Per-workspace mkdir-atomic lock held for the daemon lifetime (fork auto-cookie-persist.ts:184-280: owner.json pid+startedAt, dead-pid reclaim, pid-reuse che\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":7,"port":"re-implement","cc":"1-2 hours","files":["browse/src/session-persist.ts (filterSessionCookies: expires type/NaN/Infinity/already-expired + case-fold; persistSessionState: unique same-dir temp + fsync; lock acquire/release)","browse/src/file-permissions.ts (add writeSecureFileAtomic alongside writeSecureFile:114-352)"],"basis":"cross-reference PARTIAL"},{"id":"gap1-s10-browsewave-untrusted-content-hardening-prose","title":"Skill-prose hardening across investigate/browse/qa/canary/ship: untrusted error output, JS read-only, canary v\u2026","kind":"judgment-rule","refs":["d947d2e1","e40b0ef8"],"xref":"MISSING","residual":"All five rule sets from fork e40b0ef8 (origin/time-attack/gstack): (a) browse resolver rule 5 + JS-execution read-only constraints + session-isolation guidance \u2026","rec":"TAKE_PARTIAL","prio":"P1","val":7,"fit":8,"port":"adapt","cc":"30-45 minutes","files":["scripts/resolvers/browse.ts:11-20 (UNTRUSTED_CONTENT_WARNING rule 5 + JS execution constraints \u2014 single source so /scrape and /skillify inherit)","investigate/SKILL.md.tmpl:82-92 (untrusted error output guard; `git bisect run`; non-reproducible taxonomy)"],"basis":"cross-reference MISSING"},{"id":"gap1-s10-browsewave-daemon-reuse-regression-test","title":"Regression test: two CLI invocations reuse one daemon pid and page state survives (#456 surviving hunk)","kind":"test-infra","refs":["d947d2e1","e624751f"],"xref":"MISSING","residual":"The 41-line test from fork e624751f (origin/time-attack/gstack, browse/test/commands.test.ts +41): spawn `bun run cli.ts goto <baseUrl>/basic.html`, read pid fr\u2026","rec":"TAKE","prio":"P3","val":3,"fit":9,"port":"adapt","cc":"10 minutes","files":["browse/test/commands.test.ts:929-971 (add second test to describe('CLI lifecycle'))"],"basis":"cross-reference MISSING"},{"id":"gap1-s10-browsewave-portable-profile-fallback-test","title":"config.test.ts: build the chromium-profile fallback expectation with path.join (#2167)","kind":"test-infra","refs":["d947d2e1","b358b658"],"xref":"MISSING","residual":"The entire fix is missing: upstream line 440 still compares against a literal forward-slash path. Fork commit b358b658 (author daehyeonxyz, carried into fork ma\u2026","rec":"TAKE","prio":"P2","val":3,"fit":10,"port":"cherry-pick","cc":"2 min","files":["browse/test/config.test.ts"],"basis":"cross-reference MISSING"},{"id":"gap3-hosts-four-declarative-host-configs-pi-agy-vibe-qoder","title":"Pi, Antigravity (agy), Mistral Vibe, Qoder host configs (+ print-only/install setup arms, README rows)","kind":"feature","refs":["31157f98 (abdul, #1918)","2c857183"],"xref":"MISSING","residual":"All four hosts in full: hosts/pi.ts (globalRoot .pi/agent/skills/gstack, localSkillRoot .pi/skills/gstack, descriptionLimit 1024 + 'warn', lowercase tool rewrit\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":7,"port":"adapt","cc":"~45-60 min (~25x); qoder full install ar\u2026","files":["hosts/pi.ts (prefer landing OPEN #2507 rebased, not the fork's #1918 config)","hosts/agy.ts (new defineHost override; resolve the .agents localSkillRoot collision first)"],"basis":"cross-reference MISSING"},{"id":"gap3-hosts-grok-build-packaging-and-compat-audit","title":"Grok Build (xAI) host: fail-closed staged runtime root, bin/gstack-grok-compat-audit, section-pointer generali\u2026","kind":"feature","refs":["f0307dce (Nehr / @AgileInnov8tor, #2248)","a553876d"],"xref":"MISSING","residual":"The whole Grok Build host slice: hosts/grok-build.ts (keeps triggers/allowed-tools frontmatter, AskUserQuestion\u2192ask_user_question, ExitPlanMode\u2192exit_plan_mode, \u2026","rec":"TAKE_PARTIAL","prio":"P1","val":6,"fit":4,"port":"re-implement","cc":"make-pdf fix: ~20-30 min (var + link lis\u2026","files":["scripts/resolvers/preamble/generate-preamble-bash.ts (add GSTACK_MAKE_PDF=\"$GSTACK_ROOT/make-pdf/dist\")","hosts/define-host.ts (add 'make-pdf/dist' to the default runtimeRoot globalSymlinks, or per-host in codex/factory/opencode/cursor/kiro)"],"basis":"cross-reference MISSING"},{"id":"gap3-hosts-agent-tool-phrasing-sweeps","title":"toolRewrites catch every 'Agent tool' phrasing on agent-runtime hosts (#1935)","kind":"fix","refs":["d795266e (katlun-lgtm, #1935)","b6f16e4c (katlun-lgtm)"],"xref":"MISSING","residual":"All of it: the article-first + bare-sweep map entries \u2014 hermes `'the Agent tool'|'Agent tool' \u2192 'delegate_task'`, gbrain/openclaw \u2192 'sessions_spawn' (best added\u2026","rec":"TAKE","prio":"P2","val":6,"fit":9,"port":"cherry-pick","cc":"~20-30 min (~15x)","files":["hosts/define-host.ts (EXEC_STYLE_TOOL_REWRITES: add 'the Agent tool' and 'Agent tool' \u2192 'sessions_spawn' once \u2014 openclaw.ts:10 and gbrain.ts:21 spread it)","hosts/hermes.ts (add 'the Agent tool' / 'Agent tool' \u2192 'delegate_task')"],"basis":"cross-reference MISSING"},{"id":"gap3-hosts-codex-request-user-input-rewrite","title":"Codex host: AskUserQuestion -> request_user_input tool rewrite (#1101)","kind":"fix","refs":["a72088f2 (jacob-wang / @JiayuuWang, #1101)","151de582"],"xref":"MISSING","residual":"Entire mechanism: hosts/codex.ts `toolRewrites: { AskUserQuestion: 'request_user_input' }` (fork a72088f2) and the static regression test 'toolRewrites: Codex s\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":4,"fit":5,"port":"re-implement","cc":"15 min","files":["scripts/resolvers/preamble/generate-ask-user-format.ts","hosts/codex.ts"],"basis":"cross-reference MISSING"},{"id":"gap3-hosts-codex-design-dist-runtime-root","title":"Codex runtime root + .agents sidecar link design/dist (#1160)","kind":"fix","refs":["d1ac2799 (Mammad M. / @mamedov, #1160)","f0307dce"],"xref":"PARTIAL","residual":"Setup side: `_link_or_copy \"$gstack_dir/design/dist\" \"$codex_gstack/design/dist\"` (+ mkdir of $codex_gstack/design) in create_codex_runtime_root, and `design` a\u2026","rec":"TAKE","prio":"P1","val":7,"fit":9,"port":"adapt","cc":"20 min","files":["setup","hosts/codex.ts"],"basis":"cross-reference PARTIAL"},{"id":"gap3-hosts-codex-agents-skills-install-root-and-migration","title":"Codex global install moved to ~/.agents/skills with v1.61.0.0 migration (#2123)","kind":"fix","refs":["df1fbf63 (dpattonux, #2123)","151de582"],"xref":"MISSING","residual":"All of it: CODEX_SKILLS default \u2192 $HOME/.agents/skills; hosts/codex.ts globalRoot '.agents/skills/gstack'; Kiro sed handling both roots; migration script removi\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":6,"port":"re-implement","cc":"1.5-2 hours","files":["setup","hosts/codex.ts"],"basis":"cross-reference MISSING"},{"id":"gap3-hosts-codex-native-image-gen","title":"Codex native image_gen: /codex Image Generation section + design-shotgun uses it on the Codex host (#2174)","kind":"feature","refs":["92419927 (seungwonme)","e6f3464a (Jinzhe, #2174)"],"xref":"MISSING","residual":"All three pieces: (a) codex/SKILL.md.tmpl '## Image Generation' section (swap `-s read-only` \u2192 `-s workspace-write`, scratch dir under $TMP_ROOT with `-C` + `--\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":5,"fit":4,"port":"re-implement","cc":"(a) 20 min; (b) 2-3 hours plus a live Co\u2026","files":["codex/SKILL.md.tmpl","test/skill-validation.test.ts"],"basis":"cross-reference MISSING"},{"id":"gap3-codex-jsonl-parser-bin","title":"bin/gstack-codex-jsonl-parser replaces inline python streaming blocks in /codex (#1329 Pattern 4)","kind":"fix","refs":["2c57b98b (Nikhilesh Nanduri, #1329 Pattern 4)","e12ecf34"],"xref":"MISSING","residual":"Whole mechanism: bin/gstack-codex-jsonl-parser (--mode challenge|consult; SESSION_ID from thread.started in consult; reasoning/agent_message/command_execution; \u2026","rec":"TAKE","prio":"P1","val":7,"fit":8,"port":"adapt","cc":"45 min","files":["bin/gstack-codex-jsonl-parser","codex/sections/challenge-mode.md.tmpl"],"basis":"cross-reference MISSING"},{"id":"gap3-codex-probe-custom-provider-env-key","title":"Codex auth probe recognizes custom OpenAI-compatible providers via config.toml env_key","kind":"fix","refs":["403e0009 (hardy)","2b60a383"],"xref":"MISSING","residual":"Entire feature is absent upstream: (1) config.toml fallback in _gstack_codex_auth_probe \u2014 strip full-line comments (grep -v '^[[:space:]]*#'), strip inline comm\u2026","rec":"TAKE","prio":"P1","val":7,"fit":9,"port":"adapt","cc":"~15-20 min","files":["bin/gstack-codex-probe","test/codex-hardening.test.ts"],"basis":"cross-reference MISSING"},{"id":"gap3-codex-hermes-refresh-token-reused-recovery","title":"/codex: Hermes-aware recovery branch for refresh_token_reused (#1542)","kind":"judgment-rule","refs":["1217b92d (0xDevNinja, #1542)"],"xref":"MISSING","residual":"The whole judgment rule is absent: on stderr `refresh_token_reused`, do not go straight to `codex login`; (1) smoke-test Hermes' openai-codex provider first; (2\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":6,"port":"re-implement","cc":"~10 min","files":["codex/SKILL.md.tmpl","codex/SKILL.md"],"basis":"cross-reference MISSING"},{"id":"gap3-codex-gpt56-model-docs-and-max-reasoning","title":"/codex model docs: GPT-5.6 family ladder (sol > terra > luna), bare-id rejection, `max` reasoning level","kind":"doc","refs":["c2d88850 (Garry Tan)"],"xref":"PARTIAL","residual":"Three doc pieces still missing from codex/SKILL.md.tmpl Model & Reasoning: (a) the sentence naming the GPT-5.6 family ladder (sol > terra > luna) and that bare \u2026","rec":"TAKE_PARTIAL","prio":"P2","val":4,"fit":7,"port":"adapt","cc":"~10 min (+ the live probe)","files":["codex/SKILL.md.tmpl","codex/SKILL.md"],"basis":"cross-reference PARTIAL"},{"id":"gap3-codex-global-discover-originator-buckets","title":"/retro global: bucket Codex sessions by payload.originator (#1315)","kind":"feature","refs":["02a6177c (0xDevNinja, refs #1315)","5a5f9439"],"xref":"MISSING","residual":"Everything: CodexOriginator type with six buckets (desktop = 'Codex Desktop'/codex_desktop; cli = codex_cli_rs, codex_vscode; sdk = codex_sdk_ts, codex_sdk_py; \u2026","rec":"TAKE","prio":"P2","val":6,"fit":8,"port":"adapt","cc":"~30 min","files":["bin/gstack-global-discover.ts","test/global-discover.test.ts"],"basis":"cross-reference MISSING"},{"id":"gap3-codex-global-discover-ssh-url-form","title":"normalizeRemoteUrl handles ssh://git@host/user/repo (slash form)","kind":"fix","refs":["028db401 (Asish Kumar)"],"xref":"MISSING","residual":"Entire fix absent: (1) try `new URL(normalized)`; if `protocol === 'ssh:' && username === 'git' && pathname.length > 1` rewrite to `https://${host}${pathname}` \u2026","rec":"TAKE","prio":"P1","val":5,"fit":9,"port":"cherry-pick","cc":"~10 min","files":["bin/gstack-global-discover.ts","test/global-discover.test.ts"],"basis":"cross-reference MISSING"},{"id":"gap3-setup-windows-prefer-symlinks-with-privilege","title":"_link_or_copy prefers real symlinks on Windows when SeCreateSymbolicLinkPrivilege is available, copy fallback \u2026","kind":"fix","refs":["951979e2 (TTmo123)","9c1319f9"],"xref":"PARTIAL","residual":"HEADLINE MECHANISM ENTIRELY ABSENT: (1) symlink-first `_link_or_copy` on Windows \u2014 `ln -sn \"$src\" \"$dst\" && [ -L \"$dst\" ]` accepted, else `rm -rf \"$dst\"` and fa\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":4,"fit":8,"port":"adapt","cc":"~20-30 min + one windows-free-tests / wi\u2026","files":["setup (_link_or_copy, setup:96-115; _print_windows_copy_note_once, setup:168-171)","test/setup-windows-fallback.test.ts"],"basis":"cross-reference PARTIAL"},{"id":"gap3-setup-playwright-best-effort-not-fatal","title":"Playwright Chromium failure becomes a named warning, not exit 1 mid-setup","kind":"fix","refs":["ce9f0f9a (David Miserak)"],"xref":"MISSING","residual":"All of it: `_PW_FAIL_REASON` accumulator with the four named reasons (chromium-install | windows-no-node | windows-node-modules | post-install-launch); routing \u2026","rec":"TAKE","prio":"P1","val":9,"fit":9,"port":"re-implement","cc":"~15-20 min + one free-suite run","files":["setup (step 2 block, setup:764-850; ensure_playwright_browser Windows arm setup:455-457)","test/setup-playwright-warn-not-exit.test.ts (new; port from fork ce9f0f9a with re-anchored assertions)"],"basis":"cross-reference MISSING"},{"id":"gap3-setup-playwright-pin-bundled-version","title":"Pin `playwright install chromium` to the node_modules Playwright version and assert the full Chromium build ex\u2026","kind":"fix","refs":["ad1b567a (Jayesh Betala / @jbetala7, #1829)"],"xref":"MISSING","residual":"Both sub-pieces: (1) read `require('playwright/package.json').version` from node_modules and run `bunx \"playwright@$pw_version\" install chromium` (with unpinned\u2026","rec":"TAKE","prio":"P2","val":6,"fit":8,"port":"adapt","cc":"~15-20 min + one free-suite run","files":["setup (ensure_playwright_browser setup:445-465; install block setup:803-809)","browse/src/xprotect-heal.ts (runBoundedChromiumReinstall, ~:247-256)"],"basis":"cross-reference MISSING"},{"id":"gap3-setup-ubuntu-2604-arm64-platform-override","title":"Ubuntu 26.04 Playwright override maps aarch64/arm64 to ubuntu24.04-arm64","kind":"fix","refs":["2e78d133 (fork maintainer, on 628fa8f0 Padmaraj Nidagundi)"],"xref":"PARTIAL","residual":"The one-liner: replace setup:774 with `case \"$(uname -m)\" in aarch64|arm64) _PLAYWRIGHT_PLATFORM_OVERRIDE=\"ubuntu24.04-arm64\" ;; *) _PLAYWRIGHT_PLATFORM_OVERRID\u2026","rec":"TAKE","prio":"P2","val":5,"fit":10,"port":"adapt","cc":"5-10 min","files":["setup:774 (inside the Ubuntu 26.04 detection block, setup:765-777)","test/setup-playwright-platform-override.test.ts (new static test; closes part of TODOS.md:199-202)"],"basis":"cross-reference PARTIAL"},{"id":"gap3-relink-ownership-guard-on-prefix-flip","title":"gstack-relink only removes entries that resolve into the gstack install (foreign same-name skills survive a pr\u2026","kind":"fix","refs":["5ed18036 (smblight)","4d5f0309"],"xref":"PARTIAL","residual":"(1) readlink ownership gate in `_cleanup_skill_entry` (bin/gstack-relink:46-53) \u2014 delete only when the entry's symlink (or its SKILL.md symlink) resolves into g\u2026","rec":"TAKE","prio":"P1","val":8,"fit":9,"port":"adapt","cc":"~15-20 min + one free-suite run","files":["bin/gstack-relink (_cleanup_skill_entry :46-53; _link_root_skill_alias :55-68; flat-mode target writer ~:100-110)","setup (_install_alias_skill_md :991-1003; prefix-flip alias cleanup around :1690-1696)"],"basis":"cross-reference PARTIAL"},{"id":"gap3-update-check-apply-mode","title":"gstack-update-check --apply: one-shot non-interactive fast-forward upgrade with guards, watchdog and shared se\u2026","kind":"feature","refs":["a48e620c (Cloverings1)","a92e80e8"],"xref":"MISSING","residual":"The entire feature is missing: `--apply` flag (fork bin/gstack-update-check @e6797588: arg loop with exit 2 on unknown arg; UP_TO_DATE cache bust on bare --appl\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":5,"port":"re-implement","cc":"1.5-2 hours","files":["bin/gstack-update-check","bin/gstack-session-update"],"basis":"cross-reference MISSING"},{"id":"gap3-config-inline-comment-stripping","title":"gstack-config read_config_value strips unquoted inline `# comments` before the key prefix","kind":"fix","refs":["3c70d1a6","fac2a958"],"xref":"MISSING","residual":"The one-line sed change (fork fac2a958 final form: `s/[[:space:]]+#.*$//; s/^${key}:[[:space:]]*//; s/[[:space:]]+$//` \u2014 comment strip ordered BEFORE the key-pr\u2026","rec":"TAKE","prio":"P1","val":6,"fit":9,"port":"adapt","cc":"10-15 min","files":["bin/gstack-config (read_config_value sed, ~1 line)","browse/src/config.ts (readGstackConfigYamlKey regex: require whitespace before `#`)"],"basis":"cross-reference MISSING"},{"id":"gap3-migration-v127-owner-qualified-gh-rename-and-heal","title":"v1.27 artifacts-repo rename passes OWNER/REPO to gh (never ran before) + heal migration for already-migrated i\u2026","kind":"fix","refs":["5c5b8c4e (Brandon Pugsley)","56425c9a"],"xref":"MISSING","residual":"Both pieces are missing: (a) v1.27.0.0.sh owner qualification \u2014 `GH_OWNER=$(gh api user --jq .login)`, `gh repo view/rename/edit` on `$GH_OWNER/$OLD_REPO_NAME`,\u2026","rec":"TAKE","prio":"P1","val":8,"fit":8,"port":"adapt","cc":"45-60 min","files":["gstack-upgrade/migrations/v1.27.0.0.sh (GH_OWNER via `gh api user --jq .login`; qualify view/rename/edit; capture stderr into the WARNING; manual hint shows OWNER/REPO)","test/migrations-v1.27.0.0.test.ts (fake gh: `api user` case + reject bare names)"],"basis":"cross-reference MISSING"},{"id":"gap3-makepdf-toc-empty-heading-id-alignment","title":"make-pdf --toc: skip empty-text headings when assigning toc-N ids so TOC entries and anchors stay index-aligne\u2026","kind":"fix","refs":["7bf97231"],"xref":"PARTIAL","residual":"The addHeadingIds hunk only: match the full `<hN ...>body</hN>` (`/<(h[1-3])([^>]*)>([\\s\\S]*?)<\\/\\1>/gi`), `return full` when `decodeTextEntities(stripTags(body\u2026","rec":"TAKE","prio":"P2","val":5,"fit":10,"port":"cherry-pick","cc":"5-10 min","files":["make-pdf/src/render.ts (addHeadingIds: match full `<hN ...>body</hN>`, skip empty-text headings, re-emit with id)","make-pdf/test/render.test.ts (fork test: `<h2></h2>` then `# Real` -> TOC href resolves to the id actually on the Real heading; add image-only heading case)"],"basis":"cross-reference PARTIAL"},{"id":"gap3-design-round-artifact-preservation","title":"design: preserve every generated variant per round (variant-recommended-A/B/C.png + manifest), dedupe the alia\u2026","kind":"feature","refs":["4ec1514b (Matt Van Horn / @mvanhorn)","4225cbc0"],"xref":"MISSING","residual":"Whole feature: generateWithRoundArtifacts/iterateWithRoundArtifacts (primary written to `<base>-<A..Z>.png`, attempt recorded in `.gstack-design-rounds.json`, n\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":7,"fit":4,"port":"re-implement","cc":"1.5-2 hours","files":["design/src/cli.ts (generic no-clobber guard for generate/iterate/evolve --output: auto-suffix unless --overwrite; export main/resolveImagePaths; `import.meta.main` guard; resolveImagePaths tolerates a missing path with a warning when >=1 image resolves)","design/src/generate.ts, design/src/iterate.ts (or a small shared `nextFreeOutputPath()` helper in design/src/)"],"basis":"cross-reference MISSING"},{"id":"gap3-uninstall-sweep-renamed-install-links","title":"gstack-uninstall sweeps per-skill links that point at a renamed install dir (#1882 companion)","kind":"fix","refs":["65f39a51","b8ad3396 (Matt Van Horn)"],"xref":"MISSING","residual":"(1) Add \"$GSTACK_DIR\"/* to the readlink case patterns at bin/gstack-uninstall:207, :220, :252 (fork 65f39a51 mechanism, 3 lines). (2) Companion gap the fork did\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":9,"port":"adapt","cc":"15-20 min for the render-prefix fix + te\u2026","files":["bin/gstack-uninstall (case patterns at :207, :220, :252 \u2192 add `\"$GSTACK_DIR\"/*` and `*/.gstack/render/claude/*`; gate at :194 \u2192 also fire when the inventory is non-empty or $GSTACK_DIR lives under $CLAUDE_SKILLS)","test/uninstall.test.ts (new cases: GSTACK_DIR=<home>/.claude/skills/<other-name> with per-skill dirs whose SKILL.md links target it; per-skill SKILL.md links targeting <home>/.gstack/render/claude/<skill>/SKILL.md)"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-land-skill-merge-queue-1815","title":"/land skill + trunk.io/GitHub merge-queue driver (bin/gstack-merge, lib/merge.ts) \u2014 Garry's own PR #1815, OPEN\u2026","kind":"feature","refs":["origin/backup/pre-isolated-wave-review-2026-07-14 @ 4ab6d83c (Garry Tan)","6a252d23 (t)"],"xref":"MISSING","residual":"Everything is missing: (a) land/SKILL.md.tmpl (standalone merge-only skill with pre-flight, CI wait, VERSION drift, readiness gate, --fast, --watch, enqueue-and\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":7,"fit":7,"port":"adapt","cc":"4-6 hours with gstack (adapt in two comm\u2026","files":["lib/merge.ts (new, from fork 4ab6d83c+6a252d23+bbad1bab)","bin/gstack-merge (new; rewrite submitViaRest to receiptedFetch/writeReceipt, token out of argv)"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-land-gh-checks-targeturl-bugfix","title":"land-and-deploy dry-run still calls `gh pr checks --json name,targetUrl` \u2014 gh rejects targetUrl (fork bbad1bab\u2026","kind":"fix","refs":["bbad1bab (t) \u2014 land-and-deploy/SKILL.md.tmpl hunk @@ -250"],"xref":"MISSING","residual":"Two one-line template edits + `bun run gen:skill-docs`: (1) land-and-deploy/sections/first-run-validation.md.tmpl:112 `name,targetUrl` \u2192 `name,link`, and the pr\u2026","rec":"TAKE","prio":"P1","val":6,"fit":10,"port":"cherry-pick","cc":"5 min","files":["land-and-deploy/SKILL.md.tmpl:154 (Step 2: --json name,state,bucket; parse prose items 1-3 to read bucket pass/fail/pending)","land-and-deploy/sections/first-run-validation.md.tmpl:112-114 (--json name,link; 'extract the URL from the link field')"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-diagnose-skill-935","title":"/diagnose \u2014 read-only evidence-gated root-cause report skill (#935)","kind":"feature","refs":["e08b6100 (Milan / milstan)","bbad1bab (t) diagnose hunks"],"xref":"MISSING","residual":"Everything: diagnose/SKILL.md.tmpl (1,233 lines: 5 Deadly Sins, Iron Law 'no conclusions without evidence', Phase 0 environment scan with wrong-DB guard and env\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":5,"fit":6,"port":"methodology-only","cc":"1-2 hours with gstack","files":["investigate/SKILL.md.tmpl (Phase 1: mandatory end-to-end workflow map for cross-system bugs + environment/target-DB verification before queries; Phase 3: multiple-hypothesis rule with evidence AGAINST each, easiest-to-disprove-first ordering, confidence-scored PROBABLE_CAUSE vs ROOT_CAUSE_ESTABLISHED verdict that refuses ROOT_CAUSE without a reproduction; Arguments: a --report-only / --diagnose flag that stops before Phase 4 Implementation)","investigate/SKILL.md (regenerated)"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-plan-status-skill-1438","title":"/plan-status skill + ship open-checkbox warning (#1438) with fork correctness fixes","kind":"feature","refs":["cad6bd2f (Willard / Willardgmoore)","bbad1bab (t) plan-status + ship hunks"],"xref":"PARTIAL","residual":"Missing from upstream: (1) an on-demand read-only 'where are we on the plan?' entry point outside /ship and /review (no skill, no trigger phrases, no router row\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":4,"fit":6,"port":"re-implement","cc":"1 hour with gstack","files":["plan-status/SKILL.md.tmpl (new, thin tier-1: {{PLAN_COMPLETION_AUDIT_REVIEW}} in report-only mode, no code changes)","scripts/resolvers/review.ts generatePlanFileDiscovery (:860-885: honor `gstack-config get plan_glob` with ${_PLAN_GLOB/#\\~/$HOME} expansion ahead of the four hard-coded dirs)"],"basis":"cross-reference PARTIAL"},{"id":"gap2-skillwave-plan-pm-review-1666","title":"/plan-pm-review (RICE/JTBD/acceptance criteria) + autoplan Phase 1.5 PM review (#1666)","kind":"feature","refs":["fe1e4576 (Nikhilesh Nanduri)","bbad1bab (t) autoplan + tasks-section hunks"],"xref":"PARTIAL","residual":"Skeptic found missing pieces: /plan-pm-review skill itself (fork fe1e4576:plan-pm-review/SKILL.md.tmpl, 377 lines, tier-3, three modes PRIORITIZE/SHARPEN/SEGMEN\u2026","rec":null,"prio":null,"val":null,"fit":null,"port":null,"cc":"","files":[],"basis":"xref-absorbed, flipped by skeptic"},{"id":"gap2-skillwave-pr-prep-duplicate-audit-1696","title":"/pr-prep upstream-duplicate audit + bin/gstack-pr-prep-score + ship Step 1.5 gate (#1696)","kind":"feature","refs":["47f6a566 (Benjamin D. Smith)","d6466f9b (t)"],"xref":"MISSING","residual":"Everything: per-commit keyword derivation, open/closed issue + open/merged PR queries, Jaccard title/file scoring with state weights, EXACT_DUP/OVERLAP/SIBLING/\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":6,"port":"adapt","cc":"1.5-2 h","files":["bin/gstack-pr-prep-score (from PR #1696 head 7d3c026c, keep RELATED_OPEN_ISSUE_FLOOR; author BenjaminDSmithy preserved)","test/pr-prep-score.test.ts"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-fanout-skill-1949","title":"/fanout \u2014 decompose a design doc into N parallel worktree agent tasks (#1949, CLOSED unmerged)","kind":"feature","refs":["5e1c1207 (sohmn)","upstream PR #1949 CLOSED 2026-07-21 (sohmn)"],"xref":"PARTIAL","residual":"The artifact-producing half: appending a '## Parallel Execution Plan' section (Slab 0 + slab matrix with Writes/Reads/Public interface/Verification gate/ETA + c\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":7,"fit":6,"port":"re-implement","cc":"2-3 h","files":["plan-eng-review/sections/review-sections.md.tmpl (:115-141 Worktree parallelization strategy \u2192 add opt-in 'Write dispatch artifacts?' AUQ after the lane table)","plan-eng-review/sections/dispatch-artifacts.md.tmpl (NEW: Slab 0 promotion semantics, contract-ownership-survives-promotion, per-lane *.prompt.md files, worktree-dispatch.sh with sha8 names, --max cap with single merge-sequence question, parallelism-confidence abort, CHANGELOG/VERSION expected-conflict note pointing at gstack-next-version)"],"basis":"cross-reference PARTIAL"},{"id":"gap2-skillwave-community-review-skill-404","title":"/community-review \u2014 prioritized PR inbox for maintainers (#404)","kind":"feature","refs":["3dd32f6f (John Banner / johnbanr)","f49cd565 (t)"],"xref":"MISSING","residual":"Everything: fetch all open PRs, Impact(1-10) \u00d7 (11 \u2212 Effort) priority, staleness penalty, 6-item template-compliance check, code-quality red-flag scan, five-buc\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":4,"port":"re-implement","cc":"1.5 h","files":["bin/gstack-pr-triage (NEW: fetch open PRs, deterministic mechanical scoring \u2014 size, age/staleness, mergeable, CI status, template compliance, touched generated files \u2014 JSON + markdown digest; all body/diff text via lib/tracker-guard.ts envelopes)","test/gstack-pr-triage.test.ts (NEW, free, pure scorer tests)"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-setup-search-mcp-exa-2168","title":"/setup-search-mcp \u2014 free no-auth web-search MCP for Search Before Building (#2168, switched to Exa by fork)","kind":"feature","refs":["364d8045 (George Pickett / grp06)","737de4e8 (t)"],"xref":"MISSING","residual":"Everything: a tier-1 skill that detects the current host, runs `claude mcp add --scope user --transport http Exa-Search-MCP https://mcp.exa.ai/mcp` or `codex mc\u2026","rec":"SKIP","prio":"P3","val":2,"fit":2,"port":"n/a","cc":"15-30 min","files":["(if anything) docs/ or README.md host table footnote: 'hosts without native web search: register any Streamable-HTTP search MCP; Search Before Building degrades gracefully without one' \u2014 provider-neutral, no vendor endpoint","(optional micro-fix, verify first) scripts/skill-check.ts: honor getHostConfig('claude').generation.skipSkills when reporting missing generated outputs (hosts/claude.ts:24 skips /claude; grep skipSkills scripts/skill-check.ts \u2192 0 hits \u2014 whether it currently misreports is unverified)"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-plugin-marketplace-526","title":"Claude Code plugin marketplace manifests + skills/ symlink tree + drift tripwire (#526)","kind":"tooling","refs":["b5d6ab0d (Randy Olson / rhiever)","3ec0bbd9 (t)"],"xref":"MISSING","residual":"Everything: .claude-plugin/plugin.json + marketplace.json, skills/ symlink tree (53 links against upstream's 54 skill dirs minus connect-chrome alias), test/plu\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":5,"port":"adapt","cc":"30 min for manifests+tree+tripwire+READM\u2026","files":[".claude-plugin/plugin.json",".claude-plugin/marketplace.json"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-learnings-refine-2029","title":"gstack-learnings-refine \u2014 semantic near-duplicate dedup for the learnings store + /learn refine (#2029)","kind":"feature","refs":["15a3d5b7 (Tony Zhou / tonyjzhou)","34c9c31f (t)"],"xref":"MISSING","residual":"Everything: bin/gstack-learnings-refine (TF-IDF + char-trigram blend, --sim/--review/--review-floor/--cross-type/--min-entries/--json, dry-run default, atomic -\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":6,"port":"adapt","cc":"1.5 h (port bin, convert paths, add lock\u2026","files":["bin/gstack-learnings-refine (new, standalone bun script \u2014 no lib import so #2720 pattern is not a blocker)","learn/SKILL.md.tmpl:41-46 (command list) + new 'Refine (dedup)' section after Prune (tmpl:76-102)"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-learnings-normalize-legacy-stats-940","title":"Normalize legacy category/summary/detail learnings rows in search + bin/gstack-learnings-stats (#940)","kind":"fix","refs":["116fefc2 (X / laozhong86)","ceac07fa (t)"],"xref":"MISSING","residual":"Everything: normalizer (category->type token mapping incl. 'investigation', summary->slugified key, detail/summary->insight, confidence default 5, skill default\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":3,"fit":5,"port":"re-implement","cc":"20 min (stats bin + test + tmpl swap + r\u2026","files":["bin/gstack-learnings-stats (new; GSTACK_STATE_ROOT via gstack-paths, bun -e with GSTACK_LIB_DIR pattern)","learn/SKILL.md.tmpl:136-178 (replace inline bun -e stats with the bin call)"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-learnings-signal-gating-feedback-code-2030","title":"Signal-gated learnings capture + helpful/harmful feedback log + reinforced ranking \u2014 the CODE half of #2030 (p\u2026","kind":"feature","refs":["1b9e216d, 805b839e, f282cb06, 5ad506bb (Tony Zhou)","6b4d1fe7 (t)"],"xref":"MISSING","residual":"Everything: --signal (tests-passed|app-ran-clean|validator|benchmark|exec-success|none) routing in gstack-learnings-log with candidates file + confidence clamp \u2026","rec":"TAKE_PARTIAL","prio":"P2","val":7,"fit":6,"port":"adapt","cc":"2 h (port bins with env-import pattern, \u2026","files":["bin/gstack-learnings-log (--signal parsing, route to learnings-candidates.jsonl with confidence clamp 4, user-stated always trusted)","bin/gstack-learnings-feedback (new; GSTACK_LIB_DIR import, injection check on --note)"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-office-hours-developer-profile-glob-1790","title":"office-hours gbrain builder-profile query points at a file that no longer exists (#1790)","kind":"fix","refs":["ad68c6bc (Nikhilesh Nanduri)","upstream PR #1790 OPEN (NikhileshNanduri)"],"xref":"MISSING","residual":"The 2-line frontmatter change (glob -> ~/.gstack/developer-profile.json, drop `tail: 1`) + `bun run gen:skill-docs`. Optional follow-ons upstream lacks: retarge\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":3,"fit":8,"port":"cherry-pick","cc":"10 min for cherry-pick + regen; ~45 min \u2026","files":["office-hours/SKILL.md.tmpl:42-46 (glob -> ~/.gstack/developer-profile.json, drop tail: 1) \u2014 cherry-pick ad68c6bc, author Nikhilesh Nanduri preserved","office-hours/SKILL.md (regen)"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-office-hours-artifact-outcome-1049","title":"office-hours verifies a design doc was written before logging outcome:success (#1049) + fork $PPID session-mar\u2026","kind":"fix","refs":["bfeb922d (Chris Walton / walton-chris)","bbad1bab (t) office-hours hunk"],"xref":"MISSING","residual":"Everything: (1) the Pre-Telemetry bash block (find ~/.gstack/projects/$SLUG -name '*-design-*.md' -newer <this session's marker> -> ARTIFACT_STATUS ok|no_doc); \u2026","rec":"TAKE","prio":"P1","val":6,"fit":7,"port":"adapt","cc":"20 min","files":["/home/vercel-sandbox/gstack/office-hours/SKILL.md.tmpl","/home/vercel-sandbox/gstack/office-hours/sections/design-and-handoff.md.tmpl"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-office-hours-codebase-surface-premise-verify-1738","title":"office-hours Codebase Surface Map + verify codebase-fact premises against code before AskUserQuestion (#1738)","kind":"judgment-rule","refs":["3df206e7 (Matt Van Horn / mvanhorn)","upstream PR #1738 CLOSED 2026-07-15 unmerged (mvanhorn)"],"xref":"MISSING","residual":"All five sub-pieces: (1) Phase 1 conditional Codebase Surface Map (schema/visibility-auth/server-action triggers, cite migrations, RLS policies, handlers; expli\u2026","rec":"TAKE_PARTIAL","prio":"P1","val":8,"fit":8,"port":"adapt","cc":"30 min","files":["/home/vercel-sandbox/gstack/office-hours/SKILL.md.tmpl","/home/vercel-sandbox/gstack/office-hours/sections/design-and-handoff.md.tmpl"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-design-review-cognitive-load-s1s2-696","title":"design-review Phase 6.5 Cognitive Load (System 1 / System 2) audit with ASCII slider (#696)","kind":"judgment-rule","refs":["1e04c2c5 (MaruPelkar)","upstream PR #696 OPEN (MaruPelkar)"],"xref":"MISSING","residual":"The entire 20-line Phase 6.5 block: per-screen System 1 <-> System 2 rating (0-10) grounded in already-collected browse data (element counts from snapshot -i, l\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":5,"fit":5,"port":"re-implement","cc":"30 min","files":["/home/vercel-sandbox/gstack/scripts/resolvers/design.ts","/home/vercel-sandbox/gstack/design-review/SKILL.md.tmpl"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-plan-eng-platform-capability-check-1812","title":"plan-eng-review Step 0 platform-capability check before building new infra (#1812, issue #1685 OPEN)","kind":"judgment-rule","refs":["be6d2714 (Nikhilesh Nanduri)","upstream PR #1812 OPEN; issue #1685 OPEN"],"xref":"MISSING","residual":"The whole check: trigger (plan adds daemon/queue/worker/scheduled job/webhook receiver/integration glue to move data into or out of an existing platform), disco\u2026","rec":"TAKE","prio":"P2","val":6,"fit":8,"port":"cherry-pick","cc":"20 min (prose) + 30 min if adding the sc\u2026","files":["/home/vercel-sandbox/gstack/plan-eng-review/SKILL.md.tmpl","/home/vercel-sandbox/gstack/test/skill-validation.test.ts"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-model-design-bias-tests-1071","title":"#1071 data-model bias guardrails \u2014 the TEST half (static skill-validation pins + e2e-plan case); prose covered\u2026","kind":"test-infra","refs":["14eebd8b (David Grant / dgrant)","b680c317 (t)"],"xref":"MISSING","residual":"All test artifacts: (1) static 'data-model bias guardrails' describe (10 tests) pinning the two preference bullets in plan-eng-review and plan-ceo-review, the t\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":6,"port":"adapt","cc":"30-45 min (incl. one periodic E2E run)","files":["/home/vercel-sandbox/gstack/test/skill-validation.test.ts","/home/vercel-sandbox/gstack/test/skill-e2e-plan.test.ts"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-retro-code-health-trends-790","title":"/retro reads health-history.jsonl and reports a Code Health row with trend/regression detail (#790, CLOSED unm\u2026","kind":"feature","refs":["7d690289 (Kaustav Mishra / km-git007)","upstream PR #790 CLOSED 2026-08-01 (km-git007)"],"xref":"MISSING","residual":"Everything: (1) fetch health-history.jsonl in Step 1 (best as a `HEALTH_HISTORY: present` presence line in bin/gstack-retro-metrics mirroring SKILL_USAGE_LOG/EU\u2026","rec":"TAKE","prio":"P2","val":6,"fit":7,"port":"adapt","cc":"30 min","files":["bin/gstack-retro-metrics","retro/SKILL.md.tmpl"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-retro-persist-recommendations-followthrough-1834","title":"/retro persists '3 Things to Improve' as a recommendations array and scores follow-through next run (issue #18\u2026","kind":"feature","refs":["f6ea1310, 6462dbdf (Jayesh Betala / jbetala7)","upstream issue #1834 OPEN (no PR number resolves)"],"xref":"MISSING","residual":"Entire feature: mandatory `recommendations: [{category, text}]` in the Step 13 snapshot populated from the three improvement items; Step 12 read-back that class\u2026","rec":"TAKE","prio":"P1","val":8,"fit":8,"port":"adapt","cc":"30 min","files":["retro/SKILL.md.tmpl","retro/sections/report-format.md.tmpl"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-retro-language-agnostic-test-detection-2037-2013","title":"/retro language-agnostic test-file detection (Python/Terraform/Bats/tests-dir), added-vs-touched split, vendor\u2026","kind":"fix","refs":["da7f76ba (Sholto McNeilage / SholtoMc)","9f926b75 (t, #2013 port)"],"xref":"PARTIAL","residual":"(a) Polyglot pattern in both :170 (TEST_FILES_CHANGED) and :303 (TEST_FILES_TOTAL): `(^|/)test_` prefix, `.tftest.hcl$`, `.bats$`, plus the Java `*Test.java` / \u2026","rec":"TAKE","prio":"P1","val":8,"fit":8,"port":"re-implement","cc":"45 min","files":["bin/gstack-retro-metrics","retro/sections/report-format.md.tmpl"],"basis":"cross-reference PARTIAL"},{"id":"gap2-skillwave-review-ci-blindspot-e2e-645","title":"#645 review PR-type triage \u2014 the E2E blindspot test + CI fixtures half (prose covered by s9); note upstream cl\u2026","kind":"test-infra","refs":["9ad9eabc (Greg Jackson / gregario)","upstream PR #645 CLOSED 2026-08-01 (gregario)"],"xref":"MISSING","residual":"Nothing from 9ad9eabc is in upstream: the Step 3.6 PR-type classification prose, the three new checklist categories (Script & Shell Quality, Platform & Conventi\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":5,"port":"re-implement","cc":"1.5 hours","files":["review/checklist.md","bin/gstack-diff-scope"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-review-defensive-framing-shared-resolver-1921","title":"Extend #1899 defensive-security framing to the red-team and security-specialist dispatches via a shared resolv\u2026","kind":"fix","refs":["80ba8f17 (Brian Majewski / bmajewski)","bbad1bab (t) scripts/resolvers/review.ts hunk"],"xref":"MISSING","residual":"The whole change: shared scripts/resolvers/defensive-framing.ts (DEFENSIVE_REVIEW_FRAMING + FIXTURE_SUMMARY_MODE); review-army.ts prepending the framing to the \u2026","rec":"TAKE","prio":"P1","val":8,"fit":9,"port":"cherry-pick","cc":"20 min","files":["scripts/resolvers/defensive-framing.ts","scripts/resolvers/review-army.ts"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-review-claude-md-review-section-example-452","title":"#452 examples/CLAUDE.md.review.example \u2014 the example file half (prose covered by s9)","kind":"doc","refs":["61cc1aea (Eric Van Boxsom / evb87-tech)","upstream PR #452 OPEN (evb87-tech)"],"xref":"MISSING","residual":"Everything: (1) the 15-line example file (`## Review` section with source-of-truth-for-intent, high-risk paths, never-AUTO-FIX areas, external consumers, known \u2026","rec":"TAKE","prio":"P2","val":6,"fit":8,"port":"adapt","cc":"10-15 min","files":["review/SKILL.md.tmpl","review/SKILL.md (regenerated)"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-health-structure-scan-dimension-1976","title":"/health structure-scan dimension (oversized files/classes/functions, repeated mutation boilerplate, mixed resp\u2026","kind":"feature","refs":["203de36d (jeonghan.yun / dalsoop)","upstream PR #1976 OPEN (dalsoop)"],"xref":"MISSING","residual":"Entire feature: Structure category (10% weight; 0 warnings=10, 1=7, <5=4, >=5=0) with rebalanced weights (20/16/26/11/7/10/10); concrete thresholds (>350-line a\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":5,"fit":5,"port":"re-implement","cc":"Dart/Flutter detection: 10 min. Structur\u2026","files":["health/SKILL.md.tmpl (auto-detect block :51-83: add pubspec.yaml -> flutter analyze / dart analyze, dart format --set-exit-if-changed, flutter test / dart test; fix stale weights at :300-304)","health/SKILL.md (regenerated)"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-scrape-evidence-gate-1717","title":"/scrape evidence gate: verify the prototype JSON against the intent (checkpoints + captures) before emitting; \u2026","kind":"judgment-rule","refs":["9d0d5972 (orendi84)","upstream PR #1717 OPEN (orendi84)"],"xref":"MISSING","residual":"All of it: (1) new Step 5 'Verify the prototype result against the intent' \u2014 decompose intent into checkpoints (each datum/field/filter/count/ranking), back eac\u2026","rec":"TAKE","prio":"P1","val":8,"fit":9,"port":"adapt","cc":"30 min + one periodic E2E run (~$1)","files":["scrape/SKILL.md.tmpl (Step 3 match-path sanity check :85; Step 4 'do not emit yet' :113-115; new Step 5 evidence gate; renumber Skillify nudge to Step 6 :117; Output discipline pointer :157-158)","scrape/SKILL.md (regenerated)"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-land-and-deploy-configurable-merge-method-726","title":"Configurable merge method for /land-and-deploy: CLAUDE.md Deploy Configuration > repo settings > squash defaul\u2026","kind":"feature","refs":["a0d79a0f (Peter Armstrong / peterarmstrong)","upstream PR #726 OPEN (peterarmstrong)"],"xref":"MISSING","residual":"Whole feature: Step 4.0 three-tier resolution (CLAUDE.md `- Merge method:` unless missing/placeholder/invalid -> `gh repo view --json squashMergeAllowed,mergeCo\u2026","rec":"TAKE","prio":"P1","val":7,"fit":8,"port":"adapt","cc":"20-30 min","files":["land-and-deploy/sections/merge-and-deploy.md.tmpl (new 4.0 resolution step; :9 and :30 `--squash` -> `--<method>`; success message names the method)","land-and-deploy/sections/first-run-validation.md.tmpl (:77,81 dry-run box 'MERGE METHOD: <method> (source: CLAUDE.md/repo/default)')"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-hooks-envelope-and-state-dir-chain-1509","title":"freeze/careful hooks: hookSpecificOutput envelope ABSORBED, but the state-dir resolution chain half of #1509/#\u2026","kind":"fix","refs":["0b04809c (Nikhilesh Nanduri)","bbad1bab (t) freeze/bin/check-freeze.sh hunk"],"xref":"PARTIAL","residual":"(1) check-freeze.sh STATE_DIR resolution through gstack-paths \u2014 fork bbad1bab's ~12-line block: probe `$(dirname \"$0\")/../../bin/gstack-paths`, then `${CLAUDE_S\u2026","rec":"TAKE","prio":"P0","val":8,"fit":10,"port":"adapt","cc":"15 min","files":["freeze/bin/check-freeze.sh (:34-36 STATE_DIR resolution via $_HOOK_DIR/../../bin/gstack-paths with GSTACK_HOME-first fallback chain)","test/hook-scripts.test.ts (pin GSTACK_HOME+CLAUDE_PLUGIN_DATA in all freeze-hook tests :690-893; add GSTACK_HOME-only deny regression test)"],"basis":"cross-reference PARTIAL"},{"id":"gap2-skillwave-ios-qa-ios17-tap-and-documents-boot-token-1764","title":"ios-qa #1764: SwiftUI Button tap on iOS 16/17 via accessibilityActivate ABSORBED; Documents/ boot-token locati\u2026","kind":"fix","refs":["5cc74a90 (dwidoo)","b5f81bfe (t)"],"xref":"PARTIAL","residual":"(1) Durable token location: StateServer still writes tmp/ and the daemon still reads tmp/; the fork's Documents/ default (StateServer.swift.template hunk of 5cc\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":7,"port":"adapt","cc":"~45-60 min of CC+gstack, plus one real-d\u2026","files":["ios-qa/templates/StateServer.swift.template","ios-qa/daemon/src/tunnel-bootstrap.ts"],"basis":"cross-reference PARTIAL"},{"id":"gap2-skillwave-askuserquestion-json-shape-2045","title":"AskUserQuestion 'Tool-call shape (JSON) \u2014 schema-critical' section: questions must be a true array of objects \u2026","kind":"judgment-rule","refs":["a8e875ab, a78f35f1 (mruderman)","upstream PR #2045 OPEN (mruderman)"],"xref":"MISSING","residual":"Entire rule: (a) the 'Tool-call shape (JSON) \u2014 schema-critical' section (questions must be a true array of 1-4 objects, never a string/stringified array; each o\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":6,"port":"re-implement","cc":"20-30 min (rule + hook guard + two tests\u2026","files":["scripts/resolvers/preamble/generate-ask-user-format.ts","test/resolver-ask-user-format.test.ts"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-cso-fix-mode-safe-autofixes-1053","title":"/cso --fix: Phase 15 auto-fix engine with a catalog of provably safe fixes (#1053) + fork safety corrections","kind":"feature","refs":["5dcd569a (andreycpu)","cc133982 (t)"],"xref":"MISSING","residual":"Entire feature: `--fix` flag + Mode Resolution rule ('combinable with any scope flag and with --comprehensive/--diff; run Phase 15 after Phase 14'), Edit in all\u2026","rec":"DEFER","prio":"P3","val":5,"fit":3,"port":"methodology-only","cc":"~2 hours for a safe redesign; 15 min for\u2026","files":["TODOS.md"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-cso-mini-shai-hulud-tier3-1523","title":"/cso comprehensive-mode Tier 3 known-campaign IOC rules (mini-shai-hulud: hook /proc/*/mem reads, obfuscated .\u2026","kind":"security","refs":["225a23af (LYH / slash9494)","8a45ad25 (t)"],"xref":"MISSING","residual":"All of Tier 3: R1 (`/proc/.*/mem` in any Claude Code settings `hooks.*.command`), R2 (file under .claude/** or .vscode/** referenced from a hooks command or a t\u2026","rec":"TAKE","prio":"P1","val":8,"fit":8,"port":"adapt","cc":"~30 min of CC+gstack plus one paid perio\u2026","files":["cso/sections/audit-phases.md.tmpl","cso/sections/audit-phases.md"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-security-dashboard-genuine-zero-test-2026","title":"Salvaged test: a GENUINE zero from a healthy backend still renders '0 / Good news' \u2014 no over-degrade (#2026)","kind":"test-infra","refs":["9b2a8787 (Jayesh Betala / jbetala7)","upstream PR #2026 OPEN (jbetala7)"],"xref":"MISSING","residual":"The single test `a GENUINE zero still reads as \"0 / Good news\" \u2014 no over-degrade (#2026)`: run SEC_BIN in mode ok with GOOD_BODY_MARKER's security block zeroed \u2026","rec":"TAKE","prio":"P3","val":2,"fit":10,"port":"cherry-pick","cc":"5 min (cherry-pick + bun run test)","files":["test/security-dashboard-fallback.test.ts"],"basis":"cross-reference MISSING"},{"id":"gap2-skillwave-autoplan-codex-outside-voice-resolver-1282","title":"autoplan outside-voice routing for Codex hosts via a scripts/resolvers/autoplan.ts resolver (#1282) \u2014 hosts-ad\u2026","kind":"fix","refs":["d46a20db (spenquatch / Spenquatch)","upstream PR #1282 OPEN (Spenquatch)"],"xref":"PARTIAL","residual":"Everything except the codex_reviews master switch: (1) host-aware resolver pair {{AUTOPLAN_OUTSIDE_VOICE_PREFLIGHT}} / {{AUTOPLAN_OUTSIDE_VOICE_BLOCK:ceo|design\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":6,"fit":7,"port":"re-implement","cc":"~1.5-2 hours (~15x)","files":["scripts/resolvers/autoplan.ts (new: {{AUTOPLAN_OUTSIDE_VOICE_PREFLIGHT}} + {{AUTOPLAN_OUTSIDE_VOICE_BLOCK:ceo|design|eng|dx}}, host-branched on ctx.host==='codex')","scripts/resolvers/index.ts"],"basis":"cross-reference PARTIAL"},{"id":"gap2-skillwave-triage-ledger-and-drop-reasons","title":"The fork's consolidation ledger + reusable 'Dropped' reasons and the fork author's later upstream close recomm\u2026","kind":"methodology","refs":["afe5af43 (Sinabina), d0ff6eda (t) \u2014 the ledger","fork author comments on upstream PRs dated 2026-07-15 (#935, #404, #1949, #2168, #1438, #1666, #884, #726, #1738, #2013, #645, #790, #1815)"],"xref":"MISSING","residual":"(1) No in-repo per-PR applied/dropped/held ledger with one-line reasons (fork: docs/pr-triage/2026-07-13-community-pr-consolidation.md, 116 PRs, 5 waves); upstr\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":3,"fit":6,"port":"methodology-only","cc":"~30-45 min (re-verification via gh is me\u2026","files":["CONTRIBUTING.md (wave process step 5: require a per-PR Dropped-with-reason table in the ship PR body; note 'every triaged PR accounted for exactly once')","(no repo files for the close pass \u2014 gh pr close with maintainer-voiced comments on #592 #610 #876 #2126 #2183 #775 #491 #1711 #2114 #1172 #2164 #557 #2173 #477 #1755 #2197 and a decision on #935 #404 #1438 #1666 #884 #726 #1815)"],"basis":"cross-reference MISSING"},{"id":"gap5-hygiene-645-review-change-type-triage","title":"/review change-type triage (APPLICATION/CI_INFRA/SCRIPTS/CONFIG/DOCS/TESTS/MIXED) before running the checklist\u2026","kind":"judgment-rule","refs":["origin/main:skills/review/references/legacy/review.md:746-754","docs/gstack-2/JUDGMENT-PROVENANCE.json upstream_bug_fixes pr=645"],"xref":"MISSING","residual":"All of it. Neither the fork's one-paragraph judgment (classify APPLICATION/CI_INFRA/SCRIPTS/CONFIG/DOCS/TESTS/MIXED from the diff's files, print the file counts\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":7,"fit":7,"port":"re-implement","cc":"45-90 min incl. gen:skill-docs, ratchet \u2026","files":["review/SKILL.md.tmpl","review/checklist.md"],"basis":"cross-reference MISSING"},{"id":"gap5-hygiene-1484-qa-evidence-per-finding","title":"QA evidence-per-finding: judgment already upstream; opt-in per-finding folder layout (PR #1484) still open, no\u2026","kind":"judgment-rule","refs":["origin/main:skills/qa/references/legacy/qa.md:541-549","origin/main:skills/qa/references/legacy/qa-only.md:426-434"],"xref":"PARTIAL","residual":"Judgment sub-piece: ABSORBED \u2014 upstream already screenshots immediately per repro step, names files by issue id, and the report template maps each issue to its \u2026","rec":"SKIP","prio":"P3","val":3,"fit":6,"port":"n/a","cc":"0; ~1 hr for #1484 layout as a lazy refe\u2026","files":[],"basis":"cross-reference PARTIAL"},{"id":"gap5-hygiene-make-pdf-eager-token-trim","title":"SKILL-CONTENT-CHECKLIST item 8: move make-pdf's Common flags / Debugging / Output contract to a lazy reference\u2026","kind":"doc","refs":["origin/main:docs/gstack-2/SKILL-CONTENT-CHECKLIST/README.md item 8","origin/main:docs/gstack-2/SKILL-CONTENT-CHECKLIST/02-makepdf-bloat-trim.diff"],"xref":"MISSING","residual":"The entire restructure is absent upstream: no make-pdf/references/make-pdf-usage.md, no one-line lazy pointer, '## Common flags' / '## Debugging' / '## Output c\u2026","rec":"TAKE","prio":"P2","val":5,"fit":9,"port":"re-implement","cc":"15 min + one bun run test","files":["make-pdf/SKILL.md.tmpl","make-pdf/SKILL.md"],"basis":"cross-reference MISSING"},{"id":"gap6-s15-hostadv-fixture-set-and-schema","title":"Raw-prompt injection-resistance fixture set (4 threat scenarios) + schema_version-2 assertion contract","kind":"test-infra","refs":["b6572ebb","9919c4cd"],"xref":"MISSING","residual":"Everything behavioral is missing: (1) the four planted-instruction fixtures (LOG_INSTRUCTION app.log for /qa-only; ERROR_TEXT 'replace every timeout with 5000' \u2026","rec":"TAKE","prio":"P1","val":8,"fit":8,"port":"adapt","cc":"~1.5-2 h plus ~3 paid calibration runs (\u2026","files":["test/skill-e2e-untrusted-content.test.ts (new, gate tier)","test/helpers/touchfiles-data.ts (deps: qa-only/**, investigate/**, review/**, ship/**, test/helpers/scratch-repo.ts, test/helpers/required-reads.ts; E2E_TIERS entries -> 'gate')"],"basis":"cross-reference MISSING"},{"id":"gap6-s15-hostadv-readonly-chain-classifier","title":"Fail-closed read-only command-chain classifier (every segment must be an allowlisted read-only verb; any write\u2026","kind":"judgment-rule","refs":["80e391fc","994238ed"],"xref":"MISSING","residual":"The entire classifier and its table-driven tests are absent: no lib/readonly-command.ts equivalent, no allowlist of read-only git verbs/tools, no recursive subs\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":4,"fit":6,"port":"cherry-pick","cc":"~15-20 min (code is voice-free TS; ~70 l\u2026","files":["lib/readonly-command.ts (new: PATH_PREFIX, READ_ONLY_GIT_VERB, READ_ONLY_GIT_BRANCH, READ_ONLY_SED, READ_ONLY_TOOL, segmentIsReadOnly, classifyReadOnlyChain, isPureReadOnlyCommand w/ sh -lc wrapper strip)","test/readonly-command.test.ts (new, free tier: port fork cases from 70739826:test/gstack2-host-adversarial.test.ts:138-216 and :402-433)"],"basis":"cross-reference MISSING"},{"id":"gap6-s15-hostadv-codex-dollar-skill-activation","title":"Per-host activation-token finding: Codex activates installed skills on `$skill`, not `/skill`; Claude/Cursor/P\u2026","kind":"methodology","refs":["b6572ebb","9919c4cd"],"xref":"PARTIAL","residual":"(1) No user-facing documentation anywhere upstream that Codex activates an installed gstack skill on `$gstack-<skill>` (README Codex section, docs/skills.md, ho\u2026","rec":"TAKE_PARTIAL","prio":"P2","val":5,"fit":7,"port":"re-implement","cc":"~20 min + 1-2 paid codex runs","files":["test/codex-e2e.test.ts (new periodic test `codex-dollar-skill-activation`: prompt `$gstack-review <task>` against CODEX_REVIEW_E2E_SECTIONS fixture; assert skill-loaded behavioral marker + stderr clean)","test/helpers/touchfiles-data.ts (deps: codex/**, review/**, test/helpers/codex-session-runner.ts, test/codex-e2e.test.ts; tier periodic)"],"basis":"cross-reference PARTIAL"},{"id":"gap6-s15-hostadv-immutable-evidence-policy","title":"Immutable one-shot evidence policy for safety runs (exclusive-create, never overwrite, failed stays failed, ne\u2026","kind":"methodology","refs":["b6572ebb","9919c4cd"],"xref":"PARTIAL","residual":"Missing upstream: (a) exclusive-create + never-overwrite for eval result files (fork writeEvidenceExclusive 'wx' + updateEvidence tmp-with-'wx'+rename); (b) a `\u2026","rec":"TAKE_PARTIAL","prio":"P3","val":4,"fit":5,"port":"adapt","cc":"~45 min","files":["test/helpers/eval-store.ts:945 (exclusive-create finalize with collision fallback to suffixed name; optional `claim` field defaulting to 'INCOMPLETE' in _partial and set at finalize)","test/helpers/eval-store.ts EvalTestEntry / recordE2E extra (optional prompt_sha256, fixture_tree_sha256, transcript_sha256 fields)"],"basis":"cross-reference PARTIAL"}] |