Skip to content

fix(conformance): body-check every accepted trigger refusal - #299

Merged
scttbnsn merged 3 commits into
dev/v1.7from
fix/conformance-validate-trigger-refusal
Aug 20, 2026
Merged

fix(conformance): body-check every accepted trigger refusal#299
scttbnsn merged 3 commits into
dev/v1.7from
fix/conformance-validate-trigger-refusal

Conversation

@scttbnsn

Copy link
Copy Markdown
Contributor

CodeRabbit's review on the #298 promotion, taken and then corrected by a real run.

The finding

Assertion 8's 404|501 arm passed on the bare status. Express answers an unknown route with 404 Cannot POST /..., so a wrong trigger URL would have passed the assertion while testing nothing. That is the same failure this whole series is about: the store poll fed a 410 into jq, swallowed the error, and produced a result indistinguishable from a real failure. A probe that cannot tell "I am broken" from "the thing I watch is refused as designed" is not a probe.

501 also left the accepting arm. It was accepted unvalidated and no row has ever returned it — the run artifacts record 404 on legacy-floor (drydock 1.5.2) and 400 on both current-* rows (1.6.x). The 501 in the bundle README is Portwing's trigger endpoint, a different service from the drydock:3000 API this posts to. It now falls to the default arm, which prints the status and body, so a real 501 becomes a pinnable fact instead of a silent pass on a status nobody has observed.

The correction

My first cut asserted the literal "trigger not found", which the README has claimed since #211. Run 32323163685 failed legacy-floor and showed why:

{"error":"Remote update trigger portwing.docker.update not found"}

The documented wording was wrong, and it had never been checked because nothing ever read the body. The middle of that string is the agent-qualified trigger name, so it varies by row. The match is trigger .*not found, which still rejects a bare {"error":"Not Found"} and Express's Cannot POST body. README and CHANGELOG corrected.

The 404 PASS detail now records drydock's actual error string. The previous artifacts carried only the harness's own summary, which is exactly why a wrong assertion could be written against them.

Verification

Run 32323886778, all three rows plus the self-test green, and the artifacts now carry the evidence:

legacy-floor:     PASS -- refused as unconfigured
                  (404: Remote update trigger portwing.docker.update not found)
current-standard: PASS -- refused with no update available (400)
current-edge:     PASS -- refused with no update available (400)

Note on the third commit

build(deps): dedupe the nested magic-string in the lockfile is unrelated to the above and is not something I went looking for. The pre-push lockfile-dedupe gate blocked the push with genuine drift in fumadocs-mdx's nested magic-string (1.2.1 → 1.2.2), and unlike the false-positive class #296 just fixed, npm dedupe here produced a real three-line lockfile change. Kept as its own commit rather than folded in.

Worth recording: the install probe reported the tree as matching the lockfile while the dedupe probe reported drift. npm install --dry-run accepts a newer version that still satisfies the range; dedupe reports it. The two probes are not redundant.

CodeRabbit review on the #298 promotion. The 404 arm passed on the bare
status, so a wrong trigger URL -- Express answers those with 404 "Cannot
POST /..." -- would have passed assertion 8 while testing nothing. That's
the same shape as the bug this series exists to close: the store poll fed
a 410 into jq, swallowed the error, and produced a result indistinguishable
from a real failure. Both accepted refusals are now identified by their
response body: 404 "trigger not found", 400 "no update available".

501 leaves the accepting arm. It was accepted unvalidated and no row has
ever returned it: the 2026-08-20 run recorded 404 on legacy-floor (drydock
1.5.2) and 400 on both current-* rows (1.6.x). The 501 in the bundle README
is Portwing's own trigger endpoint, a different service from the
drydock:3000 API this posts to. It now falls to the default arm, which
prints the status and body, so a real 501 becomes a pinnable fact instead
of a silent pass on a status nobody has observed.
The first cut of the body check asserted the literal "trigger not found",
which the README has claimed since #211. Run 32323163685 shows that isn't
what drydock says. legacy-floor failed with:

  {"error":"Remote update trigger portwing.docker.update not found"}

The middle of that string is the agent-qualified trigger name, so it
varies by row. Match `trigger .*not found` instead, which still rejects a
bare {"error":"Not Found"} and Express's Cannot POST body from an
unrouted request. Correct the wording in the README and the changelog.

Also record drydock's actual error string in the 404 PASS detail. The
previous artifacts carried only the harness's own summary, so after the
fact there was no way to tell what drydock had actually answered -- which
is exactly why this wrong assertion could be written in the first place.
npm dedupe collapses fumadocs-mdx's nested magic-string from 1.2.1 to
1.2.2, which is what the workspaces already resolve. Three lines: version,
resolved URL, integrity hash. No package.json change and no behavioural
surface.

Surfaced by the pre-push lockfile-dedupe gate, which blocks a push while
the lockfile and a dedupe disagree, so this rides on the branch that hit
it rather than waiting for a PR of its own. Worth noting the install probe
reported the tree as matching the lockfile: npm install --dry-run accepts
a newer version that still satisfies the range, while dedupe reports it.
@vercel

vercel Bot commented Aug 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
sockguard-website Ready Ready Preview Aug 20, 2026 2:20am

@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@scttbnsn, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 32 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 9ac54cab-c04d-4fcb-bbed-22ea66aeddf8

📥 Commits

Reviewing files that changed from the base of the PR and between ac38443 and 7cfcf3f.

⛔ Files ignored due to path filters (2)
  • CHANGELOG.md is excluded by !CHANGELOG.md
  • package-lock.json is excluded by !**/package-lock.json, !**/package-lock.json
📒 Files selected for processing (2)
  • scripts/tri-tool-conformance/README.md
  • scripts/tri-tool-conformance/run-matrix.sh

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@biggest-littlest biggest-littlest left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Approved. All three conformance rows green on run 32323886778, and the artifacts now carry drydock's actual refusal string.

@ALARGECOMPANY ALARGECOMPANY left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Approved.

@scttbnsn
scttbnsn merged commit f9e9cc8 into dev/v1.7 Aug 20, 2026
63 of 64 checks passed
@scttbnsn
scttbnsn deleted the fix/conformance-validate-trigger-refusal branch August 20, 2026 02:26
scttbnsn added a commit that referenced this pull request Aug 20, 2026
…es to main (#298)

Promotion of dev/v1.7 into main.

#294 / #299 -- the tri-tool conformance harness stops swallowing its own errors
(closes #289). Assertion 8 polled drydock's unversioned /api/containers and
/api/triggers/docker/update, which 410 as of drydock v1.6.0. The 410 body fed
straight into jq, the type error went to 2>/dev/null, and what came back was an
empty result indistinguishable from a real store-sync failure -- which is how a
harness bug got reported as a drydock regression and sat for a month. Nothing
was ever wrong with drydock. Both URLs move to /api/v1; the poll checks the HTTP
status and the {data: [...]} envelope before trusting anything; and both
accepted trigger refusals are now identified by their response body rather than
a bare status, since a wrong URL also answers 404. 501 leaves the accepting arm:
no row has ever returned it.

#296 -- the lockfile-dedupe pre-push hook stops misnaming a stale node_modules
as lockfile drift (closes #295). It probes npm install --dry-run first and names
npm ci, and only then does the dedupe report get to mean anything. Logic moved
into scripts/lockfile-dedupe.mjs with tests.

Verified on conformance run 32323886778: all three rows and the harness
self-test green, with drydock's actual refusal strings recorded in the
artifacts.

Fixes: #289
Fixes: #295
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.

3 participants