Skip to content

1.9.79: the adversarial findings on the re-click review round and the 1.9.78 findings round - #282

Merged
tracking202 merged 3 commits into
1.9.79from
claude/1.9.79-findings-3
Oct 28, 2026
Merged

tracking202 merged 3 commits into
1.9.79from
claude/1.9.79-findings-3

Conversation

@tracking202

@tracking202 tracking202 commented Oct 28, 2026 •

Copy link
Copy Markdown
Owner

The non-blocking findings of the adversarial reviews of #258 (4) and #262 (3), named by number. The reports stay encrypted. The review-gate change, #275, is still the last PR of 1.9.79.

What changes

#258

  • 1. The re-click backfill steps a click over only for errors of its own.
    • A lock wait or deadlock, a statement interrupted or timed out, a lost or refused connection, and a server that is full, out of memory or read-only are errors of the moment (ReClickBackfill::MOMENT_ERRNOS, plus every client error, 2000 to 2999).
    • An error of the moment stops the run at the click and is logged, as before. It counts in none of the ten, however long it lasts.
    • failed_runs now counts the runs that failed with the click's own error. The API doc, the OpenAPI spec, the upgrade guide and the progress note say so.
    • Before, ten failures over an hour of any kind stepped the click over for good: an hour of lock waits on its rows did it.
  • 2. SchemaVersion compares versions with version_compare(). Only a schema older than the code names the upgrade.
    • When the files are older than their database (rolled back), the API answers as it did without the change. The sync worker still refuses to run, and now says to deploy the newer files instead of sending the operator to upgrade.php.
    • A stored value that is not a version claims no cause.
  • 3. No change. _upgrade_query() answers false for a non-transient failure, so the comparison does match. If that CREATE fails, the 1.9.79 rung creates the same table through _upgrade_measurement_tables() and leaves the version at 1.9.78 when it cannot, so the failure stays loud and the upgrade is retried. The log line only names the cause at the 1.9.5 rung.
  • 4. No code change; three answers:
    • upgrade-equals-install, MySQL 8.0 and the agent evals ran on this PR, as on 1.9.79: the review findings of the re-click restore and the ledger lock #258, and are green (below).
    • p202 system dataengine renders the answer as it comes (render(data)), so the new fields print with no CLI change. That was read, not run.
    • The Android fixture is the contract the SDK suite reads; it was edited to match the server's answer, which UpgradePendingAnswerServedIntegrationTest serves.

