Skip to content

feat(pstack): guard the T3 port with a drift check and an intent table - #4

Merged
leegmoore merged 4 commits into
limfrom
sync/a-guardrails
Oct 17, 2026
Merged

leegmoore merged 4 commits into
limfrom
sync/a-guardrails

Conversation

@leegmoore

@leegmoore leegmoore commented Oct 17, 2026 •

Copy link
Copy Markdown

Why

Upstream pstack is 8 versions ahead, and 50 files changed on both sides. Before porting anything, the fork needs a written statement of what it changes for T3 and why, plus a check that catches upstream's Cursor wording when it slips back in.

What changed

  • scripts/check-t3-port.mjs fails on Cursor terms (Task, -fast model names, ~/.cursor/rules, hidden skills, origin/main, Claude fastMode=true) and on missing T3 anchors. Each failure names the fix.
  • FORK.md gets a "T3 port intent" table and sync steps. FORK-SYNC-LOG.md lists all 29 upstream commits with a planned decision each.
  • poteto-mode gets a Speed rule. Claude fast mode needs the operator's approval in the session, for one named task only. setup-pstack never writes it.

Scope

  • The first of four sync PRs. No upstream commits are ported here.
  • A PENDING list in the check holds the drift that PRs B and C remove. An entry that no longer matches anything fails the check.

Blast Radius

The skill text changes are the Speed rule, one setup-pstack paragraph, and one default in multi-phase-plan. Every other change is a maintenance file outside pstack/skills, which the install doesn't copy.

Verification

  • node scripts/check-t3-port.mjs is clean on this branch and reports 177 problems on upstream's pstack/ tree.
  • node --test scripts/check-t3-port.test.mjs passes 9 of 9: the branch passes, and each of 8 planted regressions fails with its rule id.

🤖 Generated with Claude Code


Note

Low Risk
Mostly docs and CI-style lint on skill copy; limited runtime impact except new agent rules for Claude fast mode and one playbook default string.

Overview
Adds T3 port guardrails before the fork catches up to upstream pstack (0.15.17→0.15.25). FORK.md gains a T3 port intent table (subagents, roles, speed, trunk, install, etc.) and numbered sync steps; FORK-SYNC-LOG.md logs 29 upstream commits with planned take/adapt/skip and target follow-up PRs. No upstream behavior is ported in this PR (first of four).

scripts/check-t3-port.mjs scans pstack/skills and pstack/agents for Cursor drift (Task, -fast slugs, origin/main, hidden skills, Graphite, Claude fastMode=true defaults, etc.), required T3 anchor strings, and named-only skill descriptions; failures name the fix. A PENDING allowlist tolerates known drift until sync PRs B/C land, and stale entries fail the check. check-t3-port.test.mjs asserts the repo passes and eight planted regressions fail with the right rule id.

Skill text changes: poteto-mode documents Speed (Grok/GPT fast OK; Claude fastMode only on explicit per-task operator approval in-session). setup-pstack refuses to write Claude fast mode on role lines. multi-phase-plan updates the default swarm workers model to the T3 role-line form (cursor/grok-4.7 … fastMode=true).

Reviewed by Cursor Bugbot for commit e55a05b. Configure here.

Add scripts/check-t3-port.mjs, which fails when Cursor wording comes back
into pstack/skills or a T3 anchor goes missing, and names the fix. A
PENDING list holds the drift that later sync PRs remove, and fails once
an entry has nothing left to match.

FORK.md gains a "T3 port intent" table that says what the fork changes
and why, plus the sync steps. FORK-SYNC-LOG.md lists all 29 upstream
pstack commits since 11713c6 with a planned decision each.

poteto-mode's Subagents section gets a Speed rule. Grok and GPT may run
fast freely. Claude fast mode needs the operator's approval in the
session, for one named task only. setup-pstack never writes it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-17T15:14:31.551425Z f78e11d New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e55a05be32

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/check-t3-port.mjs Outdated
Comment on lines +107 to +108
if (pending >= 0) usedPending.add(pending);
else fail(`${file}:${i + 1}`, rule.id, rule.fix);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Limit pending exemptions to the known violations

When a file has a matching PENDING entry, every occurrence of that rule in the file is accepted, rather than only the pre-existing violation. During the upcoming sync, adding another forbidden command such as gt submit to playbooks/orchestrate.md still produces T3 port check clean, so the guard misses exactly the new drift it is intended to catch. Record expected lines or match counts and fail when additional occurrences appear.

Useful? React with 👍 / 👎.

