n-seo 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -1
- package/ingest/http_util.py +6 -4
- package/package.json +1 -1
- package/probes/site_probe.py +10 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,27 @@ uses [Semantic Versioning](https://semver.org/).
|
|
|
8
8
|
|
|
9
9
|
Nothing yet.
|
|
10
10
|
|
|
11
|
+
## [0.7.1] - 2026-09-28
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
- **One HTTP/2 hiccup no longer fails the whole index-status step.** The
|
|
15
|
+
retry helper only retried the curl exits it knew about, and treated every
|
|
16
|
+
other one as a bad request. A dropped HTTP/2 connection (curl exit 16)
|
|
17
|
+
mid-run failed the first URL Inspection call it hit, which took the step
|
|
18
|
+
down, and the daily run's one step-level retry hit the same thing. Exits
|
|
19
|
+
16 and 92 (HTTP/2 connection and stream errors) and 55 (send failure) now
|
|
20
|
+
get the same per-request backoff as timeouts and resets.
|
|
21
|
+
- **A curl failure now says why.** Requests ran with `-s`, which silences
|
|
22
|
+
curl's own error line along with the progress meter, so the failure read
|
|
23
|
+
`curl exit 16: ` with nothing after it. They run with `-sS` now.
|
|
24
|
+
- **A slow first answer no longer reads as a regression.** The site probe
|
|
25
|
+
fetched each file once with a 15-second limit. A cold origin behind a CDN
|
|
26
|
+
can miss that on its first request of the morning, and the run then
|
|
27
|
+
alerted `robots.txt REGRESSED` for a site serving it fine. It happened
|
|
28
|
+
every few days to one site. The probe now tries once more, five seconds
|
|
29
|
+
later, when there is no answer or a 5xx. A site that is really down fails
|
|
30
|
+
both tries and is still reported.
|
|
31
|
+
|
|
11
32
|
## [0.7.0] - 2026-09-18
|
|
12
33
|
|
|
13
34
|
### Added
|
|
@@ -537,7 +558,9 @@ First public release.
|
|
|
537
558
|
`n-seo upgrade` gate — without changing the reported test counts, and an
|
|
538
559
|
in-place install ran those assertions against the owner's live data.
|
|
539
560
|
|
|
540
|
-
[Unreleased]: https://github.com/en-dash-consulting/n-seo/compare/v0.
|
|
561
|
+
[Unreleased]: https://github.com/en-dash-consulting/n-seo/compare/v0.7.1...HEAD
|
|
562
|
+
[0.7.1]: https://github.com/en-dash-consulting/n-seo/compare/v0.7.0...v0.7.1
|
|
563
|
+
[0.7.0]: https://github.com/en-dash-consulting/n-seo/compare/v0.6.1...v0.7.0
|
|
541
564
|
[0.6.1]: https://github.com/en-dash-consulting/n-seo/compare/v0.6.0...v0.6.1
|
|
542
565
|
[0.6.0]: https://github.com/en-dash-consulting/n-seo/compare/v0.5.0...v0.6.0
|
|
543
566
|
[0.5.0]: https://github.com/en-dash-consulting/n-seo/compare/v0.4.1...v0.5.0
|
package/ingest/http_util.py
CHANGED
|
@@ -14,9 +14,10 @@ import subprocess
|
|
|
14
14
|
import sys
|
|
15
15
|
import time
|
|
16
16
|
|
|
17
|
-
# curl exits worth another try: 6/7 resolve+connect,
|
|
18
|
-
# 35 TLS handshake, 52 empty reply,
|
|
19
|
-
|
|
17
|
+
# curl exits worth another try: 6/7 resolve+connect, 16 HTTP/2 framing,
|
|
18
|
+
# 28 timeout, 35 TLS handshake, 52 empty reply, 55 send error,
|
|
19
|
+
# 56 recv error, 92 HTTP/2 stream reset.
|
|
20
|
+
RETRYABLE_EXITS = {6, 7, 16, 28, 35, 52, 55, 56, 92}
|
|
20
21
|
TIMEOUT = 180
|
|
21
22
|
ATTEMPTS = 4
|
|
22
23
|
|
|
@@ -29,7 +30,8 @@ def curl_json(args, *, timeout=TIMEOUT, attempts=ATTEMPTS, label=""):
|
|
|
29
30
|
"""
|
|
30
31
|
last = None
|
|
31
32
|
for attempt in range(1, attempts + 1):
|
|
32
|
-
|
|
33
|
+
# -sS: no progress meter, but curl still says why it failed.
|
|
34
|
+
p = subprocess.run(["curl", "-sS", "--max-time", str(timeout), *args],
|
|
33
35
|
capture_output=True, text=True)
|
|
34
36
|
if p.returncode == 0:
|
|
35
37
|
try:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n-seo",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "Agentic, local-first SEO / AEO / GEO control plane: pulls Search Console + GA4, probes your sites, and ranks the next moves. Your LLM writes the proposals; your coding agent works the queue over MCP.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "En Dash Consulting (https://endash.us)",
|
package/probes/site_probe.py
CHANGED
|
@@ -13,6 +13,7 @@ Stdlib only — no pip installs needed.
|
|
|
13
13
|
import json
|
|
14
14
|
import re
|
|
15
15
|
import sys
|
|
16
|
+
import time
|
|
16
17
|
from datetime import datetime, timezone
|
|
17
18
|
from html.parser import HTMLParser
|
|
18
19
|
from pathlib import Path
|
|
@@ -33,7 +34,15 @@ UA = "Mozilla/5.0 (compatible; n-seo-probe/0.1)"
|
|
|
33
34
|
|
|
34
35
|
|
|
35
36
|
def fetch(url, timeout=15):
|
|
36
|
-
|
|
37
|
+
"""One retry when the site doesn't answer or answers 5xx. A cold origin
|
|
38
|
+
behind a CDN can take longer than the timeout on its first request of the
|
|
39
|
+
morning, and without the retry that read as robots.txt or sitemap.xml
|
|
40
|
+
REGRESSED. A site that is really down fails both tries."""
|
|
41
|
+
status, body = fetch_text(url, timeout=timeout, ua=UA)
|
|
42
|
+
if status is None or status >= 500:
|
|
43
|
+
time.sleep(5)
|
|
44
|
+
status, body = fetch_text(url, timeout=timeout, ua=UA)
|
|
45
|
+
return status, body
|
|
37
46
|
|
|
38
47
|
|
|
39
48
|
class MetaParser(HTMLParser):
|