Skip to content

Seeds: atomic canonical claims for the #1137 corpora, lint before any registration - #70

Merged
Tailor-AUS merged 3 commits into
rehome-reviewfrom
agent/open-graph-claims
Sep 21, 2026
Merged

Tailor-AUS merged 3 commits into
rehome-reviewfrom
agent/open-graph-claims

Conversation

@Tailor-AUS

@Tailor-AUS Tailor-AUS commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Refs TailorAU/tailor-group#7 (step 2, data half — the fix the first apply needed). Base rehome-review.

What happened

Under Knox's go, the three topic corpora were applied against pact.tailor.au after #68 deployed. All 30 topic creations were rejected with canonicalClaim must be at most 140 characters (got 155…277) — the #3691 W2 atomic-claim rule (src/lib/claim.ts), which these corpora predate. The GET-only dry-run could not see a POST-side validation, and 30 seed agents (plus 1 for the edge seed) had already been registered when the rule fired. Topics 12 → 12, edges 0 → 0, agents 1 → 32. The 11 legislation documents were byte-identical before and after (sections + SHA-256 of each record); qld/act-2016-025 is not present in this database at all (404 before and after).

What this does

  • Rewrites each of the 30 canonicalClaims to one atomic proposition ≤ 140 chars (longest 135). The longer text remains in content. Two claims drop their dotted rule numbers from the claim text — ASX LR 3.1 and DFARS 252.225-7052 — because the server splits sentences on .; the titles still carry the numbers. Please eyeball the 30 rewrites in the diff before the re-run.
  • _defence_seed_helpers.py gains lint_atomic_claim / lint_corpus, a Python mirror of lintAtomicClaim (length, single sentence, top-level and/or joining two verb-bearing clauses, hedges). seed_topic_batch lints the whole corpus first — in dry-run and in apply — and exits 2 before registering anyone.

Evidence

  • Lint: 0 failures across 12 + 10 + 8 claims; the old wording and a 141-char string both fail the mirror.
  • SEED_DRY_RUN=1 after the rewrite: 30 to create, 0 present; 25 edges pending those topics.
  • python -m py_compile clean on the four files.

Re-run note

The registration flood backstop is 60/hour per address; this seat spent 32 of those at ~05:05–05:15 UTC. The re-apply needs 31 more, so it runs after ~06:15 UTC or from a different egress.

🤖 Generated with Claude Code


Note

Low Risk
Changes are limited to offline Python seed scripts and README; they do not alter production API or app runtime, though operators must re-run seeds against live PACT with rate-limit awareness.

Overview
Fixes failed #1137 topic seeding where all 30 POST /api/pact/topics calls were rejected after agents had already been registered, because canonicalClaim violated the server’s atomic-claim rule (≤140 UTF-16 units, single sentence, no bundled conjunctions/hedges).

Data: Rewrites every canonicalClaim in the AU/US defence and critical-minerals corpora to one short atomic proposition; fuller text stays in content. Some claims drop dotted section numbers from the claim line because the server treats . as sentence boundaries.

Tooling: _defence_seed_helpers adds a Python mirror of lintAtomicClaim, runs lint_corpus before any agent registration (exit 2 on failure), resolves existing titles first and only registers agents for missing topics, and stops instead of round-robinning when registration returns fewer keys than needed (exit 3). Optional PACT_SEED_KEYS_FILE / PACT_SEED_AGENT_KEY persist and reuse keys so seed_topic_dependencies need not burn a 31st registration. create_topic distinguishes exact-title 409s from fuzzy near-duplicate 409s; pact_pow.register retries transient network errors.

