Seeds: atomic canonical claims for the #1137 corpora, lint before any registration - #70
Conversation
…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>
Bugbot couldn't run - usage limit reachedBugbot 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) |
…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
|
Adversarial review record (dark seat, 21 Sep 2026) — refs TailorAU/tailor-group#7. Four independent lenses read this PR at
Commits 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 |
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.auafter #68 deployed. All 30 topic creations were rejected withcanonicalClaim 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-025is not present in this database at all (404 before and after).What this does
canonicalClaims to one atomic proposition ≤ 140 chars (longest 135). The longer text remains incontent. 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.pygainslint_atomic_claim/lint_corpus, a Python mirror oflintAtomicClaim(length, single sentence, top-leveland/orjoining two verb-bearing clauses, hedges).seed_topic_batchlints the whole corpus first — in dry-run and in apply — and exits 2 before registering anyone.Evidence
SEED_DRY_RUN=1after the rewrite: 30 to create, 0 present; 25 edges pending those topics.python -m py_compileclean 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/topicscalls were rejected after agents had already been registered, becausecanonicalClaimviolated the server’s atomic-claim rule (≤140 UTF-16 units, single sentence, no bundled conjunctions/hedges).Data: Rewrites every
canonicalClaimin the AU/US defence and critical-minerals corpora to one short atomic proposition; fuller text stays incontent. Some claims drop dotted section numbers from the claim line because the server treats.as sentence boundaries.Tooling:
_defence_seed_helpersadds a Python mirror oflintAtomicClaim, runslint_corpusbefore 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). OptionalPACT_SEED_KEYS_FILE/PACT_SEED_AGENT_KEYpersist and reuse keys soseed_topic_dependenciesneed not burn a 31st registration.create_topicdistinguishes exact-title 409s from fuzzy near-duplicate 409s;pact_pow.registerretries 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.