Harness Contributing
This is the executable contribution path for this repository. Start with a
public issue or a maintainer-approved scope, work in one isolated worktree, and
finish with a reviewable pull request. The current
tools/gate-manifest.json,
package.json, and
pull_request_template.md remain the
machine-readable authorities they describe; inspect them instead of relying on
remembered job names or template fields.
Boundary
Use only public repository source, public issue/PR discussion, and evidence a reviewer may see. Never copy local planning records, generated runtime state, local agent instructions, credentials, private URLs, or absolute machine paths into the branch or PR body. Before every commit, inspect the complete staged diff and confirm every path belongs to the stated public scope.
The contribution scope grants authority to change the stated files and run
local checks. Push the branch or open/update its PR only when the user or
maintainer asked for that external action. No contribution grants authority to
push to main, bypass a gate, force-push, or merge. A maintainer owns the final
merge.
中文:只使用公开仓库、公开 issue/PR 和 reviewer 可见的证据。不要把本地规划、 运行状态、凭证、私有链接或本机绝对路径放进公开 diff 或 PR。贡献者只能提交提案, 不能直推或自行合入
main。
Environment and worktree
Node.js 24 or newer and git are required. For a new checkout, run:
git clone https://github.com/FairladyZ625/harness-anything.git
cd harness-anything
git fetch origin
git status --short --branch
Run this version gate as one standalone command before npm ci; it exits
nonzero and prints three common activation choices when the active Node is too
old:
node -e 'const major=Number(process.versions.node.split(".")[0]); if (major < 24) { console.error([`Node.js 24+ required; found ${process.version}.`, "nvm: nvm install 24 && nvm use 24", `Homebrew node@24: brew install node@24 && export PATH="$(brew --prefix node@24)/bin:$PATH"`, "Volta: volta install node@24"].join("\n")); process.exit(1); } console.log(`Node.js ${process.version} satisfies >=24`);'
If it fails, use one printed line to activate Node 24, then rerun the same gate
until it exits zero. Stop if the checkout already has changes you do not own.
Do not implement on the primary checkout or shared main. From the primary
checkout, create exactly one task worktree from current origin/main:
git worktree add .worktrees/<slug> -b <branch> origin/main
cd .worktrees/<slug>
git merge-base --is-ancestor origin/main HEAD
git rev-list --count origin/main..HEAD
git log --oneline origin/main..HEAD
git status --short --branch
npm ci
Replace <slug> with a short filesystem-safe scope and <branch> with the
public contribution branch, such as fix/<slug> or docs/<slug>. If either
name already belongs to another worktree, choose a new name; never share that
worktree. git merge-base --is-ancestor must exit zero before editing. A newly
created branch should print 0 from git rev-list and no commit lines from
git log. Any listed commit is already part of the prospective
origin/main...HEAD PR delta: continue only when it belongs to the approved
public contribution, and later describe the whole branch delta while clearly
distinguishing those pre-existing commits from the edits made in this run.
Otherwise stop and create a clean worktree or ask the maintainer which branch
scope is intended.
Read the issue and relevant source in this worktree. State, in one sentence, the problem, allowed change surface, excluded surface, and proof required. Ask for a maintainer decision rather than guessing when the public issue does not settle a load-bearing choice.
中文:先用单独的一条可执行命令确认 Node 24+,再从最新
origin/main创建独立 worktree;每个贡献者或 agent 使用自己的 branch/worktree。编辑前列出 ahead commit;它们会进入整个 PR diff,不能当作不存在。安装依赖并写清范围后再编辑。
Make the change and test its surface
Keep the patch to the smallest coherent solution. Inspect nearby code and tests before adding a new abstraction. Preserve unrelated changes and generated files.
Every new Node test under packages/ or tools/ must:
- have a filename ending in
.test.mjs,.test.js,.test.ts,.spec.mjs,.spec.js, or.spec.ts; and - put exactly one of these declarations on line 1:
// harness-test-tier: fast
// harness-test-tier: contract
// harness-test-tier: integration
Choose fast for pure or near-pure behavior, contract for public API/schema
or cross-package contracts, and integration for CLI, filesystem, store,
migration, or other slower behavior. The rules are enforced by
tools/test-tier-manifest.mjs; there is no
central file list to edit.
Run each changed or newly added Node test through the repository runner:
node tools/run-node-tests.mjs --file <repo-relative-test-file>
Repeat --file for multiple exact files when they form one test surface. For a
docs-only change, run the closest docs checker or checker test if one exists;
do not invent a meaningless test. Always inspect the patch:
git status --short
git diff --check
git diff --stat
git diff -- <changed-paths>
中文:测试文件名必须匹配
.test/.spec约定,首行必须且只能声明一个fast|contract|integrationtier。先跑改动面的精确测试;docs-only 改动若没有 对应行为测试,不要为了凑数新增无意义测试。
Run local gates
Do not use npm run check:local as the contribution loop, and do not run the
full aggregate merely to approximate GitHub. GitHub CI is authoritative. The
worker stop-point command derives its cheap deterministic checks from the
current gate manifest and the complete working-tree diff:
node tools/run-manifest-gates.mjs --changed origin/main
Run that command before the local commit. It includes every matching gate whose
manifest entry is deterministic, local, PR-visible, and declares
localPathGlobs; an unscoped gate is not silently promoted into this bounded
local path. Run affected integration tests separately through the isolated test
dispatcher. Use --workflow-job only to reproduce or preflight a particular CI
job; workflow mode runs all selected gates and reports every failure together.
First list the current pull-request job names and tiers:
node -e 'const m=require("./tools/gate-manifest.json"); console.log([...new Set(m.gates.filter(g=>!g.aggregate).flatMap(g=>(g.executionSurfaces?.rewriteCi?.pullRequestJobs??[]).map(job=>`${g.tier}\t${job}`)))].sort().join("\n"))'
Then print the gate IDs, commands, and declared consumer scope behind those jobs; use this output rather than inferring a job from its name:
node -e 'const m=require("./tools/gate-manifest.json"); for (const g of m.gates.filter(g=>!g.aggregate)) for (const job of g.executionSurfaces?.rewriteCi?.pullRequestJobs??[]) console.log(`${job}\t${g.id}\t${g.command}\t${(g.consumerScope??[]).join("; ")}`)'
Then run every job that matches the changed surface. Pass the merge base to the runner so its optional manifest path declarations can narrow local commands; a working-tree comparison includes committed, uncommitted, and untracked edits:
node tools/run-manifest-gates.mjs --workflow-job <job> --changed origin/main
npm run typecheck
boundaries is the usual job for public source, tool, and documentation
boundaries. Use the manifest's other current PR jobs when the patch touches
their surface—for example tests, package policy, dependencies/supply chain, or
the GUI. Path selection is conservative: it narrows a job only when every
changed path matches explicit localPathGlobs; an unclassified or mixed surface
runs the complete job. A docs-only change under docs-release/** selects the
three docs/release checks declared by the manifest. CI omits --changed and
still runs every command in every job. Record every command and result in the PR
body, including a scoped reason for anything not run.
One gate has a local credential exception. If boundaries reaches
check-github-required-contexts, the only failure that may be excluded locally
is the exact error repository must be provided as owner/name when no GitHub
repository/token context is available. Preserve that output and rerun the same
job with only that gate excluded:
node tools/run-manifest-gates.mjs --workflow-job boundaries --changed origin/main --exclude check-github-required-contexts --resume
If that exact message is not the sole failure, do not exclude the gate. Never
treat the exclusion as a CI waiver; the required GitHub context must still pass
on the PR. --resume uses only the checkpoint from the latest failed run in the
same worktree, skips commands that already passed, and removes the checkpoint
after success. If the selected gates or their commands changed, the runner
rejects the checkpoint; rerun without --resume so affected checks are not
skipped. Results are never cached across successful runs.
中文:worker 停止点统一运行
node tools/run-manifest-gates.mjs --changed origin/main;它从 manifest 中派生带localPathGlobs的本地、PR、确定性门,不维护 第二份清单。受影响的 integration 测试仍须经隔离派测入口单独运行。按 job 复现 CI 时才使用--workflow-job,该模式会跑完所选门并一次报告全部失败;CI 始终全跑。 本地只有check-github-required-contexts的精确报错repository must be provided as owner/name可在确认缺 GitHub 上下文后单独排除; 该排除不适用于 CI,也不能掩盖其他失败。--resume只复用同一 worktree 最近一次 失败运行的已绿命令;成功后删除断点,所选 gate 或命令变化后必须重新完整执行。
Commit with the contributor identity
Confirm the author identity before committing:
git config --get user.name
git config --get user.email
If either is empty or wrong, the contributor must set their own identity before continuing:
git config user.name "<your name>"
git config user.email "<your email>"
Stage only named contribution paths, recheck the staged patch, and commit:
git add <changed-paths>
git diff --cached --check
git diff --cached --stat
git diff --cached -- <changed-paths>
git commit -m "<feat|fix|refactor|docs|test|ci>: <concise English summary>"
Do not mention an AI author in the commit message. Use the actual human or agent operator's configured git identity.
Prepare the bilingual PR body
Do this after all contribution commits, because the production-delta gate
measures committed HEAD from its merge-base. Refresh and synchronize first,
then rerun affected tests and gates if the rebase changes the branch:
git fetch origin
date -u '+%Y-%m-%d %H:%M:%S UTC'
git rebase origin/main
git rev-parse origin/main
git merge-base origin/main HEAD
git status --short --branch
Put the date -u output in Last git fetch origin time. If the initial
worktree check found approved pre-existing commits, describe the complete
origin/main...HEAD delta in the PR body and explicitly separate those commits
from the changes authored in the current run.
Copy the current template; never reconstruct its sections from memory:
cp .github/pull_request_template.md /tmp/harness-anything-pr-body.md
${EDITOR:-vi} /tmp/harness-anything-pr-body.md
Fill every uncommented section in the complete # English block and the
complete # 中文 block. Preserve their order and the shared checklist. Use
not applicable plus a reason where appropriate instead of deleting a section.
Keep machine-readable declarations exactly once and only in the English block,
flush left as the template instructs. Do not claim CI, human review, or a test
that has not happened.
For an external contributor, fill Harness task in both language blocks with
the public issue number, for example #1234; if there is no public issue, write
not applicable. Never put a private task ID, local planning ID, or private
evidence path in the public PR body. If neither package.json nor
package-lock.json changed, delete the entire Dependency-Change: line; do not
leave Dependency-Change: none. Keep and fully describe that line only when one
of those dependency files changed.
In the Verification checklist, check an item only when its exact command exited
zero, either because you ran it directly or because the manifest runner printed
that command and reported it passed. A passing current boundaries job
indirectly runs these checklist items:
npm run harness:check-import-boundariesnpm run harness:scan-forbidden-symbolsnpm run harness:check-private-boundarynpm run harness:check-implementation-contractsnpm run harness:check-schema-contractsnpm run harness:check-legacy-intake-readiness
Check those items only when all appear as passed in the runner output. Do not
infer that npm run check, npm test,
npm run harness:check-package-policy, or
npm run harness:smoke-cli-package ran as part of boundaries; leave each
unchecked unless that exact command actually passed. Record the top-level
manifest command and any allowed exclusion in the surrounding Verification
text.
Run the authoritative production-delta calculator after all commits. It reports the computed addition, deletion, churn, and net values without requiring a PR body declaration:
node tools/gates/production-delta.mjs --base origin/main --pr-body-file /tmp/harness-anything-pr-body.md
If computed production churn exceeds 200 lines or net growth exceeds +300, fill both architectural-justification sections.
Preflight the two complete language blocks through the requested environment interface, then run the manifest's full PR-body job:
export PR_BODY="$(cat /tmp/harness-anything-pr-body.md)"
node tools/check-pr-body-bilingual.mjs --env PR_BODY
export PR_BASE_SHA="$(git merge-base origin/main HEAD)"
export PR_HEAD_SHA="$(git rev-parse HEAD)"
node tools/run-manifest-gates.mjs --workflow-job pr-body-lint
unset PR_BODY PR_BASE_SHA PR_HEAD_SHA
references/example-pr-body.md is a completed
docs-only example that exercises every section. It is a fixture, not a template:
always copy the live repository template for a real PR.
中文:所有 commit 完成后运行 production-delta 计算器。PR body 必须保留模板的完整 英文块、完整中文块和共享 checklist;其余机读声明只在英文块顶格出现一次。外部贡献者的
Harness task只填公开 issue 号,没有就填not applicable,不要放私有 ID;无依赖 文件变化时删除整条Dependency-Change:。checklist 只勾选直接通过、或由 runner 明确打印并通过的命令。不得把未发生的 CI、人工 review 或测试写成已完成。
Push and open the PR
Push only the contribution branch to a remote where the contributor has write access:
git push -u <write-remote> HEAD
With an authenticated GitHub CLI, open the PR against the canonical main:
gh auth status
gh pr create --repo FairladyZ625/harness-anything --base main --head <github-user>:<branch> --title "<PR title>" --body-file /tmp/harness-anything-pr-body.md
If the branch is in the canonical repository rather than a fork, use
--head <branch>. Save the PR URL. Update the body rather than replacing it
with a shorter hand-written summary when later commits change scope or delta.
Review and merge
Watch the protected checks and read the actual failure output:
gh pr checks <pr-number> --repo FairladyZ625/harness-anything --watch
gh pr view <pr-number> --repo FairladyZ625/harness-anything --comments
Triage every concrete reviewer or bot finding. Before merge, each P0/P1/P2 finding must be fixed, explained as a false positive, deferred with an owner and reason, or left explicitly blocking. For a fix, edit the same worktree, rerun the smallest proving test and affected manifest jobs, make another prefixed commit, push normally, and update the PR body. Never force-push to escape a failed check.
External contributors and their agents stop after the PR is green, current, conflict-free, and fully reviewed. A maintainer performs the repository's normal merge-commit path; only that maintainer may run:
gh pr merge <pr-number> --repo FairladyZ625/harness-anything --merge --delete-branch
Do not squash, rebase-merge, direct-push, or use an admin bypass. The contribution is complete when GitHub reports the PR merged or closed with a clear reason.
中文:逐条处理 CI、human review 和 bot comment;P0/P1/P2 必须完成 triage。 外部贡献者或 agent 在 PR 全绿、无冲突、review 完成后停下,由 maintainer 用普通 merge commit 合入。不得 squash、rebase merge、直推或 admin bypass。
Agent contributor notes
An agent follows the same path and evidence standard as a human. It must keep the declared scope visible, preserve unrelated work, show exact commands and results, and leave external actions such as pushing or opening a PR within the user's granted authority. It must not report human review, Dashboard confirmation, release readiness, or merge approval on anyone else's behalf.
Before handoff, report:
- what changed and what stayed out of scope;
- exact tests and manifest jobs run, with pass/fail results;
- commands not run and the scoped reason;
- the production delta and PR-body preflight result;
- open findings, residual risk, and the files needing human attention; and
- that merge remains maintainer-owned.
中文:agent 必须保留无关改动、如实报告命令结果,且不能替人声称人工确认、发布 就绪或合入批准。handoff 要写清改动、验证、未跑项、风险和 maintainer 合入边界。