Repository navigation
Conversation
All seven kit verify scripts ended with the same two-state verdict:
[ "$fail" -eq 0 ]
That answers "did anything fail?" and cannot answer "did we actually check
anything?". Two consequences, both measured:
1. A run where NOTHING executed reported success. With pass=0 and fail=0 the
test is true, so the script printed "All checks passed." and exited 0 having
verified nothing. Reproduced in isolation:
pass=0 fail=0 -> "All checks passed." exit 0
2. A skipped check was indistinguishable from a passing one. Across the seven
scripts there are 29 skip/NOTE sites and 9 warn sites that increment no
counter. Worst case: git-ssh-sign skips its end-to-end signed-commit check --
the kit's entire purpose -- whenever no key is in the forwarded SSH agent, and
still reported "All checks passed." openchamber and paseo DO define skip() and
warn(), but they are cosmetic printf with no counter, so a run can print 19
yellow SKIPs and still claim the offline gate passed.
This is the ninth instance of this defect class in this family of repos
(ENV-1, SEC-6, DX-7/8/9, SEC-12/13/17, DEP-4 are the prior ones), so the fix is
a shared contract rather than seven local patches.
WHAT THIS ADDS. integrations/isolation/acq-kits/verify-report.sh: five states and
a verdict that is a function of a coverage record, not of a failure counter.
ok ran and passed
bad ran and failed
unver COULD NOT RUN (missing tool, absent credential, no network) --
counted, and degrades the verdict
skip not applicable in this configuration -- counted, does NOT degrade
warn advisory; a documented fallback was taken -- does not degrade
exit 0 every check that ran passed, and at least one ran
exit 1 at least one check FAILED
exit 3 nothing failed but the run is not a pass: a check could not be
performed, or no check ran at all
3 is distinct from 1 so a caller can tell "we looked and found problems" from
"we could not look". The unver/skip split is the load-bearing part: collapsing
them is how a verify script claims coverage it does not have.
STAGED CONVERSION. Two kits here -- git-ssh-sign and usai-provider, the two
smallest -- so the contract is reviewable in isolation before the bulk edit.
Remaining: openchamber (641 lines, 3 gates), paseo (864, 3), pi-coding-agent
(337, 3), agentic-coding-playbook (167), zscaler-ca-certificate (167). They are
listed in the test's UNCONVERTED set, which must reach empty.
Converted sites:
git-ssh-sign - no host SSH key -> unver (was a bare echo NOTE)
- no forwarded key -> unver (was a bare echo SKIP; this is the
kit's only end-to-end assertion)
usai-provider - no USAi secret -> unver (was a bare echo NOTE)
- API probe empty -> unver. in_sbx() swallows the exit status, so
an empty result means EITHER "no curl in the guest" OR "sbx
exec failed" -- indistinguishable, and never a pass.
ENFORCEMENT. scripts/tests/test_verify_contract.py, 12 tests, because nothing in
CI runs these shell scripts: they need a live sandbox this repo's CI cannot
create, and the repo has no shellcheck hook, so 2,400 lines of shell are
currently linted by nothing. The tests read the scripts as text and assert the
library keeps BOTH degrading branches (a deleted branch silently restores the
two-state verdict for every caller at once), that converted kits source it and
do not shadow its reporters with no-op locals, that no bare `echo "SKIP"`
remains, and that UNCONVERTED describes reality in BOTH directions -- a kit
converted without being delisted fails, and so does a listed kit that reverted.
Every helper asserts its input set is non-empty first, so the suite cannot pass
vacuously over a glob that stopped matching.
A near-miss worth recording: the library was first written to acq-kits/lib/, and
.gitignore:13 carries the stock Python build-artifact block whose `lib/` rule
silently excluded it. Committing would have shipped two kits sourcing a file git
never tracked -- every verify run dying on "No such file or directory". Caught
because `git status` listed the two modified kits and the new test but not the
library. It now sits at the acq-kits root beside validate-kits.py, the existing
precedent for shared assets there, and the reason is recorded in the test file so
nobody re-adds a lib/.
Verified:
all five verdict states exercised directly:
nothing ran -> exit 3 clean -> exit 0 a failure -> exit 1
an unver -> exit 3 skip-only -> exit 0
pytest scripts/tests/ -> 413 passed (12 new)
degraded path of the TESTS: reverting usai-provider to origin/main
-> FAILS "does not source lib/verify-report.sh"
validate_repo.py --root . -> exit 0
validate-kits.py --root . --strict -> all kits OK
scan_unsafe_shell.py . -> 0 errors, 0 warnings
shellcheck -s sh verify-report.sh -> exit 0
shellcheck, converted kits -> git-ssh-sign 10 before / 10 after
usai-provider 7 before / 7 after
(pre-existing SC2015/SC2016 info
findings; I added none)
ruff check / ruff format --check -> clean
markdownlint -> 0 issues
git diff --check -> clean
NOT IN THIS PR, deliberately: general shell linting. These scripts have never
been shellcheck'd and adding a hook would surface unrelated findings across
2,400 lines; that belongs in its own change. This one closes the verdict-honesty
gap only.
AI assistance disclosed: prepared by an AI agent (OpenCode) on operator
instruction. Human review and merge still required.
…o converted CI caught a real defect in the contract test, from a direction I had not anticipated. Rebased onto main (1.10.0) and fixed. WHAT HAPPENED. `oci-engine` (#437) landed on main while this change was in review — an EIGHTH verify script that did not exist when I branched. The test derived its converted set by subtraction: {k: p for k, p in _verify_scripts().items() if k not in UNCONVERTED} so a kit in neither set was treated as CONVERTED by default. The four contract tests then failed against it with "oci-engine/scripts/verify does not source lib/verify-report.sh", which is true but misleading: the real problem was that a kit appeared that nobody had classified. I had guarded both directions I thought of — a kit converted but still listed, and a listed kit that reverted — and missed the one that actually happened. The default was the bug: an unclassified kit silently inherited a contract it does not implement, which is the same shape as the defect this whole change exists to fix (something unmeasured treated as passing). THE FIX. Two explicit sets, CONVERTED and UNCONVERTED, plus `test_every_kit_is_classified` asserting that every verify script appears in exactly one of them. A kit in neither is now a hard error naming the real cause, and the sets cannot name a kit that has no verify script. Proved it by simulating a ninth unclassified kit: AssertionError: verify script(s) in no classification set: ['zz-phantom']. Add each to CONVERTED (if it sources verify-report.sh) or to UNCONVERTED (if it is still on the old two-state verdict). A kit is never converted by default. CORRECTED COUNTS, recounted on the rebased tree rather than carried forward: there are EIGHT verify scripts, not seven, and 35 uncounted `skip`/NOTE sites, not 29 (9 `warn` sites unchanged). oci-engine itself has 303 lines, 2 gates, and 2 `[ "$fail" -eq 0 ]` verdicts, so it has the primary defect too; it is listed as UNCONVERTED for the staged bulk conversion. Stale numbers in the library header and the test docstring are updated. UNCONVERTED is now: agentic-coding-playbook, oci-engine, openchamber, paseo, pi-coding-agent, zscaler-ca-certificate. It must reach empty. Unrelated to the code, but it is why this took a second pass: the CI log could not be read at first because `gh run view --log` failed with `x509: certificate signed by unknown authority`. Root cause is Go-specific and documented in the review workspace, not here — Go's x509.SystemCertPool() omits macOS admin-installed roots (121 of the host's 177), so any Go tool fails against a proxy-intercepted host while `curl` to the same host verifies fine. Reading the log required pointing SSL_CERT_FILE at a bundle including the admin roots. No repo change needed; noted so the next person who sees that error does not mistake it for a CI outage. Verified on the rebased tree: pytest scripts/tests/ -> 420 passed (13 contract tests) unclassified-kit probe -> FAILS with the naming assertion validate_repo.py --root . -> exit 0 validate-kits.py --root . --strict -> all kits OK scan_unsafe_shell.py . -> 0 errors, 0 warnings shellcheck -s sh verify-report.sh -> exit 0 ruff check / ruff format --check -> clean AI assistance disclosed: prepared by an AI agent (OpenCode) on operator instruction. Human review and merge still required.
54563f0 to
49572de
Compare
|
CI is green now (7/7). Rebased onto main (1.10.0) and fixed a real defect the failure exposed — in my own test, not the library. What CI caught
{k: p for k, p in _verify_scripts().items() if k not in UNCONVERTED}So a kit in neither set was treated as converted by default, and four contract tests failed against it with "oci-engine/scripts/verify does not source lib/verify-report.sh" — true, but misleading. The real problem was that a kit appeared nobody had classified. I'd guarded both directions I thought of — a kit converted but still listed, and a listed kit that reverted — and missed the one that actually happened. The default was the bug: an unclassified kit silently inherited a contract it doesn't implement, which is the same shape as the defect this whole change exists to fix. The fixTwo explicit sets, Corrected countsRecounted on the rebased tree rather than carried forward from the original description:
Stale numbers in the library header and test docstring are updated. Verification on the rebased treeOne note, not a repo issueI initially couldn't read the CI log at all: Go's Reading the log required pointing AI-assisted (OpenCode), on operator instruction. Human review and merge required. |
mogul
left a comment
There was a problem hiding this comment.
Technically this is fine, but the level of bot-rumination in the comments distracts from understanding what it does, and memorializes context that won't matter going forward.
So I'm grudgingly requesting changes, even though that means another review round-trip... Sorry.
If you respond with improvements that only land in comments, then I approve your next push in advance, so feel free to check the box that skips the "require review" gate and merge it then!
| info() { printf '\n\033[1m%s\033[0m\n' "$1"; } | ||
| # Shared verdict contract (ok / bad / unver / skip / warn + verify_verdict). | ||
| # Sourced rather than redefined here so one fix cannot leave the other kits | ||
| # behind: the old local reporters had no "could not check" state, so a run that |
There was a problem hiding this comment.
The usual critique: Code comments should not memorialize bugs fixed, but rather describe the code as it is.
| it; `warn` is advisory. The `unver` / `skip` distinction is load-bearing — | ||
| collapsing the two is how a verify script ends up claiming coverage it does not | ||
| have. |
There was a problem hiding this comment.
The extra commentary in the final sentence here is distracting. The section is documenting what the exit code means, not why the verify script is designed the way it is.
| # "did we actually check anything?". Two consequences, both observed in the | ||
| # scripts this file replaces: | ||
| # | ||
| # 1. A run where NOTHING executed reports success. With pass=0 and fail=0 the | ||
| # line above is true, so the script prints "All checks passed." and exits 0 | ||
| # having verified nothing. | ||
| # 2. A skipped check is indistinguishable from a passing one. The scripts had | ||
| # 35 `skip`/NOTE sites and 9 `warn` sites that incremented no counter, so a | ||
| # run that skipped its single most important assertion — git-ssh-sign skips | ||
| # the end-to-end signed-commit check when no key is in the forwarded agent — | ||
| # still ended in "All checks passed." |
There was a problem hiding this comment.
Same complaint; describing "what was" is not relevant for the person or agent trying to read and understand the code. This is the kind of information that belongs in the commit, not in the code.
| # here" is a complete run of a smaller set. Collapsing the two is how a verify | ||
| # script ends up claiming coverage it does not have. |
There was a problem hiding this comment.
Same superfluous design note in the last sentence here. It reads as self-flagellation for previous sins ("what was") rather than documentation of "what is".
| # silently inherits a contract it does not implement. That is not hypothetical: | ||
| # `oci-engine` landed on main while this change was in review, and the original | ||
| # set-subtraction classified it as converted, failing four tests with a | ||
| # misleading "does not source lib/verify-report.sh" instead of the true cause | ||
| # ("a kit appeared that nobody classified"). |
There was a problem hiding this comment.
Irrelevant and distracting information that belongs in the commit, not the code.
| WHY THIS FILE EXISTS | ||
|
|
||
| Every kit's `scripts/verify` used to end with: | ||
|
|
||
| [ "$fail" -eq 0 ] | ||
|
|
||
| That is a two-state verdict. It answers "did anything fail?" and cannot answer | ||
| "did we actually check anything?", so two things were true of all eight scripts: | ||
|
|
||
| 1. A run where NOTHING executed reported success — with `pass=0` and `fail=0` the | ||
| test above is true, so the script printed "All checks passed." and exited 0. | ||
| 2. A skipped check was indistinguishable from a passing one. Across the eight | ||
| scripts there were 35 `skip`/NOTE sites and 9 `warn` sites that incremented | ||
| no counter, including `git-ssh-sign` skipping its end-to-end signed-commit | ||
| check — the kit's entire purpose — whenever no key was in the forwarded agent. | ||
|
|
||
| `integrations/isolation/acq-kits/verify-report.sh` replaces that with a | ||
| five-state contract whose verdict is a function of a coverage record. These tests | ||
| keep it that way. |
There was a problem hiding this comment.
The description of "what was", and what is no longer true, is not relevant, and an obstacle to understanding. This section should just focus on the positive "why" aspects:
This helps us distinguish "did anything fail" from "did we actually check anything?"
…im comment narration per mogul's review Two fixes, both from mogul's CHANGES_REQUESTED review: 1. Rebase onto main pulled in the opencode kit (#466), which landed with a verify script in neither CONVERTED nor UNCONVERTED, failing test_every_kit_is_classified exactly as the test is designed to catch (reproduced locally before fixing: `AssertionError: verify script(s) in no classification set: ['opencode']`). opencode's verify script is on the old two-state verdict, so it goes in UNCONVERTED alongside the other not-yet-migrated kits. 2. Trimmed six comment/docstring blocks that narrated the OLD two-state verdict's history ("used to end with...", "the old reporters had no...", the oci-engine near-miss anecdote) instead of describing the current code. Per review: this kind of narration belongs in the commit message, not in the code, where it has no reader value and persists as noise. Trimmed in: - integrations/isolation/acq-kits/git-ssh-sign/scripts/verify - integrations/isolation/acq-kits/usai-provider/scripts/verify - integrations/isolation/acq-kits/README.md - integrations/isolation/acq-kits/verify-report.sh (module header) - scripts/tests/test_verify_contract.py (module docstring + 2 inline comments + 1 docstring) Comment-only / allowlist-entry changes: no test logic, no shell logic, no shared-library behavior changed. Per the review's own standing offer ("if you respond with improvements that only land in comments... feel free to check the box that skips the require-review gate"), this should qualify to merge without a second review round-trip. Verification: - PYTHONPATH=scripts python3 -m pytest scripts/tests/: 420 passed (was failing 1/420 before the opencode classification fix, reproduced first). - python3 scripts/validate_repo.py: all validators pass. Co-authored-by: OpenCode Agent <agent@gsa.gov>
|
Addressed in `4f26eb4`. Two changes:
Flagging #2 explicitly because your standing offer was for comment-only fixes — this PR also has that one allowlist line, so I didn't want to assume it's covered and self-merge on a stretched reading. Your call whether that still qualifies or you'd rather take another look. CI is 7/7 green. `python3 scripts/validate_repo.py`: all validators pass. |
Replace text-presence assertions with a six-state executable matrix, require real library/verdict invocations, and trim the remaining investigation-history narration. Co-authored-by: OpenCode Agent <william.zujkowski@gsa.gov>
Require the exact shared reporter source, exercise both missing-tool degraded paths, and keep contract-test comments in present-tense invariant form. Co-authored-by: OpenCode Agent <william.zujkowski@gsa.gov>
Correct the copyable usage example and format the executable contract tests. Co-authored-by: OpenCode Agent <william.zujkowski@gsa.gov>
mogul
left a comment
There was a problem hiding this comment.
One approval-blocking documentation issue remains.
integrations/isolation/acq-kits/README.md:87 says “Verify scripts share one verdict contract,” then presents exit codes 0, 1, and 3 as the meaning of scripts/verify. But scripts/tests/test_verify_contract.py explicitly classifies only git-ssh-sign and usai-provider as CONVERTED; seven kits remain UNCONVERTED and retain the old two-state verdict. A caller can therefore rely on this documented contract for a listed kit and receive an incorrect result.
Please scope this section to converted kits and make the staged migration status clear, or defer the general exit-code documentation until every kit uses the shared reporter. The implementation and contract tests otherwise look sound.
The exit-code table described a contract only two kits implement, so a caller could trust a 0 from an unconverted kit whose 0 does not distinguish every-check-passed from a check that could not run. Document the staged split explicitly, state what an unconverted 0 does and does not establish, and derive both lists from the test suite so a README-only edit, a conversion, or a reversion each fail. Co-authored-by: OpenCode Agent <william.zujkowski@gsa.gov>
|
Addressed in What changed
On that last point I went looking for the concrete mechanism rather than asserting it generically. These scripts report an unmet precondition with a bare message that increments no counter, then exit The split is now enforced, not just describedProse that must track a migration will drift, so Three details worth flagging, because a guard like this is easy to write so that it passes vacuously:
The converted lookup still hard-fails on a missing section, since that one is not supposed to disappear. VerificationThe five No implementation or contract-test behavior changed — only the documentation scope plus the new guard. AI-assisted (OpenCode). Advisory; requires your review. |
All seven kit verify scripts ended with the same two-state verdict:
That answers "did anything fail?" and cannot answer "did we actually check anything?". Two consequences, both measured rather than inferred.
1. A run where nothing executed reported success
Reproduced in isolation:
2. A skipped check was indistinguishable from a passing one
Across the seven scripts there are 29 skip/NOTE sites and 9 warn sites that increment no counter.
Worst case:
git-ssh-signskips its end-to-end signed-commit check — the kit's entire purpose — whenever no key is in the forwarded SSH agent, and still reported "All checks passed."And
openchamber/paseodo defineskip()andwarn(), but they're cosmeticprintfwith no counter:So
paseocan print 19 yellow SKIPs and still claim the offline gate passed.This is the ninth instance of this defect class across this family of repos (ENV-1, SEC-6, DX-7/8/9, SEC-12/13/17, DEP-4 being the prior ones), which is why the fix is a shared contract rather than seven local patches.
The contract
integrations/isolation/acq-kits/verify-report.sh— five states, and a verdict that is a function of a coverage record rather than a failure counter:okbad1unver3skipwarn3is distinct from1so a caller can tell "we looked and found problems" from "we could not look." Theunver/skipsplit is the load-bearing part — collapsing them is how a verify script ends up claiming coverage it does not have.Staged on purpose: two kits here
The two smallest (
git-ssh-sign,usai-provider), so the contract is reviewable in isolation before a bulk edit. Remaining:openchamber(641 lines, 3 gates),paseo(864, 3),pi-coding-agent(337, 3),agentic-coding-playbook(167),zscaler-ca-certificate(167) — listed in the test'sUNCONVERTEDset, which must reach empty.Converted sites:
unver; no forwarded key →unver(the kit's only end-to-end assertion).unver; API probe empty →unver. That last one matters:in_sbx()swallows the exit status, so an empty result means either "no curl in the guest" or "sbx execfailed" — indistinguishable, and never a pass.Enforcement, because nothing in CI runs these scripts
They need a live sandbox CI cannot create, and this repo has no shellcheck hook — so 2,400 lines of shell are currently linted by nothing.
scripts/tests/test_verify_contract.py(12 tests) reads them as text and asserts:verify_reset, and don't shadow its reporters with no-op locals (which would pass every other test while behaving exactly as before);echo "SKIP"remains in a converted kit;UNCONVERTEDdescribes reality in both directions — a kit converted without being delisted fails, and so does a listed kit that reverted.Every helper asserts its input set is non-empty first, so the suite cannot pass vacuously over a glob that stopped matching. That would be the same defect wearing a different hat.
A near-miss worth recording
The library was first written to
acq-kits/lib/..gitignore:13carries the stock Python build-artifact block, whoselib/rule silently excluded it:Committing would have shipped two kits sourcing a file git never tracked — every verify run dying on "No such file or directory." Caught because
git statuslisted the two modified kits and the new test but not the library. It now sits at the acq-kits root besidevalidate-kits.py(the existing precedent for shared assets there), and the reason is recorded in the test file so nobody re-adds alib/.Verification
I exercised the degraded paths of both the library and the tests, because a guard that only passes when things are fine is indistinguishable from a guard that always passes.
Not in this PR, deliberately
General shell linting. These scripts have never been shellcheck'd, and adding a hook would surface unrelated findings across 2,400 lines — that belongs in its own change. This one closes the verdict-honesty gap only.
acq-kits/README.mdgains a short section documenting what each exit code means, since the exit contract is now something a caller can rely on.AI-assisted (OpenCode), prepared on operator instruction. Human review and merge required.