Comment on lines +13 to +14
const root = mkdtempSync(join(tmpdir(), "t3-port-"));
cpSync(join(repo, "pstack"), join(root, "pstack"), {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Clean up copied test trees

Every regression test creates a complete temporary copy of pstack but never removes it. A single invocation currently leaves eight roughly 4 MB directories under /tmp, so repeated local runs or runs on persistent workers continually consume disk space. Track the created roots and remove them in test teardown.

Useful? React with 👍 / 👎.

leegmoore and others added 2 commits October 17, 2026 11:04
The Speed rule now says a Claude fast-mode approval covers only the work the operator names, not retries, replacement agents, reviewers, verifiers, the lead's own chat or later sessions, and that it ends with that work.

The drift check counts PENDING matches exactly, so new drift in a pending file fails. It now catches Cursor's environment, run_in_background, readonly and ~/.cursor/plugins wording and structured Claude targets with fastMode true. It reads YAML block descriptions, requires the named-only sentence at the end, and accepts disable-model-invocation: false. FORK.md names the auto and inherit-parent target exception and the four auto-load skills.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The structured-target check now finds the object around each claudeAgent provider and looks for fastMode true inside it, in any key order, with single or double quotes, or as T3's list of {id, value} options. Prose after the object no longer counts. Plain YAML descriptions that continue on the next line parse again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 58e54b1b76

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/check-t3-port.mjs Outdated
// A structured T3 target can span lines and list its keys in any order, so these run
// over the whole object that holds each claudeAgent provider.
const CLAUDE_PROVIDER = /["']?providerInstanceId["']?\s*:\s*["']claudeAgent["']/g;
const FAST_ON = /["']?fastMode["']?\s*[:=]\s*true\b|["']id["']\s*:\s*["']fastMode["']\s*,\s*["']value["']\s*:\s*true\b/;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Match list-form fast options regardless of key order

When a valid list-form option serializes its members as {"value": true, "id": "fastMode"}, this regex misses it: the first alternative expects fastMode to be followed by : or =, while the second hard-codes id before value. Consequently, a structured Claude target with fast mode enabled can still produce T3 port check clean solely because JSON object members were reordered; parse the option object or accept either member order.

Useful? React with 👍 / 👎.

…simple

Two rounds of parser fixes kept missing target shapes. A census found no structured targets in the fork's skills or upstream's, and 21 compact role lines, which the existing rule covers. So the object parser goes. A line naming claudeAgent as the provider now fails if fastMode appears within 8 lines, whatever the value, key order or comments. Skill examples never need to show Claude fast mode.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@leegmoore
leegmoore merged commit d116852 into lim Oct 17, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f78e11d77b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/check-t3-port.mjs

const root = resolve(process.argv[2] ?? join(dirname(fileURLToPath(import.meta.url)), ".."));
const SCANNED = ["pstack/skills", "pstack/agents"];
const TEXT = /\.(md|mjs|js|ts|sh|json|tsv)$/;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Scan extensionless source files for port drift

The extension allowlist silently excludes the existing source file pstack/skills/poteto-mode/scripts/watch-pr/watch-pr. During an upstream sync, adding a banned construct such as origin/main to that executable still produces T3 port check clean, so the new guard does not cover all installed source under its advertised scan roots. Include extensionless text executables or determine text files by content rather than this suffix list.

Useful? React with 👍 / 👎.

@leegmoore
leegmoore deleted the sync/a-guardrails branch October 17, 2026 15:44
leegmoore added a commit that referenced this pull request Oct 17, 2026
* test(orch): pin that frontier set refuses a trunk checkout

resolveFrontier already throws a UserError when HEAD is the trunk, so
`orch frontier set` can no longer overwrite a valid frontier with an
empty one. Nothing tested it. The new test saves a frontier, checks out
main, asserts the UserError, and asserts frontier.json is byte-for-byte
unchanged. It fails when the guard is removed.

Fixes #6 (comment)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(check-t3-port): scan extensionless text files and clean up test trees

The extension allowlist skipped extensionless executables such as
scripts/watch-pr/watch-pr, so drift planted there passed. The walker now
also scans an extensionless file when its first 8 KB hold no NUL byte.
New tests plant origin/main in watch-pr and show an extensionless binary
is skipped. Each test fails against the matching broken walker.

copyTree(t) now registers t.after cleanup right after creating its temp
root, and every caller passes t, so runs no longer leave t3-port-* copies
of the tree in the temp dir.

Fixes #4 (comment)
Fixes #4 (comment)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(pstack): compare the whole PR patch before reusing a verdict

Shipping step 3 compared `git patch-id` at the verdict SHA with the
head. Hashing a commit only covers the tip, so a rebase that changed an
earlier commit of a multi-commit PR could keep an old verdict for code
no verifier saw.

A verdict now records the head it verified and that head's merge base
with the PR's base branch, taken at verification time. Reuse compares
`git diff <saved-merge-base> <verdict-head> | git patch-id --stable`
with the same diff from the current merge base to the current head. The
saved merge base is never recomputed, because a restack moves it. The
build-equivalence exception for test, doc and lint changes stays.

Shipping step 3 owns the rule. autopilot-full, autopilot-stack and
multi-phase-plan point to it.

Fixes #6 (comment)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(pstack): place /ketchup choices above the list and restore /swarm's N step

/ketchup said to show a choice after the action list, but also that
the html_render page, where a drawn choice goes, shows above the reply.
It now says to show each choice above the list, either under the
screenshots that already show its options or on the published page,
with the action item ending "see the page above".

Upstream's 99743e9 cut /swarm's step 3, so a bare "swarm this" left N
undefined while Phase B still spawns all N workers. The step is back,
and FORK-SYNC-LOG.md records it as a fork fix on top of 99743e9.

Fixes #7 (comment)
Fixes #7 (comment)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(pstack): compare verdict patches with whitespace kept

git patch-id --stable strips whitespace, so a rebase that only dedents Python or changes YAML nesting kept the same ID and carried an old verdict to untested behavior. --verbatim keeps whitespace. Checked in a scratch repo: --stable gave the same ID for a dedent that changed behavior, --verbatim gave different IDs.

Fixes #9 (comment)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant