Repository navigation
jpdev check --changed follow-ups: the vendored check.sh, CI on pull requests, the small-fix prompt, the version message (#43) - #45
Conversation
…equests, the small-fix prompt, the version message (#43) - scripts/dev/check.sh --changed [BASE] (and templates/check.sh): the same selection, rules and report as jpdev check --changed, through scripts/dev/changed_checks.py, a versioned copy of lib/changed_checks.py vendored beside it (the template run from the kit falls back to lib/changed_checks.py). The vendored selection code is a selection input. Every fixture of tests/changed_checks_test.py runs through both runners, and a test compares their reports. - CI: a pull request runs check.sh --changed against its base branch; a push to the default branch and a dispatch run the whole list, and only they record release evidence. Applied to templates/ci-check.yml and the kit's own ci.yml (each job keeps its steps with --skip). - codex run --small tells the builder to run jpdev check --changed instead of --only <steps>. - jpdev version adds the kit checkout's git describe; an unknown jpdev check option and a refused --changed selection name it; an unknown check.sh option names the runner's release line. Closes #43 Signed-off-by: kikashy <35789537+kikashy@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review record: devkit PR #45 (issue #43,
|
| # | Finding | Sev | Evidence | What to do |
|---|---|---|---|---|
| 1 | The "no merge base" refusal in resolve_base (code from #40, used by this PR's CI path) has no test. |
MEDIUM (from #40) | Mutant M2d (fall back to HEAD in both copies) survives: 49/49 OK. In CI (fetch-depth: 0, clean tree) the mutant would still run the whole list. Locally, with uncommitted edits, it would select too few checks. |
Add a shallow-clone fixture to ChangedCheckTests that asserts exit 2 and the message, so it runs through both runners. Pre-release batch. |
| 2 | No test pins the new scripts/dev/changed_checks.py entry in .github/ci-evidence.json inputs. |
LOW | M3 survives in ci_evidence_test and run.sh, as expected: capture and verify both hash the inputs from git show at the same SHA, so removing the entry changes the record but no admit/refuse decision. |
Optional: a test that the inputs cover scripts/dev/*. |
| 3 | The kit's lint job selects steps differently on PRs (--skip tests) than on push (--only plus 7 names). |
LOW | A step added to dev.json later would run in PR lint but in neither job on main, and the explicit evidence list would not require it. The --only on push is older; this PR makes the two paths diverge. |
Use --skip tests on push too. Capture then refuses with check-coverage until the evidence file lists the new step. |
| 4 | When the base cannot be resolved (missing ref, empty BASE_REF, shallow clone), the run refuses (exit 2, the required job fails) instead of running the whole list. |
LOW (docs) | Probed: all three exit 2 before any check runs, and none is read as "nothing changed". This fails closed, and the README lists the refusal. | Optional: adopting.md §4 can say the PR job fails rather than falls back. |
| 5 | jpdev version with GIT_DIR in the environment (for example, under a git hook) describes the other repository's commit as the kit's. |
LOW | Probe: GIT_DIR=<fixture>/.git jpdev version printed jpdev 0.7.0 (b0529e7), the fixture's commit. |
Clear GIT_DIR/GIT_WORK_TREE for the two git calls in kit_version. |
What held:
-
A (boundary): Two guards keep PR runs out of capture: the step
if(refs/heads/mainand notpull_request) andcaptureitself (GITHUB_REFmain, event in {push, workflow_dispatch}).verifyadmits only runs with head_branch main, an allowed event, no PR association,head_shaequal to the tag commit, and this repository as head repository. Coverage must equal the configured list, all PASS. The push and dispatch commands are unchanged (lint 7 + tests 1 = dev.json's 8, equal to the evidence lists). Across the two jobs, the PR split (--skip tests/--skip7) runs the whole list. -
B: Probed on a simulated PR merge commit with the vendored runner:
- docs-only: lint 3, tests none
- AGENTS.md: 4 checks plus
tests - templates/*.md: 2 checks plus
tests - whole list across both jobs: unmapped, mixed, rename to unmapped,
scripts/dev/check.sh,scripts/dev/changed_checks.py,jpdev.json,dev.json, empty PR
BASE_REFreaches the script through env and is quoted. -
C:
run.shcompares the whole library with the vendored copy minus line 2, and checks line 2 againstjpdev --version. The release.yml snippet, extracted and run: the clean copy passes; body drift, line-1 drift, wrong line 2, an appended line and a missing file are all refused. All 18ChangedCheckTestsalso run through the vendored runner (18 + 5 = 23), and the report comparison covers 3 cases. -
D: The messages carry no path. An unpacked (non-checkout) kit and a PATH without git both print the plain version with exit 0.
--versionis unchanged. -
E: 13 mutants killed: unmapped fallback (lib only; vendored only), unresolved base to HEAD, runner refusal to whole, runner drops
--base, empty selection, vendored body drift, vendored line 2, library not re-copied, evidence coverage subset, capture on any event, capture on any ref, select on any event. Survived: M2d (jpdev v0.1.0: setup, check, mutants, record; the manifest, the public runner, the agent docs and the policy #1), M3 (The go toolchain takes a version in dev.json, so a workflow's Go pin has one source #2), and E3, whererun_identity's event clause is redundant withselect()'s filter (E4 killed; code from Reuse trusted exact-commit CI evidence at release through a shared tested gate #37, no gap). -
F: No machine-local paths, personal names or organizations in the added lines of docs or workflows.
What ran:
- Setup: a shared clone at c23ad39, Python 3.12.11,
ulimit -v 4000000,timeoutand< /dev/nullon every run. - Baseline:
tests/run.sh436 passed;tests/changed_checks_test.py49 OK (23 throughVendoredChangedCheckTests). - Mutants: 16, each applied with an exact-once substitution and reset after. Target:
changed_checks_test,ci_evidence_test, or the fullrun.shfor the copy and inputs mutants. - Probes: CI selection on a fixture origin with a GitHub-style merge commit; base and shallow cases;
jpdev versionin a checkout, an unpacked kit, a PATH without git and withGIT_DIRset; the release.yml copy gate. - Cleanup: every probe and scratch copy was deleted afterwards. The review checkout has no changes.
merge: yes (no HIGH). Disposition per the kit policy: the MEDIUM and the cheap LOWs are fixed in this PR in one round by the builder and confirmed by this reviewer.
…by jpdev version, evidence inputs pinned - tests/changed_checks_test.py: a shallow clone whose branch tips share no commit is refused with exit 2 and "no merge base of origin/main and HEAD", through both runners, with a working tree change that a fallback would have selected; an empty base branch name (`origin/`) is refused as an unresolved BASE. - bin/jpdev: kit_version runs git on the kit with GIT_DIR, GIT_WORK_TREE and the other repository-locating variables unset; tests/run.sh sets GIT_DIR to another repository. - tests/run.sh: .github/ci-evidence.json inputs hold scripts/dev/check.sh and scripts/dev/changed_checks.py. - ci.yml: the lint job runs `--all --skip tests` on a push too, the same selection as on a pull request (the same seven steps today; a new step then fails capture until the evidence lists it). - docs/adopting.md: a pull-request job fails when the base cannot be resolved; a push to the default branch runs the whole list. Signed-off-by: kikashy <35789537+kikashy@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Confirmation: 993b75aAll five findings are fixed: one commit on top of c23ad39, 5 files, +55/−5. Read from the diff, and re-run in a scratch copy of 993b75a. No new finding and no new HIGH.
What ran:
merge: yes (993b75a) |
|
🎉 Thank you for your contribution to Judgment Pack! If you’d like another task, choose a path that interests you: |
Summary
Closes #43: the follow-ups of
jpdev check --changed(#40). One pull request, four decisions.What changes
check.sh --changed [BASE].scripts/dev/check.shandtemplates/check.sh(byte-identical, as before) take--changed [BASE]with the kit's rules: the whole list when a path is unmapped, whenjpdev.json, the manifest or the runner changed, when nothing changed, or with no mapping. Decision: import, not embed. The runner callsscripts/dev/changed_checks.py, which islib/changed_checks.pywith the release on line 2. That is the same vendoring the handover script uses. The selection code exists once. A test holds the copy to the library line for line, and the release workflow refuses a copy that drifted. The template run from the kit falls back tolib/changed_checks.py.check.sh --changedrefuses with a named message when the copy is absent, when it is given with--onlyor--setup, and when the selection code refuses (no output, exit 2). The vendored selection code is a selection input, so a change to it runs the whole list (both runners).changed_checks.py --labelnames the runner in the report and in a refusal.tests/changed_checks_test.pyruns a second time through the clone's vendored runner (VendoredChangedCheckTests). One added test compares the two runners' selection blocks on the same changes, which is the input test the kit has for its own runner. Others cover the template in the kit, the missing copy,--setup, and a change to the vendored selection code.check.sh --changed origin/<base branch>; a push to the default branch and a dispatch run the whole list. This is the policy's split (docs/policy.md, "Scoped runs"). CI owns the deterministic checks, the scoped run is allowed on pull requests, and the full list is required on the default branch and before a release. A repository with nochangedmapping still runs the whole list on every pull request. The change applies totemplates/ci-check.ymland to the kit's ownci.yml. In the kit's own CI each job keeps its steps: on a pull requestlintruns--changed … --skip testsandtestsruns--changed … --skip <the lint steps>. Main and dispatch runs are unchanged (--onlyper job). Checkouts usefetch-depth: 0so that the merge base is found. The base ref is passed throughenv, never inlined into the script. The release evidence is unchanged:.github/ci-evidence.jsonstill namespushandworkflow_dispatchonly, and the same per-job check lists. Pull-request runs record no evidence.scripts/dev/changed_checks.pyis added to the evidence inputs, as part of the runner. The choice is written up indocs/adopting.md§4,docs/ci-evidence.mdanddocs/policy.md.jpdev codex run --smallnow says to runjpdev check --changedand not to choose the steps, instead ofjpdev check --only <steps>. The test asserts the new line and that--onlyis absent.jpdev --versionkeeps printingjpdev X.Y.Zalone, because the release gate compares it exactly. The newjpdev versionadds the kit checkout'sgit describe(for examplejpdev 0.7.0 (v0.7.0-4-g1f02688)), which tells a kit at a release from one past it. It adds nothing for an unpacked tarball or for a kit that only sits inside another repository's clone. An unknownjpdev checkoption and a refused--changedselection name that version. An unknowncheck.shoption names the runner's line-2 release. A kit installed before this change cannot be changed after the fact. From this change on, a newer option fails on an older kit with the kit's version in the message.Public surface
scripts/dev/check.sh --changed [BASE], plus a new vendored filescripts/dev/changed_checks.py(docs/adopting.md§2, README).jpdev version;jpdev --versionis unchanged.jpdev checkandcheck.sh, and an added line on a refused--changed.scripts/dev/changed_checks.py.templates/ci-check.ymlruns--changedon pull requests.docs/releasing.md,release.yml) sets and checks line 2 of the new vendored file.Checks
jpdev check --changed --allon this head (installed kit,jpdev 0.7.0):tests/changed_checks_test.py: 49 tests OK, 23 of them the vendored-runner pass.Each new safeguard was broken once in a scratch copy, and its test failed at the intended assertion:
scripts/dev/changed_checks.pyfrom the selection inputs fails the selection-code test in both classes.check.shfails 7 vendored tests.ChangedCheckTests.test_failures_name_the_kit_version.kit_versionmadejpdev versionprint the outer repository's commit, which the run.sh case refuses.A note for whoever runs
tests/run.shlocally:tests/clean_test.py(already on main, not touched here) callsgit mktreewith stdin inherited. Under a harness whose stdin is an open socket it waits forever. Running with< /dev/nullpasses. That is a separate issue.Fix round
At 993b75a, in response to the review:
test_a_shallow_clone_without_the_merge_base_is_refusednow runs through both runners. The fixture is a--depth 1 --no-single-branchclone whose branch tips share no commit, plus a working-tree change. With and without BASE, the run must refuse with exit 2 and "no merge base of origin/main and HEAD (a shallow clone needs the history)", with no report and no check run.test_an_unresolved_base_is_refusednow also covers an empty base branch name (origin/). Mutant: falling back to HEAD in both copies ofresolve_basefails 4 subtests (2 per runner); restored, 51 OK.tests/run.shchecks that.github/ci-evidence.jsoninputs holdscripts/dev/check.shandscripts/dev/changed_checks.py.--all --skip testson a push as well. That is the same selection as on a pull request and the same seven steps today. A step added to dev.json later fails evidence capture until the evidence file lists it.docs/adopting.md§4 now says a pull-request job fails when the base cannot be resolved, and that a push to the default branch runs the whole list.kit_versionruns git on the kit withGIT_DIR,GIT_WORK_TREEand the other repository-locating variables unset.tests/run.shcovers it for a kit checkout and for a kit inside another clone. Mutant: plaingit -Cprinted the other repository's commit for the kit checkout, which the new case refuses.jpdev check --changed --allat 993b75a: whole list (selection inputscripts/dev/check.shchanged),== 8 passed, 0 failed, 0 skipped, 0 not run ==, tests439 passed, 0 failed.Sign-off
Every commit carries a Developer Certificate of Origin sign-off that matches its author.
🤖 Generated with Claude Code