Docs: README seed steps document dry-run, keys file, hourly registration budget, and default SOURCE_BASE (https://pact.tailor.au).

Reviewed by Cursor Bugbot for commit 5afacba. Bugbot is set up for automated code reviews on this repo. Configure here.

…de lint before any registration (refs TailorAU/tailor-group#7)

The first live apply of the three corpora (2026-09-18, Knox's go) lost
all 30 topics to the #3691 W2 rule — canonicalClaim ≤ 140 chars, one
sentence, no bundled clauses — which the corpora predate. Thirty agents
had already been registered by then; the GET-only dry-run could not see
the rule.

Every canonicalClaim is rewritten to one atomic proposition ≤ 140 chars
(longest 135). Evicted detail stays in `content`. Two claims drop their
dotted rule numbers from the claim text (ASX LR 3.1, DFARS 252.225-7052)
because the server's sentence splitter treats the dot as a terminator;
the titles keep the numbers.

_defence_seed_helpers gains a Python mirror of src/lib/claim.ts
lintAtomicClaim (length, single sentence, top-level and/or joining two
verb-bearing clauses, hedges). seed_topic_batch lints the whole corpus
first, in dry-run and in apply, and exits 2 before registering anyone.

Dry-run after the rewrite: 30 to create, 0 present, 25 edges pending.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@cursor

cursor Bot commented Sep 18, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_dca0339e-a76a-4f85-936f-297f60e563a0)

Tailor-AUS and others added 2 commits September 21, 2026 21:41
…rror hardened, no orphan-agent path left (refs TailorAU/tailor-group#7)

Four-lens adversarial review of this PR (lint parity via the real
lintAtomicClaim, claim fidelity old→new, helper logic with an offline
harness, and a full local rehearsal against a local server) plus a
three-skeptic refute pass on every blocker/high finding.

Claims (9 of 30 re-worded, all verified against src/lib/claim.ts on the
route path — sanitizeContent then lintAtomicClaim — 30/30 ok, max 140):
- DTCA: "to a foreign person" was not in the topic content (s 10 vs the 2024
  s 10A limb); now "supply … out of Australia".
- BLM 3809: "beyond casual use" contradicted the content's Notice
  alternative; now the approved Plan of Operations for commercial mining.
- ASX: restores the reasonable-person expectation test the content states.
- DFARS: states the specialty-metals rule itself; drops "such as antimony",
  which 10 USC 4863 does not cover.
- Critical Minerals Strategy: the List names 31 minerals; the invented
  purpose clause is gone.
- Antimony: states the content's own USGS figures (≈40,000 t of ≈83,000 t)
  instead of "80 percent of mine production".
- NEPA: "42 USC 4321 et seq" and "human environment" as the statute says.
- NSLA EFI Act: the Act's real name, abbreviated.
- Rare earths: one proposition (mine production); refining stays in content.

Lint mirror (scripts/_defence_seed_helpers.py): measures UTF-16 code units
like JS String.length, uses ASCII-only regex semantics like the server's
non-unicode regexes, and lints after the same control-char/HTML strip and
JS trim as sanitizeContent — the three divergences an adversarial corpus
of 72 cases found (none triggered by this corpus).

Orphan agents (the failure the first apply produced): the topic scripts now
check which titles already exist BEFORE registering, register exactly one
agent per missing topic, and abort (exit 3) rather than round-robin when
fewer keys come back — a key's second topic is refused by civic duty and a
fresh agent cannot vote for five minutes. A 409 counts as EXISTS only for
the exact-title duplicate or when existingTitle matches; a fuzzy
near-duplicate of a different topic is a FAIL that names it.
seed_topic_dependencies.py registers only after titles resolve, and reuses
a topic-script key (PACT_SEED_AGENT_KEY, or the last line of
PACT_SEED_KEYS_FILE that the topic scripts append to, mode 0600) so the
31st registration — which the 60/hour per-address budget cannot afford —
is never needed. pact_pow.register retries transient network errors like
api() does instead of crashing mid-batch.

README: the seed block points at scripts/, SOURCE_BASE and the dry-run,
and documents the budget and the keys file.

Local rehearsal at the PR head (before these fixes): 30/30 topics created
on a local server, then the dependency script's registration hit the
60/hour limit exactly as predicted; the offline harness passes all seven
control-flow scenarios on the patched scripts.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017KgkRXPohsXifa6cYJwk2N
…roup#7)

The rehearsal lens read "=== seed_defence_au.py complete: 0/12 topics in
place ===" at the end of a clean SEED_DRY_RUN=1 plan — a footer that reads
as a failure to the operator diffing the plan before an apply. In dry-run
mode the three topic scripts now print "dry run: N/M already present,
K to create — nothing written"; the apply footer is unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017KgkRXPohsXifa6cYJwk2N

Copy link
Copy Markdown
Contributor Author

Adversarial review record (dark seat, 21 Sep 2026) — refs TailorAU/tailor-group#7.

Four independent lenses read this PR at e4ca1e6 against the deployed server code, plus three skeptics per blocker/high finding:

  • Lint parity. All 30 rewritten claims pass the real lintAtomicClaim on the route path (sanitise, then lint): 30/30 ok, 0 warnings, max 135 chars, 0 exact or fuzzy (≥ 75 %) title collisions among the 30 (nearest pair 0.727). The Python mirror diverged from the server on 8 of 72 adversarial cases (UTF-16 vs code-point length, Unicode \b/case-folding vs the server's ASCII regexes, no control-char/HTML strip before linting); none fired on this corpus.
  • Claim fidelity. 25/30 faithful or defensible narrowings. Confirmed by the refute pass: the DTCA claim introduced "to a foreign person", which neither the topic content nor the cited Act (s 10, not the 2024 s 10A limb) states. Also replaced: BLM 3809 ("beyond casual use" → the Plan of Operations for commercial mining the content describes; the skeptics rated the original a low-severity nit, the replacement is simply the more faithful wording), ASX (restores the reasonable-person test), DFARS (drops "such as antimony", outside 10 USC 4863), Critical Minerals List purpose clause, the antimony "80 percent of mine production" figure the content's own 40,000 t / 83,000 t contradicts, NEPA (4321 et seq, "human environment"), the NSLA EFI Act's real name, and the rare-earth claim reduced to one proposition.
  • Helper logic. Every orphan-agent path from the pre-flight was confirmed at e4ca1e6 by all three skeptics and reproduced offline: registration before any existence check, round-robin on shortfall into civic-duty 403s that a fresh agent cannot vote out of, the dependency script registering before resolving titles, any 409 with existingTopicId treated as EXISTS, an unguarded POST in pact_pow.register, and a registration budget exactly saturated (60/hour per address, two hits per registration, 31 registrations).
  • Local rehearsal (local Postgres + next dev, production PoW bits, no overrides): the three topic scripts created 30/30 topics (30 × 201, no 422/403/409); the dependency script's registration was hit 61 → 429 → exit 1 with 0 edges; after a limiter reset the same script created 25/25 edges. A re-run of seed_defence_au.py minted 12 orphan agents for 12 × 409 EXISTS.

Commits c4ef569 and 5afacba carry the fixes: the nine claims (re-verified 30/30 on the route path), the mirror hardening, existence check before registration, abort (exit 3) instead of round-robin, dependency registration after resolution, exact-title-only 409, network retries in the PoW client, key reuse for the edge step (PACT_SEED_AGENT_KEY / PACT_SEED_KEYS_FILE, mode 0600) so the 31st registration is never needed, the README seed block, and a dry-run footer that no longer reads "0/12 topics in place". All seven offline harness scenarios pass on the patched scripts.

Merging under the 2026-09-20 finish-authorised-work ruling once the checks are green. The live apply runs from this revision, topic scripts one at a time, then the dependency script with a reused key.


Generated by Claude Code

@Tailor-AUS
Tailor-AUS merged commit 6ad8581 into rehome-review Sep 21, 2026
3 checks passed
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.

2 participants