C2 classification contract — C1 §3 implemented, Erratum 1 filed, C2 row signed - #72
Merged
Merged
Conversation
…fication C1 decided what things mean; C2 makes the transport structurally capable of carrying that decision. This commit carries it. Every classification below traces to a row of C1 §3.3 or to §4's residual rule — no new semantics. WHAT LANDED - `CaptchaCondition(str, Enum)` — C1-1..C1-10 plus RESIDUAL. No UNKNOWN member: an unclassifiable response is RESIDUAL, a positive classification, not a missing one. No fourth `CaptchaOutcome` member (§4 item 1, §7 item 4). - `CaptchaSubmitResult` replaces the `(CaptchaOutcome, dict | None)` two-tuple, which had nowhere to carry the matched condition or the response headers and so could satisfy neither §7's recording requirement nor §3.2's two-axis detection. Follows Note D's precedent: typed result, visible shape change, no compatibility adapter. - `CaptchaAttemptRecord.condition_id` is REQUIRED — a record that does not identify its condition is not constructible (§7 item 2). - `classify_captcha_response()` applies §3.2 precedence in order, then §3.3, then §4. Never keyed on status alone, never on the `error`/`hint` strings (unpinned human-facing text); C1-2 is `success is False` on a 2xx. - `live_submit_captcha_fn(request_fn, api_key)` builds the live seam on the module-level `real_request` extracted in 0fdbf88. Exactly one request per submission, no loop, no backoff, no resubmission on any outcome (§5). - `verify()` is a CARRIER: it copies every field onto the record and derives nothing. Re-deriving classification here would put a second, drifting interpretation of the same response into the record. C1 §10(b) BOUNDARY, HELD STRUCTURALLY Verify-path `rate_limit`/`platform_headers` are preserved on the attempt record. They are never written to `TransportResult.rate_limit`, which keeps its Note D meaning (the WRITE response's state) — `resp_meta` stays bound to the write response and `verify()` still returns a bare `CaptchaOutcome`, so verify-path metadata is unreachable from `_classify_created_content` by construction rather than by discipline. Preservation confers no authority: nothing reads these fields, and the kill-switch trigger is still keyed on `outcome` alone, its signature still closed keyword-only so evidence cannot silently become an escalation input. FINDING — AN INCONSISTENCY INSIDE LOCKED C1, FLAGGED NOT RESOLVED C1 §3.2 rule 1 names "rows 3-7" as the authoritative enumerated non-2xx statuses, but §3.3 also enumerates C1-8 (400) and C1-9 (500), which are likewise non-2xx. Rule 4 covers only statuses "not enumerated in §3.3", so on a literal reading 400 and 500 fall through §3.2 entirely despite having their own rows, and could never be recorded as themselves. This implementation treats ALL enumerated non-2xx statuses as authoritative, because §8 item 1 requires "every enumerated condition classified as specified" — under the literal reading, rows 8 and 9 are dead letters, which §8 item 1 cannot mean. The runtime outcome is IDENTICAL either way (both readings yield AMBIGUOUS); only the recorded provenance differs. Recorded in code at the mapping and reported to the operator 2026-08-17. Not treated as a §9 stop: §9 stop 1 covers conditions §3.3 does NOT enumerate, and these are enumerated. Related, and disclosed rather than smoothed over: a non-JSON body raises inside `real_request` before a status is available, so such a response reaches C1-10 rather than §3.2 rule 3 even when it was a 2xx. Both are AMBIGUOUS; only provenance differs. Documented at the C1-10 handler. TESTS — 647 passed, 7 xfailed (33 added) One per §3.3 row plus C1-R; §3.2 precedence including an enumerated status beating a contradicting body; residual-vs-enumerated distinguishability; mandatory `condition_id` on both types; no-retry proofs on C1-5/6/9/10 by counting calls at the seam; urllib's own no-retry posture evidenced behaviourally rather than asserted (§8 item 4); and the boundary proof — write and verify responses carrying DIFFERENT rate-limit values, asserting `TransportResult` reports the write's and the record the verify's. All fake-driven; `POST /api/v1/verify` is never really issued. C1 §8 ITEM 7 — CARRIED, NOT RESOLVED The disposition of an AMBIGUOUS outcome after `verify()` returns stays unresolved, now recorded as an explicit TODO item rather than left implicit: the outcome is recorded but nothing consumes it, and because AMBIGUOUS never increments the confirmed-failure counter, a systematic ambiguous condition will never engage `captcha_suspension_risk`. C1 §6 records this as needing its own ruling before unattended operation, and as not blocking GO-2. Test-count sync (CLAUDE.md, TODO.md, README.md -> 647) performed here, once, at the C2-complete count, per the deferral recorded in 9ab4d10; its TODO entry is marked done rather than left reading as open. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ce note Alongside 55fd620 rather than after it: the classifier commit records the divergence from §3.2's literal text, and this is the artifact that resolves what the plan means. Filed as its own dated document rather than as an edit to the locked plan, per the precedent that a locked document is not reopened to record a correction. DRAFT — corrects nothing until signed. Scope is deliberately one cross-reference. §3.2 rule 1 cites "§3.3 rows 3-7" as the authoritative enumerated non-2xx statuses, but §3.3 also enumerates C1-8 (400) and C1-9 (500); rule 4 excludes them by its own terms ("not enumerated in §3.3"), and rules 2-3 are conditioned on 2xx. So two enumerated rows are matched by no rule of §3.2. Corrected to "rows 3-9". The erratum states at length what it does NOT do, because the failure mode here is a scope-word fix reading as a re-decision: it changes no row's outcome, amends no other section, and decides nothing undecided. §3.3 assigns outcomes; §3.2 describes the order in which rows are reached. The defect is in the second. Outcome-neutral and says so: C1-8 and C1-9 are AMBIGUOUS as signed, and C1-R is AMBIGUOUS under §4, so no CaptchaOutcome, publication_status, verification_status, or counter differs either way. What differs is the recorded condition identifier — which is the reason to correct it rather than tolerate it, since §7 exists to keep a documented-ambiguous outcome distinguishable from one that falsifies the model, and the uncorrected reading would record a documented 400 or 500 as a falsification. It also states that signing it is NOT review of the C2 code: it records what the plan means; whether C2 implements the plan is the C2 row's question, answered by its own evidence and its own signature. Every citation verified against the plan before drafting (rule 1 at :125, rule 4 at :131-134, §8 item 1 at :338-339, §7 at :304-305, §2 at :81, the C1-8/C1-9 outcomes at :153-154). One defect found in my own draft and fixed: the §8 item 1 quotation carried bold emphasis the source does not have, which is the same paraphrase-fidelity error class as borrowing a narrower conclusion sentence. Now quoted plainly and marked as such. Separately, the non-JSON observation is kept as a PARKED note at the C1-10 handler rather than escalated: a body that fails to decode inside request_fn loses its status before classification, so it lands as C1-10 rather than §3.2 rule 3 even when it was a 2xx. Both rows are AMBIGUOUS, so no outcome differs; only provenance does. Resolving it would mean changing what request_fn returns, which is Note D's contract and outside C2. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ce in §4 Two operator-directed changes to the unsigned draft. 1. §4's phrasing. "is corrected to" was the active voice of an amendment, on a document that is locked — it implicitly claimed this erratum has authority to alter the plan's text, contradicting §1's own premise that it is filed INSTEAD of editing the locked document, precisely because it cannot. Now reads "should read, correcting the citation to ...": it describes what the plan's text ought to say without asserting that this adjacent, unsigned document is the instrument doing it. Line 75 was the only occurrence; §1, §5 and §6 were already in the weaker states-what-the-plan-means register and are untouched. 2. A fourth piece of internal evidence in §3, independent of the first three: §7's own illustrative list contrasts "a documented-ambiguous response (C1-6, C1-9, C1-10)" with "a response C1 never enumerated (C1-R)" (plan :302). A section written after §3.2 therefore already assumes row 9 is recorded as itself rather than folded into residual. Recorded with its limit rather than at full strength: that list names C1-9 and NOT C1-8, so point 4 is direct evidence for row 9 only. Row 8's reachability continues to rest on points 1-3 and on its identical structural position in §3.3. Writing it as covering both rows would have been the widening this erratum exists to avoid. Staleness sweep caught the consequence of the addition: §3's own preamble still read "Three features", and the fourth is not symmetric with the other three. Preamble now states the count and the asymmetry together. Still DRAFT. Corrects nothing until signed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Updated correction details with operator name and date.
Updated the correction date for the wiring plan erratum.
Updated correction timestamp from 00:42 to 00:43 EDT.
Post-signature staleness pass. The header still read "DRAFT — awaiting operator signature. Corrects nothing until signed." on a document that had been signed — the same self-contradiction the GO-1 record carried when its header said it authorized nothing over a signed authorization. Replaced with the locked status, the recorded signature time, and a pointer to where the signature lives. The original line did two jobs: it stated status AND it bounded the document's effect. Only the first was stale, so the second is preserved rather than dropped — the replacement still says the effect is the §4 citation-scope correction and nothing beyond it, and still points at §1 for what the erratum does not do. Dropping that clause would have quietly widened the document at the moment it became operative. Touches the header line only. The signature block is not modified. Full sweep of the document found no other stale statement: §1, §4, §5 and §6 were written in the states-what-the-plan-means register throughout, and §6's "signing it does not constitute review of the C2 code" remains true after signing rather than becoming a past-tense claim. Signature verified before this commit: all three cells present (LOCKED / Kevin Brown / 2026-08-17 00:43 EDT), the timestamp consistent with the signing commit's author date, and the cumulative diff across the operator's three commits touching ONLY those three cells — Statement and document body byte-identical to the drafted text. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
C1 decided what the platform's responses mean; this PR implements that contract, files the one correction C1 needed, and signs C2's checklist row.
Completes C2's engineering half. The structural half (instance-free request/auth seam) landed in #71.
What changed
moltbook/transport.py(+245) — the C1 §3 response-condition contract: the eleven-row classification table, detection precedence across the HTTP-status and response-envelope axes, HTTP 409 asAMBIGUOUS, the §4 residual rule (unenumerated responses resolve toAMBIGUOUS, no silent coercion and no exception-raising), and §7's requirement thatCaptchaAttemptRecordidentify which §3.3 condition matched or that none did.tests/test_moltbook_transport.py(+428) — per-row coverage plus the residual path.docs/m7_c1_wiring_plan_erratum_1_2026-08-17.md(+144) — Erratum 1, LOCKED, operator-signed 2026-08-17 00:43 EDT.TODO.md— the C2 parked items, recorded so each deferral is a decision on the record rather than something a later reviewer reconstructs from a commit body.CLAUDE.md/README.md— test count synced 611 → 647, the deferral C2 seam extraction — instance-free request/auth path for the live captcha wiring #71 filed deliberately.docs/m7_operator_go_checklist.md— C2's row signed.Erratum 1 — a defect inside locked C1
§3.2 rule 1 cited "§3.3 rows 3–7", but §3.3 also enumerates C1-8 (400) and C1-9 (500). Rule 4 excludes them by its own terms ("not enumerated in §3.3") and rules 2–3 are 2xx-only — so two enumerated rows were matched by no rule of §3.2.
This was implemented under the corrected reading because C1 §8 item 1 admits no other, with the divergence recorded in the code and commit at the time. It is not a §9 stop: stop 1 covers conditions §3.3 does not enumerate. The outcome is unchanged either way — both readings yield
AMBIGUOUS— so only recorded provenance differs, which is what §7 exists to protect.The erratum is filed instead of an edit: C1 is locked and is not reopened to record a correction. Its wording states that §3.2 rule 1's parenthetical should read "rows 3–9"; it does not claim to alter the locked text, change any row's outcome, or touch §3.3 in any respect.
C2's checklist row
Signed as artifacts-exist + suite-green, and the row says so explicitly: it attests that the required artifacts exist at the cited commit and that the suite is green, and does not attest to a reading of the implementation itself.
The row's Evidence is also the only thing in the repo that points at Erratum 1 — a reader of locked C1 §3.2 would otherwise see "rows 3–7" with no sign a signed correction exists.
tools/verify_go_checklist.py: 29 rows — 15 complete, 14 open, 0 defective.Tests — 647 passed, 7 xfailed
Verified by run at
714f202with a clean tree.Scope
No C1 decision introduced or revisited · no governance authority claimed over C1's locked text · the
AMBIGUOUS-disposition architecture question carried as C1 §8 item 7, not resolved here · C3–C5 untouched and still open ·POST /api/v1/verifywas not called.🤖 Generated with Claude Code