SCANNER_PROBE_RE gap: vendor appliance path /access/api/v1/system/ping pages on mars and pluto, 3 hits from 3 IPs
A repeat benign 404 is a filter gap, never a close (Elazar 2026-09-22), and this one has now recurred on two apps from three different hosts, so it will keep arriving. MEASURED. Path /access/api/v1/system/ping, unauthenticated, no referrer, classifiedReason=genuine-bad-route, tiered as a real miss and paged in real time. pluto: 2 rows, 2026-09-29 23:34:14Z and 2026-10-02 19:46:46Z, 2 distinct IPs. mars: 1 row, 2026-10-01 21:56:54Z. terra and enamel: zero (checked in the shared project on coalesce(route,path)). venus NOT checked - no DSN in this lane. Three IPs, 20.255.193.239 (Azure), 3.112.204.177 (AWS Tokyo) and the 09-29 one, all with the same desktop Chrome UA family. It is the health endpoint of a SonicWall-style remote-access appliance, so it is generator-specific and cannot plausibly be a route in any Evolutiva app. ASKED CHANGE: one EXACT-path alt, same shape as Block X's canary, /^\/access\/api\/v1\/system\/ping(?:$|[?#])/. DO NOT BROADEN IT to /access/ or /access/api/. terra and enamel both have real access-issue surfaces, and a prefix alt would silence a genuine dead internal link or a real resource miss on them. Pin /access and /access/api/v1/system/pingx as real-miss boundaries in the tests, the way the plural and the generic /x-404-probe are pinned for the canary. PROPAGATION IS THE DOCUMENTED FIXED ORDER, because venus's pre-push hook refuses otherwise: (1) mars not-found-classify.ts + test; (2) pluto not-found-classify.ts + scanner-probe-vectors.ts, push pluto; (3) venus scanner-probe-re.ts SHARED + regenerate fixtures/scanner-probe-vectors.json from the pluto checkout, update the corpus count, push venus; (4) terra and enamel not-found-tier.ts, kept cmp-identical, each test walking the route templates. Scanner tier, not the benign carve-out: the benign path is silent while a scanner probe still leaves a [scanner-404] runtime line, and a caller nobody has identified should stay countable. Verification is behaviour, not version: after each deploy the app's appEvents count for that route must stop moving. Do not verify by curling the path - that writes the row you are trying to count.
Sub-tickets — 0/1 done
Activity
-
venus answered and the fleet census is now complete and controlled. coder-venus-cc: ZERO rows for the path over the full retention window 2026-05-13..2026-10-02, so no retention wall cuts the 09-29..10-02 hits. They supplied controls so the zero is not an uncontrolled one - route LIKE '/%' = 3845 rows, '%wp-%' = 57, ilike '%ping%' = 0 - and disposed of the single '%/access%' match as a 2026-06-24 traversal probe for apache2/access.log. Fleet total stands at 3 hits on 2 apps from 3 IPs: pluto 2, mars 1, terra 0, enamel 0, venus 0. Alt verified independently against venus before any push: current SHARED+PULL sets both return false on the path (genuine miss, zero matching alts), the alt matches the exact path and the ?/# forms and refuses /access, /access/api/v1/system/pingx and the trailing-slash form, and the venus adopt-gate passed with 0 collisions across 69 route/page templates + 15 public assets = 84 paths, positive control firing. They also found a better argument than mine against broadening: venus's own manifest carries /admin/access-requests[/[id]], so the prefix form would collide on venus too, not only on terra and enamel. SEQUENCING FACT I DID NOT HAVE, and it changes the plan from 'fixed order' to 'steps 2 and 3 adjacent': venus's drift test re-syncs its vendored fixture from ../pluto/src/lib/scanner-probe-vectors.ts and asserts upstream.length === vectors.length === 101. The moment pluto pushes vector 102, EVERY venus push fails until venus re-vendors and bumps the count. So pluto's push does not merely precede venus's - it BREAKS venus's push lane until venus lands, and venus must therefore go in one pass (alt + re-vendored fixture + 102) in the same turn. coder-venus-cc declined to land early for exactly that reason, plus refusing to ship a pattern nothing asserts while the positive vector lives in pluto's corpus. Correct refusal, recorded, not argued; patch held locally, tree clean, lock taken and released. Open: step 1 needs coder-mars-cc to name the file carrying the set on mars (mars has no scanner-probe-re.ts; my knowledge says src/lib/not-found-classify.ts, theirs to confirm). Step 2 undone, pluto corpus still 101 with no ping vector. I ping coder-venus-cc the moment pluto's vector is on origin, and terra+enamel after venus lands.
-
coder-mars-ca / coder
-
Mars exact-path scanner matcher and boundary tests shipped at ce39a02 (v2.85.4); 944 tests passed. Pluto classifier/vectors are being edited by its owner in the shared worktree; Venus matcher/fixture push delegated to its authorized coder lane after Pluto lands. Awaiting deployed behavior verification without probing the scanner route.
-
pluto pushed 315ed3d, and the landed pattern has a one-character defect that would have propagated to three more apps. As landed: /^\/access\/api\/v1\/system\/ping(?:$|[?#])$/ - there is a trailing $ AFTER the group, which makes the [?#] branch unreachable, because that branch then requires the string to end immediately after the ? or #. Tested in node against the landed form and the specified one: bare path true/true, '?' true/true, but '?x=1' FALSE/true and '#f' FALSE/true. So any probe carrying a query string still pages, which is precisely the case the branch was written for. The two negatives (pingx, bare /access) are unaffected and stay correct. Spec was no trailing $, same as Block X's canary. Corpus is 104, not the 102 venus was expecting: pluto added 1 positive plus 2 negatives. coder-venus-cc's assertion bump is 104, and their push lane is blocked until they re-vendor - which is the coupling recorded above, now live. Asked pluto for the one-character fix plus a third positive vector 'ping?x=1' so the suite asserts the branch instead of only the bare path, and told venus to wait for the second pluto push before vendoring so they do not re-vendor twice. Both in one DM. Lesson for this row: I specified the regex in prose and checked the two NEGATIVE boundaries by hand, but never tested the positive variants of my own spec against what landed. A pattern is not verified until every alternation branch has a vector.
-
Pluto owner pushed exact-path classifier + 3 corpus vectors at 315ed3d (104 total); live /api/health reports v2.23.110, matching remote main. Venus authorized coder lane is syncing shared matcher and vendored fixture. Mars live v2.85.4 matches remote main. No scanner-path probe was issued.
-
RETRACTED: there is no regex defect. I read pluto's source at 315ed3d - not-found-classify.ts:376 is /^\/access\/api\/v1\/system\/ping(?:$|[?#])/ with no trailing $, exactly as specified, and the corpus carries the positive plus the pingx and bare-/access negatives. What I actually tested was the literal AS QUOTED IN THE RESULT DM, which carried an extra $ the committed code does not have. The node test was correct about that string and worthless as a statement about the repo. I then reported it as a landed defect, told pluto to push a fix and told venus to hold off vendoring - all from a quoted pattern instead of the file, which is the one thing the no-mechanism-advice-on-code-you-have-not-read rule exists to stop. The pluto checkout was sitting in this same working tree the whole time; reading it cost one command, which is what I did the moment I was challenged instead of before I sent. Withdrawn with it: the 'wait for a second pluto push' instruction to venus, now corrected to vendor at 104 immediately, and the ping?x=1 vector request, which is unnecessary since the branch is reachable. Both carried in one DM to coder-venus-cc and coder-pluto-cc. Cost: one wrong instruction to a lane whose push gate was already blocked, which is the expensive direction - venus held for four minutes on my word. coder-pluto-cc caught it by reading their own source and quoting the line, which is the correct answer to a claim like mine. Standing lesson, sharper than the one I wrote above: a regex pasted into a message is not the regex in the repo. Verify a pattern against the FILE, and quote the file:line when reporting on it.
-
Mars: src/lib/not-found-classify.ts and focused boundary tests pushed as fa08577/ce39a02; 944/944 pre-push tests passed; live /api/health v2.85.4 matches remote package.json. Pluto: 315ed3d pushed, live /api/health v2.23.110 matches remote package.json. Neither scanner path was curled. Post-deploy appEvents flatness remains observational and cannot be concluded before a subsequent scanner hit.
-
Steps 1-3 pushed in order: Mars fa08577+ce39a02 v2.85.4 (944 tests), Pluto 315ed3d v2.23.110 (104 vectors), Venus 9b6ec29 v1.17.29 (shared matcher, regenerated fixture, 27 focused tests). All live health versions match remote main. Support-evolutiva-cc was notified on original thread to route terra/enamel step 4 and monitor appEvents counts. No scanner-path curl. My Supabase MCP count query returned authentication required, so route count flatness remains unverified from this seat.
-
Steps 1-3 on origin: mars fa08577+ce39a02 (v2.85.4, 944 tests), pluto 315ed3d (v2.23.110, 104-vector corpus), venus 9b6ec29 (v1.17.29, shared alt + re-vendored fixture + 27 focused tests). All three /api/health versions match remote main per coder-mars-ca. Nobody curled the route, which is correct - the verification is count flatness, and a probe writes the row being counted. Step 4 triggered to coder-terra-cc and coder-enamel-cc, carrying the literal read out of pluto's FILE (not-found-classify.ts:376) rather than any message text, with the trailing-$ trap named explicitly so my own retracted error does not get re-introduced at the copy step. Also told them their own data gives them no positive control: terra and enamel are at zero rows for this path over the shared project's history, so the only evidence is pluto x2 plus mars x1, and their suites have to carry the assertion instead. Verification I own: terra, enamel, mars and pluto route counts for /access/api/v1/system/ping must stay flat after their deploys. The honest statement of what that proves is narrow - the probe arrived 3 times in 4 days from 3 IPs, so a flat count over days is consistent with both a working filter and a scanner that moved on. The suites are what prove the pattern matches; the counts only prove nothing new is paging. I will not curl any app to manufacture a positive. coder-mars-ca could not check count flatness themselves (Supabase MCP auth failure) and said so rather than asserting it - noted, and it is mine anyway since I hold the read roles.
-
Deploy state, measured rather than inferred. /api/health across the fleet at 20:00:07Z: mars 2.85.4 dpl_3NTJNeAtVPBQe7kbMVfYgCWuDYhH, pluto 2.23.110 dpl_GJU9DFAJSnft5hiL5L9SCcU9z6TR (same id on both evolutiva.pensanta.com and pluto-evolutiva), venus 1.17.29 dpl_Fp7w7jxntCxnNZkAFaRfLMKbGqcZ, terra 0.31.86 ed6fc34, enamel 0.14.1. So steps 1-3 are rolled out and step 4 has not landed yet, which matches. venus needed care because its push was --only-scoped to 3 files and never bumped package.json, so 1.17.29 reads identical before and after and the VERSION ORACLE IS USELESS THERE - a matching version is compatible with the deploy never having happened. coder-venus-cc observed the deploymentId flip from dpl_GpMHfbsh3ceKJu12RvZt1fNn84PZ at 19:59:50Z and I read the new id independently at 20:00:07Z; two observations, one conclusion, and that is the whole of the evidence. coder-mars-ca withdrew their 'all versions match remote main' proof themselves for the same reason, then re-confirmed on the id - correct both times. WHAT NOBODY HAS PROVEN: that dpl_Fp7w... carries 9b6ec29. githubCommitSha is not among venus /api/health's fields, coder-venus-cc's Vercel MCP returns 0 rows unfiltered, and MY Vercel read 404s on both the deployment id and the hostname - not_found rather than forbidden, so this agent's token is simply out of scope for that project. The timing fits and nothing confirms it. Proposed to coder-venus-cc the behavioural oracle instead, which is strictly better than provenance here: ONE disclosed GET of the path followed by their appEvents read. A live filter writes no row at all, only a [scanner-404] runtime line, and venus's pre-state is a hard zero over 2026-05-13..2026-10-02, so a row means not-live and silence means live - and in the passing case it cannot pollute the count. That knowingly contradicts the 'never curl' instruction I gave four times today: that rule is about not manufacturing flatness on a rail where my own probes have been mistaken for users, and a single disclosed probe against a hard-zero baseline is the opposite situation. Theirs to run; I hold no venus DSN.
-
Step 4 LIVE on terra (1ff7758, sha+dpl oracle, TERRA-264 closed) and pushed on enamel (4a759f1, cmp-identical). Step 3 venus must re-vendor at 106, not 104, after pluto 3484a6d. Step 5 opened as MARS-791 p3 (coder-mars-cc): the (?:$|[?#]) alternation is unreachable through every public API because all five apps strip the tail before matching, so the three pinned tail positives are green lines and the corpus cannot carry tail cover - pluto's own harness runs vectors through tierForNotFound(), which strips. venus already exports the pattern set and asserts the RE directly, which is why its mutation run was the only one that went red; scope is the other four repos. Post-deploy check for this filter keys on detail->>'subkind'='scanner' and the message prefix, NEVER on row absence (venus not-found-capture.ts:104-120 writes an info/security row on a match). Terra states its own coverage limit: zero historical rows for this path there, so absence is not evidence either way; only pluto and mars have a population that can show suppression.
-
audit pass: Mars ce39a02 deep/2c source and focused classifier tests
payload
{"scope":"Mars ce39a02 deep/2c source and focused classifier tests","outcome":"pass","evidence":"audit-general-ca PASS:ce39a02 including fa08577; anchored scanner path and boundary, 279/279 focused tests. Integration and live scanner route not exercised; no HTTP probe.","reportRef":null} -
Mars classifier ce39a02 and sibling propagation are shipped/source-audited. Required live check is a naturally recurring /access/api/v1/system/ping request after deployment followed by appEvents count staying flat; deliberately curling it would contaminate the count. No such post-deploy recurrence is recorded on this row, and this coder seat has no Mars DB read credential. Await natural recurrence plus support-evolutiva-cc read-only count; MARS-791 owns the separate raw-query alternation coverage.
-
ACCEPTANCE REWRITTEN - the previous one could only ever report silence, which is the finding here rather than the recurrence answer. OLD ACCEPTANCE, WITHDRAWN: "post-deploy check keys on detail->>'subkind'='scanner' plus the message prefix, NEVER row absence". Pluto never populates that key. Measured 2026-10-06 on PLUTO_RO: 356 action='page_not_found' rows in 14 days, ZERO carrying any detail->>'subkind', zero with 'scanner' anywhere in message or in detail::text. A check waiting on that field is unsatisfiable by construction - it cannot distinguish suppression-working from nothing-ran, and it would have sat green forever. NEW ACCEPTANCE: the observable for a suppressed scanner-shaped 404 on pluto is category='malicious' at level=info. Mechanism, read in source not inferred: not-found-log.ts:168-173 (PLUTO-182) persists scanner-shaped paths with no same-origin referer into the malicious security bucket at level=info, deliberately BELOW the applog daemon's warn threshold and inside the >=365d security retention class. So a suppressed probe is a malicious/info row, NOT an absent row and NOT a subkind field. WINDOW, both halves. Fix live from 2026-10-02 ~20:00Z; classifier commit 315ed3d at 19:55:12Z (version 2.23.111), corpus commit 3484a6d at 20:02:26Z. Read taken 2026-10-06 14:55Z. Window 3d19h. (a) NO NATURAL RECURRENCE of the ping pattern. /access/api/v1/system/ping has exactly TWO rows all-time on pluto, both category=navigation level=warn on appVersion 2.23.109: 2026-09-29 23:34:14.103Z and 2026-10-02 19:46:46.126Z. The second is 8m26s BEFORE the classifier commit and before its deploy, so BOTH are pre-fix. Zero rows since. (b) THE MALICIOUS RAIL IS ALIVE, so (a) is absence of traffic and not a dead rail. 97 malicious/info rows in 14 days, and since the fix the bucket has recorded /wp-json (2026-10-06 10:12:19Z), /.env (2026-10-04 23:33:54Z) and /api/session/properties x2 (latest 2026-10-03 21:42:15Z). The rail is receiving and classifying scanner traffic post-fix; the ping probe simply has not come back. SO SUPPRESSION FOR THIS PATTERN IS UNEXERCISED. The fix is not proven by observation and the row says so. No traffic was manufactured to exercise it. NOT READ, by instrument rather than by choice: mars and venus. This lane holds PLUTO_RO and ENAMEL_RO only. The mars env on this host is db-mars-ca's named role and will not be reused - named roles exist for attribution. The mars-side half of this same read is assigned to db-mars-ca; if mars's own check also keys on a field mars does not populate, it is the same defect and takes the same rewrite. ENAMEL/TERRA MEASURED, not carried: zero rows all-time for route ilike '%system/ping%' across both appKeys on the shared cluster, so neither app can witness suppression regardless of traffic.
-
Awaiting a NATURAL recurrence of /access/api/v1/system/ping, which has not happened in 3d19h since the fix went live (2026-10-02 ~20:00Z; classifier 315ed3d 19:55:12Z). The support read this blocker waited on is DONE and recorded: both all-time pluto rows are pre-fix, the second 8m26s before the commit; enamel/terra hold zero rows all-time. TWO INSTRUMENT CORRECTIONS, both measured, replace the test this blocker names. (1) 'appEvents count staying flat' is row-ABSENCE, which this row's own acceptance forbids, and it cannot separate suppression-working from no-traffic. (2) detail->>'subkind'='scanner' is never populated on pluto (356 page_not_found rows/14d, zero with any subkind), so the old check was unsatisfiable. On recurrence the expected signal is POSITIVE, not flat: a category='malicious' level=info row at that route (not-found-log.ts:168-173, PLUTO-182), with a navigation/warn row being the regression. The malicious rail is alive post-fix - 97 rows/14d, /wp-json 10-06 10:12Z, /.env 10-04, /api/session/properties x2 - so the current zero is absence of probe traffic. Still do NOT curl it: a deliberate probe writes the very row the check reads. Mars half assigned to db-mars-ca; this lane holds no mars credential and will not reuse db-mars-ca's named role.
-
Mars-side read by db-mars-ca at 2026-10-06 14:55Z via Mars project read role agent_db_mars_ca (current_database=postgres; appEvents has no appKey column, project scope is the Mars DB). Window from 2026-10-02 20:00Z to read time: zero exact-route appEvents rows; all-time exact-route count=1, 2026-10-01 21:56:54.942368Z, pre-fix. Across that one historical row: subkind='scanner'=0; category='malicious' AND level='info'=0; actual group is category=navigation, level=warn, action=404, classifiedReason=genuine-bad-route, subkind NULL. SQL: SELECT current_database(),current_user,EXISTS(SELECT 1 FROM pg_attribute a JOIN pg_class c ON c.oid=a.attrelid JOIN pg_namespace n ON n.oid=c.relnamespace WHERE n.nspname='public' AND c.relname='appEvents' AND a.attname='appKey' AND a.attnum>0 AND NOT a.attisdropped); WITH route_events AS (SELECT createdAt,category,level,action,detail,COALESCE(route,detail->>'requestedPath') AS event_path FROM public.appEvents WHERE route='/access/api/v1/system/ping' OR detail->>'requestedPath'='/access/api/v1/system/ping') SELECT count(*),count(*) FILTER(WHERE createdAt>=timestamptz '2026-10-02 20:00:00+00'),count(*) FILTER(WHERE detail->>'subkind'='scanner'),count(*) FILTER(WHERE createdAt>=timestamptz '2026-10-02 20:00:00+00' AND detail->>'subkind'='scanner'),count(*) FILTER(WHERE category='malicious' AND level='info'),count(*) FILTER(WHERE createdAt>=timestamptz '2026-10-02 20:00:00+00' AND category='malicious' AND level='info'),count(*) FILTER(WHERE category='security' AND level='info'),min(createdAt),max(createdAt) FROM route_events. Source confirms the correct Mars observable is different: src/lib/not-found-log.ts:215-220 emits console.warn('[scanner-404] ...') then returns before logEvent; 222-225 map persisted categories only to security/navigation. not-found-classify.ts:481-490 marks scannerProbe as info/security, but that appEvent is intentionally not written. Therefore subkind and Pluto's malicious/info appEvents predicates are unsatisfiable for Mars. Correct Mars recurrence check: Vercel runtime stderr [scanner-404] path=/access/api/v1/system/ping; current no-traffic window does not exercise suppression. Do not curl the route.
-
Mars-side read complete: the appEvents subkind='scanner' and category='malicious' level=info predicates are unsatisfiable here. Scanner probes set scannerProbe=true, emit a [scanner-404] console.warn, then return before logEvent; persisted categories are only security/navigation. After a natural recurrence, read Vercel runtime stderr for [scanner-404] path=/access/api/v1/system/ping. Do not curl. Zero appEvents rows since 2026-10-02 20:00Z is consistent with no observed traffic and does not exercise suppression. Historical exact-route count is one pre-fix row; no appKey column exists in this project database.
-
coder-mars-cc