#262

  • 1. Two click-path entries the code computes and keeps for 30 days are now keyed by its version too (LookupRepositoryFactory::cacheNamespace()): the user-agent parse and the bot-range verdict.
    • The rest stay on the bare install hash, each for a reason now listed in the new CacheKeyNamespaceTest:
      • The redirect fallback's URLs and the account's settings are Setup values no upgrade changes. Versioning the fallback would also empty it right after an upgrade, when an outage is likeliest.
      • The SQL-keyed reads live for minutes.
    • The window between deploying the files and running the upgrade is covered by the rule already written at the lookup cache: a step that changes what a lookup answers changes its key subjects.
  • 2. The landing script reads p202_consent as PHP's $_GET files it.
    • Before, p202.consent=0, p202 consent=0, p202[consent=0 and p202_consent[]=0 were a refusal to the tracker and consent to the script.
    • The value is trimmed of PHP's trim() characters only. A no-break space before the 1 is now a refusal in both.
    • A followed tracker link drops every spelling of the parameter before adding the refusal.
  • 3. The approval page is now checked as rendered: a browser scenario signs in, opens it with a well-formed link and reads its visible text. The source scan stays as the floor. The ISP switch's source test stays as it is: tests/live/autocron-switch.sh drives that handler over HTTP.

Found by Codex on this PR, fixed here

  • PHP cuts a parameter name at its first NUL before it reads brackets, so p202_consent%00x=0 was a refusal to the tracker and consent to the script (c74b387). The reader now cuts there first.
  • The version check refused 1.9.30a and 1.9.30b, which the ladder writes, so an install at either rung lost the 503 (85b9c51). One trailing letter is a version now.

Also

Testing

Run locally on PHP 8.3.6 and MariaDB 10.11, with a full vendor/.

Ladder (verify.sh --changed):

  openapi    PASS
  patterns   PASS
  phpcs      PASS
  phpstan    PASS
  schema     SKIP  set P202_TEST_DB_HOST and P202_TEST_DB_NAME to a SCRATCH database (this tier drops and recreates tables)
  syntax     PASS
  unit       PASS

tracking202/static/landing.php went from 391 phpcs errors to 376.

Integration. tests/run-integration-suites.sh on the first commit: 145 suites, 1,412 tests, all passed, each on its own fresh database. On their own, on the current head:

  • ReClickBackfillIntegrationTest 14/14. The new case runs a lock wait, a lost connection and a statement timeout (each raised with its errno from a trigger) for two hours of runs, and nothing is stepped over. Then the tenth error of the click's own steps it over.
  • SchemaVersionIntegrationTest 9/9, covering 1.9.78, 1.9.8 (older, though greater as text), 1.9.30a and 1.9.30b, current, 1.9.80, 1.9.100 (newer, though smaller as text), not a version, and none.
  • UpgradePendingAnswerServedIntegrationTest 9/9. A schema newer than the code now answers the plain 500 over HTTP.

The consent reader was held to PHP's parse_str() on 45 spellings: arrays, dots, spaces, unmatched brackets, repeats in both orders, no-break space, \v, NUL in a value and in a name, a different case and a longer name. All 45 agree, taken from the shipped file.

Browser passes, on a 1.9.79 instance served from this tree:

  • identity-landing 64/64, with thirteen refusal spellings, seven consent spellings and the followed-link scenario. One earlier run lost one scenario to a page load interrupted seconds after the server started; it did not recur.
  • The new account-pages scenario 5/5.
    • The full account-pages run failed 63 checks; none is this change's. Each page's "no JavaScript errors" check failed on Google's hosted ad loader, which this sandbox's network answers with an HTML redirect. Users' empty-list check failed because this instance kept a user from an earlier pass.
    • The licence check fails open when its host is unreachable: for these passes my.tracking202.com pointed at 127.0.0.1, with the server started without the proxy. Both were put back.

Every fix was planted against and fails by name:

  • every failure counting, and an error of the moment adding to the count (3 cases each);
  • the old any-difference rule, the newer schema sent to the upgrade, and a non-version compared;
  • the user-agent key on the bare hash (5 failures across the two device suites);
  • a new bare-hash key (the listing test);
  • the old landing reader (12 failures) and the old link decorator (2);
  • "verified" put back on the approval page.

On this PR, CI on 85b9c51 is green: integration on MySQL 8.0, upgrade-equals-install, agent-evals, test, lint, PHPStan and the rest.

🤖 Generated with Claude Code

https://claude.ai/code/session_01U3VVstdYdz5zwv5MUbkDjT

… 1.9.78 findings round

The non-blocking adversarial findings on #258 and
#262, by number:

#258
- 1: the re-click backfill steps a click over only for its own errors.
  A lock wait, deadlock, timeout, lost connection or a full or read-only
  server (ReClickBackfill::MOMENT_ERRNOS, and every client error) stops
  the run at the click and counts in none, however long it lasts.
- 2: SchemaVersion compares versions with version_compare(). Only a
  schema older than the code names the upgrade; files older than their
  database answer as before, and the sync worker says to deploy the
  newer files.

#262
- 1: the user-agent parse and the bot-range verdict, kept 30 days, are
  keyed by the code's version too. CacheKeyNamespaceTest lists every key
  on the bare install hash with why.
- 2: the landing script reads p202_consent as PHP's $_GET files it
  (p202.consent, p202_consent[] and the rest), with PHP's trim(), and a
  followed tracker link keeps no spelling of it but the refusal.
- 3: the approval page's words are checked as rendered, in the
  account-pages browser pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U3VVstdYdz5zwv5MUbkDjT
Copilot AI balanced review requested due to automatic review settings October 28, 2026 03:11
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-28T03:23:17.223721Z c74b387 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

@github-actions

Copy link
Copy Markdown
Contributor

Code review: CLEAN

For ee9391a: 0 issue(s). The review is encrypted for the maintainers in the review-findings artifact of this run.

@github-actions

github-actions Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Adversarial review: NON-BLOCKING

For 85b9c51: 6 finding(s). The report is encrypted for the maintainers in the review-findings artifact of this run.

Rewritten on every push; the check fails on BLOCKING.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ee9391a426

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tracking202/static/landing.php
…as PHP does

PHP's $_GET cuts a query name at its first NUL before it reads any
brackets, so p202_consent%00x=0 and p202_consent%00[]=0 are a refusal to
the tracker; the landing script kept the NUL and read them as absent,
which is consent (found by review). p202PhpName() now cuts there first.
Held to parse_str() on 45 spellings, nine of them with a NUL: the
reader before this differed on seven.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U3VVstdYdz5zwv5MUbkDjT

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c74b387ce3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread 202-config/Database/SchemaVersion.php
…e upgrade

The ladder writes 1.9.30b and accepts 1.9.30a, and the version check
taken in the previous round read only dotted numbers as a version, so
an install at either rung lost the upgrade's 503 in the deploy window
(found by review). One trailing letter is a version now;
version_compare() orders both before 1.9.30.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U3VVstdYdz5zwv5MUbkDjT
@tracking202
tracking202 merged commit 043d104 into 1.9.79 Oct 28, 2026
17 checks passed
@tracking202
tracking202 deleted the claude/1.9.79-findings-3 branch October 28, 2026 04:36
tracking202 pushed a commit that referenced this pull request Oct 28, 2026
…start IPN branch

GET /users/{id}/preferences now serves every integration secret as its
stored state (#270), and the PayKickstart IPN keys are one more:
paykickstart_ipn_secret_keys is on ServedPreferences::SECRET, answered
{"stored": true}, and the count this branch served in its place
(paykickstart_ipn_keys_stored, PayKickstartKeys::withoutKeys()) is gone.
GET /system/integrations keys_stored still says how many. The
PreferenceSecretsAreNotServedIntegrationTest round trip stores the keys
with the other secrets.

Conflicts: changelogs (1.9.79's lines, then this branch's), the
preferences docs and the OpenAPI schemas (1.9.79's, with the keys added
as a StoredSecret), and the controller (1.9.79's).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VRoS2SViuxaucFaKWsFnLr
tracking202 pushed a commit that referenced this pull request Oct 28, 2026
…JVZoo branch

#268 now dates a notification's row by the provider's own time, held to the
click for a sale and to the sale for a refund, and brings 1.9.79's #270
(ServedPreferences: GET preferences serves each secret as {"stored": ...}),
#280, #281 and #282.

Conflicts: both changelogs keep the base's lines with the JVZoo line after
them; the OpenAPI preferences update takes #270's oneOf shape, with the
JVZoo key's rule in its string branch; the eval cases keep #268's admin-005
notes and add admin-006 after it. jvzoo_ipn_secret_key is already on
ServedPreferences::SECRET, and JVZoo adds no other column.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VRoS2SViuxaucFaKWsFnLr
tracking202 pushed a commit that referenced this pull request Oct 28, 2026
…79's #270, #280, #281, #282) into the ClickBank branch

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VRoS2SViuxaucFaKWsFnLr

# Conflicts:
#	202-config/changelogs.json
#	changelogs.txt
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