Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .agents/skills/evidence/scripts/evidence_browser.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@ if (typeof WebSocket !== "function") {
}

const profile = await mkdtemp(path.join(tmpdir(), "evidence-profile-"));
// Headless Chrome in GitHub-hosted ubuntu containers often never writes DevToolsActivePort unless the sandbox
// and tiny /dev/shm are disabled. The profile is still a fresh mkdtemp and is removed afterwards; never a user profile.
const args = [
"--headless=new", "--remote-debugging-port=0", `--user-data-dir=${profile}`, "--no-first-run", "--no-default-browser-check",
"--disable-extensions", "--disable-sync", "--disable-background-networking", "--mute-audio", "--hide-scrollbars",
"--no-sandbox", "--disable-setuid-sandbox", "--disable-dev-shm-usage", "--disable-gpu",
`--window-size=${job.viewport.width},${job.viewport.height}`, `--lang=${job.locale}`, "--force-device-scale-factor=1", "about:blank",
];
let browser;
Expand Down Expand Up @@ -75,6 +78,7 @@ try {
const portFile = path.join(profile, "DevToolsActivePort");
let endpoint;
await Promise.race([spawnError, waitFor(async () => {
if (browser.exitCode !== null) throw new Error(`browser exited ${browser.exitCode} before DevToolsActivePort appeared`);
try { endpoint = (await readFile(portFile, "utf8")).split("\n"); return endpoint.length >= 2 && endpoint[0].trim() !== ""; } catch { return false; }
}, "the browser's DevToolsActivePort file")]);
const port = endpoint[0].trim();
Expand Down
113 changes: 96 additions & 17 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,98 @@
# Contributing to sum

Use an isolated development checkout and keep the installation serving live work untouched.

## Checklist

- [ ] Confirm the repository root, target branch, and the task's approved scope.
- [ ] Install only the pinned verification prerequisites with `mise install go python node`; Git must also be available.
- [ ] Make the smallest change that satisfies the approved acceptance criteria.
- [ ] Run `MISE_ENABLE_TOOLS=go,python,node python3 .agents/skills/verify/scripts/verify_run.py --base <merge-base>` once for your role and retain its candidate-bound record.
- [ ] Run `mise run test-live` separately only when a real Herdr smoke test applies and is available; otherwise leave that manual scenario accurately not-run.
- [ ] Describe acceptance results and evidence paths in the handoff, including failures or manual scenarios not run.
- [ ] Include contributor attribution when applicable, adding an entry to `ATTRIBUTIONS.md` when new material or inspiration enters, and state deployment or release impact when relevant.
- [ ] Leave branch-protection and merge actions to their owner; a human reviews and merges changes.

The recommended order is scope and prerequisites, implementation, canonical verification, applicable live verification, review, then human merge.
Only explicit technical dependencies are prerequisites; a roadmap's recommended order does not create a dependency.
The worker's run, a fresh root run for the same candidate, and independent review are all required before human merge.
CI supplies additional evidence; an absent CI result, worker-only pass, or missing root review is not merge readiness.
Thanks for wanting to help with sum.

Sum is a small, Herdr-native agent distro: harness instructions in [AGENTS.md](AGENTS.md) do the reasoning, Herdr owns panes and worktrees, and `bin/sumctl` keeps task records. There is no sum daemon, and contributions do not go through a special push proxy.

The normal path is an ordinary GitHub pull request targeting `main`. Keep the change scoped, follow the verification contract in [VERIFY.md](VERIFY.md), and leave merge to a human.

## Workflow

Pull requests target `main`. Fork, branch, commit, push, and open a PR in the usual way.

1. Fork [douglasjarquin/sum](https://github.com/douglasjarquin/sum) if you do not have push access, then clone your fork (or clone this repository).
2. Update `main` from upstream and create a topic branch.
3. Make the smallest change that satisfies the accepted scope.
4. Commit with a message that says what changed and why.
5. Push the branch to your remote.
6. Open a pull request against `main`.

If you are editing a checkout that already serves a live coordinator, do the work in an isolated development checkout instead of that installation. See [Repo conventions](#repo-conventions). That is local hygiene, not a second publication path: the PR still targets `main` through ordinary git.

GitHub Actions runs the same verification runner described in [VERIFY.md](VERIFY.md) on pull requests to `main`. Treat CI as extra evidence. A human reviews and merges; do not assume a green check is merge authority.

## Verification

[VERIFY.md](VERIFY.md) is this repository's verification contract. Use that file. It is not a stub, and a contribution should not replace it with a different gate.

The contract works in an ordinary clone with Git, mise, and the pinned tools. You do not need a sum installation, a Herdr session, or any path outside this checkout.

Install the pinned verification tools once:

```sh
mise install go python node
```

Git must also be available from the host. For a local run, prefix the runner with `MISE_ENABLE_TOOLS=go,python,node` so mise does not automatically install unrelated repository tools.

The canonical aggregate entrypoint is:

```sh
mise run verify
```

That command is what [VERIFY.md](VERIFY.md) names as `entrypoint`. It runs, in order, the offline Python suites, the Mesh Node tests, and the scripted demo, and stops at the first failure. Feature maps under `docs/features/` say which user journeys those checks cover.

For a candidate you intend to land, run the recorded runner against the merge-base so edits to the contract, mise tasks, or maps are flagged for root review:

```sh
MISE_ENABLE_TOOLS=go,python,node python3 .agents/skills/verify/scripts/verify_run.py --base <merge-base>
```

A preflight that validates the contract without running the suites:

```sh
python3 .agents/skills/verify/scripts/verify_run.py --check
```

Scoped iteration can use `mise run test` (suites only) and `mise run demo`. `mise run test-live` is the explicit real-Herdr smoke test and is not part of the aggregate; run it only when that scenario applies and a real Herdr is available, otherwise record it as not-run.

Keep checks pointed at temporary state homes and named lab sessions. Never aim a test at a live `.sum/` directory or the user's `default` Herdr session.

Record the command, result, and evidence path (under `.artifacts/verification/`) in the pull request. Say so when a mapped manual scenario was not exercised. A green `mise run verify` covers the automated feature-map rows only.

When the change is delivered through sum, the worker's run, a fresh root run of the same candidate, and independent review remain required before a human merges. CI does not replace those.

## Repo conventions

These conventions are for this repository. Sum is not a Node/pnpm app; do not import that workflow.

- **Tools.** [mise.toml](mise.toml) pins Go, Python, and Node. Verification requires `git`, `mise`, `go`, `python3`, and `node`. Use those pins. Do not add a competing toolchain to make the checks easier to pass.
- **Helper.** The CLI is `./bin/sumctl` (or `sumctl` after setup). That name exists so this project does not shadow the Unix `sum` command.
- **Roles.** A harness session in a sum checkout starts with `./bin/sumctl init` and follows the role it returns: `coordinator`, `worker`, or `developer`. Read [AGENTS.md](AGENTS.md). Sending a pull request does not require becoming a coordinator. If another pane already owns coordination, or you are in a development checkout, stay a developer.
- **Live installs.** The checkout where setup ran serves live work. Change sum from an isolated checkout:

```sh
./bin/sumctl dev prepare --name my-topic
cd .sum/dev/my-topic && ./bin/sumctl init
```

Details are in `skills/sum-develop/SKILL.md`. Do not edit the installation's `.sum/`, run setup for it, or dispatch from a developer pane.
- **Scope.** Change only what the accepted work needs. Do not retarget verification to a `verify` task inherited from a parent directory.
- **State.** `.sum/` is Git-ignored private state. Do not commit it, secrets, or runtime credentials. Commit `mise.lock` with dependency changes when a networked machine generates it; do not fabricate one.
- **Attributions.** When new material or inspiration enters the tree, add an entry to [ATTRIBUTIONS.md](ATTRIBUTIONS.md). That page supplements license and source notices; it does not replace them.
- **Platforms.** macOS and Linux are the targets. Windows is not supported by the file-locking helper in this MVP.
- **Merge.** Leave branch-protection and merge actions to their owner.

### Before you open a PR

- [ ] Confirm the repository root, target branch (`main`), and the change's scope.
- [ ] Install pinned verification prerequisites with `mise install go python node`.
- [ ] Run the [VERIFY.md](VERIFY.md) entrypoint (or the runner with `--base`) and keep the candidate-bound record.
- [ ] Run `mise run test-live` only when that live scenario applies; otherwise say it was not run.
- [ ] Note deployment or release impact when it exists.
- [ ] Update [ATTRIBUTIONS.md](ATTRIBUTIONS.md) when credit is due.

## Questions

Open a [GitHub issue](https://github.com/douglasjarquin/sum/issues).
8 changes: 8 additions & 0 deletions tests/test_evidence_skill.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,14 @@ def test_capabilities_report_what_this_machine_can_drive_and_never_claim_an_abse
self.assertFalse(caps["browser"]["supported"])
self.assertIn("no Chromium-family browser", caps["browser"]["reason"])

def test_browser_driver_launches_with_container_safe_flags_and_an_ephemeral_profile(self):
source = (ROOT / ".agents/skills/evidence/scripts/evidence_browser.mjs").read_text()
for flag in ("--no-sandbox", "--disable-setuid-sandbox", "--disable-dev-shm-usage", "--disable-gpu"):
self.assertIn(flag, source)
self.assertIn("mkdtemp", source)
self.assertIn("evidence-profile-", source)
self.assertIn("--user-data-dir=${profile}", source)

# -- the real browser path --------------------------------------------------------------------
@unittest.skipUnless(BROWSER and NODE_OK, BROWSER_REASON)
def test_seeded_browser_bug_is_red_at_base_and_green_at_candidate_with_screenshots_and_playable_video(self):
Expand Down
10 changes: 9 additions & 1 deletion tests/test_verify_skills.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,8 +359,16 @@ def test_change_detection_affected_maps_rationale_and_deliberately_failing_branc
self.assertIn("docs/features/service.health.md", record["policy"]["changed"])
# A deliberately failing branch: the test contradicts the code. The runner fails; the audit does not paper over it.
self.git(repo, "checkout", "-q", "-b", "failing")
test.write_text(test.read_text().replace('"version": 2})', '"version": 3})'))
source = test.read_text()
self.assertIn('"version": 2})', source)
test.write_text(source.replace('"version": 2})', '"version": 3})'))
self.assertIn('"version": 3})', test.read_text())
self.git(repo, "commit", "-qam", "wrong expectation")
# The earlier runner in this method compiled tests/test_app.py. A same-second rewrite can leave a timestamp-valid
# .pyc of the passing tests, so the next discover run would not see the wrong expectation.
cache = repo / "tests/__pycache__"
if cache.is_dir():
shutil.rmtree(cache)
code, record, _ = self.runner(repo, "--base", base)
self.assertEqual((code, record["outcome"]), (1, "fail"))
self.assertEqual({s["status"] for s in record["scenarios"] if s["driver"] == "automated"}, {"fail"})
Expand Down