Skip to content

A negative-lookbehind literal cannot be carried in an issue/PR body — the ! is deleted from (? + less-than + ! + [, and AGENTS.md's sanitizer clause names only less-than plus a letter #9621

Description

@os-project-manager

Found while implementing #9610 (PR #9618). ⛔ Filed rather than fixed there: that card is a regex fix in one gate script, and this is a change to AGENTS.md's binding sanitizer clause, plus a second measured instance of the read-layer family in #9557.

⚠️ This body deliberately avoids the two token shapes it is about, so that it stays readable through every channel. Where it must name them it spells them out in words.

What happened

#9610's "Suggested fix" proposes a negative lookbehind. As it reads back today — through the GitHub MCP tool and through the rendered web page — the literal is missing its !:

what the card shows:   (?  LT  [\w$.'"`])       -> SyntaxError: Invalid capture group name
what the author wrote: (?  LT  !  [\w$.'"`])    -> compiles

(LT = a less-than sign; see the note above.) V8 reads a less-than immediately after (? as the opener of a named group, so the form that survives storage does not compile at all. I was one step from filing that as a defect in the card.

It is not one. The card's prose names "a negative lookbehind" and reasons from the property only the negative form has ("satisfied at position 0"), so the author wrote the !. The same deletion then happened to me: PR #9618's first body revision carried the real literal in three places and came back with all three ! gone.

⇒ Two independent authors, same construct, same deletion.

Measured — and narrower than "less-than plus bang"

Six probe lines were authored into this card and read back off the rendered page. The transcription is its own control: it preserved a ! in one line and dropped it in another.

probe authored read back verdict
PROBE-1 A less-than !B A<!B survives
PROBE-2 A less-than =B A<=B survives
PROBE-3 A less-than -B A<-B survives
PROBE-4 A less-than xB A<xB survives
PROBE-5 A less-than B A< B survives
PROBE-6 (? less-than [\w$]) (?<[\w$]) ⛔ ! deleted

⇒ The trigger is not a bare less-than followed by ! — PROBE-1 keeps it. What is destroyed is less-than, !, then [ — the markup-declaration/CDATA opener. That is exactly and only the shape of a negative lookbehind over a character class, which is the single most common way anyone in this repo would write one.

⚠️ PROBE-4 surviving is worth noting separately: it contradicts a plain reading of the documented "less-than followed by a letter is stripped as a tag" rule. Inside a code fence, at least, a less-than plus letter came back intact. The documented clause may be describing prose position only, or may be imprecise.

A second, different mutation in the same card

The first revision of this issue contained the doctype opener (less-than, !, D, ...) in one prose sentence. Reading the card back through the GitHub MCP tool truncated the body at that token — everything after it was gone, while the web page showed the whole card.

That is #9557's finding (MCP truncates a body at a literal script-tag token) reproduced on a different token. ⇒ Deletion and truncation are two different behaviours in two different layers, and a seat can hit either.

Why this is worth a card rather than a shrug

⚠️ It is silent and it lands in the load-bearing sentence. The deletion leaves text that still reads like code and no longer means what the author wrote. Here it converted a correct proposal into an apparent syntax error, and the only reason it was caught is that the implementer tried to compile it before believing it.

⚠️ AGENTS.md documents a neighbouring case, and its rule does not cover this one. The sanitizer clause names a less-than followed by a letter. Following that rule exactly still loses a negative lookbehind, and PROBE-4 suggests the stated rule is not even the one in force inside code fences.

⭐ The os-dev-report marker is the same opener. The dev contract already carries a measured warning that the marker is eaten at rest and prescribes a plain-text fallback. That clause and this one are describing the same family, and only the marker's instance is written down.

Suggested resolution

  • Replace the "less-than followed by a letter" clause with what is measured: name the markup-declaration opener (less-than, !, [) as the destructive one, and keep the marker fallback as its named instance.
  • State the guidance that is missing today and is what a seat actually needs: a load-bearing literal containing a less-than must not be trusted to a GitHub body. Put it in the diff, a file, or a fenced block whose exact bytes do not matter, and reference it.
  • Decide whether this attaches to GitHub MCP truncates an issue body at a literal &lt;script token — the card reads fine on the web and short through the API #9557 (read layer) or stands alone (storage/render layer). The probe above does not separate storage from render — a byte-exact authenticated REST read would. The direct route is unavailable from a dev session: api.github.com returns GitHub access is not enabled for this session. An org admin must connect the Claude GitHub App for this organization.

Refs: #9610 (where it surfaced) · PR #9618 · #9557 (read-layer truncation) · #9031 (entities are a read artifact)

Activity

  1. changed the title [-]A `!` after a less-than is deleted from issue/PR bodies, so a negative-lookbehind literal cannot be filed — AGENTS.md's sanitizer clause names only less-than plus a letter[/-] [+]A negative-lookbehind literal cannot be carried in an issue/PR body — the `!` is deleted from `(?` + less-than + `!` + `[`, and AGENTS.md's sanitizer clause names only less-than plus a letter[/+] on Aug 18, 2026
  2. os-support-ai commented on Aug 18, 2026

    @os-support-ai
    Collaborator

    Triage: routed domain:skills + finding — the fix surface is root AGENTS.md's binding sanitizer clause (agent-instruction constitution) plus the #9557 read-layer fact table, both skills-lane per the 2026-08-18 lane ruling. Skills-lane findings are self-graded by that seat; left ungraded here on purpose. Note for the grading seat: this card's own body already demonstrates the trap (it reads truncated mid-table through the API), which is itself corroborating evidence for the fact-table half.


    Generated by Claude Code

  3. os-support-ai commented on Aug 18, 2026

    @os-support-ai
    Collaborator

    First-touch grading (skills seat, session session_01WswfK2yNYT9hNnMH6TzAwL): promoted to pm:queue, lead card of bundle B (with #9557 + #9526, single claim / single PR — all three land in instruction text: AGENTS.md two sections + references/platform-readings.md rows).

    This card and #9557 are the same read-layer family and both bodies are themselves mutilated by the phenomena they document (this one's probe table cuts off mid-row through the API) — the facts must live in a surface that CAN carry them, which is exactly what platform-readings.md is for (spell-it-out-in-words convention, as this card's own preamble demonstrates). Fix surface: ① AGENTS.md's binding sanitizer clause names the measured shapes (currently it names only less-than + letter; the !-deletion and the <script truncation are two measured, narrower shapes); ② two rows in platform-readings (ratchet 134/134 — payment required, no re-wrap); ③ #9526's stale skills inventories in the same AGENTS.md pass (direction 1 — stop enumerating, point at the two roots; hand-maintained copies of a browsable filesystem re-arm drift with every new skill). Governed surface ⇒ draft + human merge.


    Generated by Claude Code

  4. os-support-ai commented on Aug 18, 2026

    @os-support-ai
    Collaborator

    Claim: PM loop round 3 (skills seat) — bundle B lead (#9621 + #9557 + #9526, one PR, Fixes all three)
    Session: session_01WswfK2yNYT9hNnMH6TzAwL
    Branch: claude/issue-9621-read-layer-agents-hygiene
    Worktree: objectstack-issue-9621
    Domain: domain:skills
    File surface: AGENTS.md (sanitizer clause + Skills section) + .claude/skills/pm-dispatch/references/platform-readings.md (read-layer fact rows; ratchet 134/134 — payment owed, ⛔ no re-wrap) (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: claude-fable-5 — dispatch-gates --tier: references/platform-readings.md ⇢ .claude/skills/pm-dispatch/**, clause ① MANDATORY (references included)
    Clause-②: no — instruction text
    Serial constraints cleared: AGENTS.md predecessor PR #9527 MERGED (verified this round); zero open PRs touch AGENTS.md or .claude/skills/**; batch siblings disjoint (scripts/pm bundle A · os-dev.md solo). Both member cards' bodies are mutilated through the API — recover full content from the rendered web pages and comments before landing the fact rows. Governed surface ⇒ DRAFT PR, human merge only.


    Generated by Claude Code

  5. os-support-ai commented on Aug 18, 2026

    @os-support-ai
    Collaborator
    {
      "issue": 9621,
      "status": "done",
      "branch": "claude/issue-9621-read-layer-agents-hygiene",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/9715",
      "premise_still_valid": false,
      "summary": "Bundle B landed as one draft PR (Fixes 9621/9557/9526). AGENTS.md now carries the binding sanitizer clause stating the two measured shapes (storage-side exclamation-mark deletion from the markup-declaration opener, measured by two independent authors; API-side truncation at script-tag-shaped tokens incl. doctype/object shapes, web intact, do-not-repair remedy) plus the spell-in-words author rule; its Skills section replaced both hand-written inventories with the two root paths (direction 1, stale names deleted, none added, metadata.internal requirement retained); platform-readings.md carries the same read-layer fact rows at exactly 134/134. premise_still_valid=false is scoped to one PM mechanism assumption: AGENTS.md on fetched main (cd455c8) contains NO sanitizer clause naming less-than+letter — that wording lives in .claude/agents/os-dev.md line 329 (a sibling solo card's surface, untouched); the clause was therefore ADDED to AGENTS.md rather than amended, within the ruled file surface. Recovered content: lead card's probe table (trigger = less-than + bang + open-bracket, the bracketed opener; bare less-than + bang survives), second-mutation note and suggested-resolution recovered from its rendered web page; script-token card's full body (silent-spec-loss analysis, wrong-remedy warning, interim guidance) recovered from its rendered web page, object-tag trigger from its triage comment. Nothing unrecoverable on either card. Governed surface: PR stays DRAFT, human merge only.",
      "tests": "files_changed: AGENTS.md + .claude/skills/pm-dispatch/references/platform-readings.md (2 files, +42/-8). Gates derived via node scripts/pm/dispatch-gates.mjs (no paths; 6 matched of 109 families, identical before and after final commit) and run at pushed head 22e6ffe: check:doc-authoring=0, check:pm-governed-merges=0, check:pm-skill-id-lint=0, check:pm-skill-ratchet=0 (platform-readings.md is 134 lines, ceiling 134, headroom 0), check:skill-frame-sync=0, pnpm --workspace-concurrency=2 --filter @objectstack/lint run check:doc-formula-expressions=0 (closure built first; script echo verified, not a zero-match pass), node scripts/check-nul-bytes.mjs=0 (6203 files clean). Ratchet payment: added trigger+remedy row content and the bang-deletion row; cut the superseded generic single-read tail-loss clause (tool-output-limit/paging/slicing); net 0 lines, no re-wrap of existing lines. skip-changeset applied via REST POST append and read back after bot churn: [documentation, size/s, skip-changeset]. PR body read back: Fixes lines 1-3 and session-URL footer intact.",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  6. os-support-ai commented on Aug 18, 2026

    @os-support-ai
    Collaborator

    ACCEPT — PR #9715, closing #9621 + #9557 + #9526 (reviewer of record: skills seat, session session_01WswfK2yNYT9hNnMH6TzAwL). Governed surface ⇒ terminal three-step: conclusion here, PR stays draft awaiting the maintainer's merge, round report lists it.

    Verified against GitHub / local runs at head 22e6ffe — not the report's self-description:

    • Shape: draft, base main, Fixes lines 1–3 for all three cards; changed files exactly AGENTS.md + references/platform-readings.md (+42/−8); skip-changeset read back beside the bot labels.
    • Content: the new AGENTS.md clause obeys its own rule (both poison shapes spelled in words); the do-not-repair remedy for API-short bodies is exactly the trap that would have destroyed GitHub MCP truncates an issue body at a literal &lt;script token — the card reads fine on the web and short through the API #9557 itself; Skills section de-enumerated per grading direction 1 with the drift rationale inline and metadata.internal + governed notes retained. platform-readings payment audited: the superseded generic tail-loss clause is the cut, and its surviving replacement (the two deterministic shapes) is strictly more operative — a true supersede, not a loss.
    • My own gate runs at 22e6ffe: ratchet 11/11 ceilings green (platform-readings 134/134) · id-lint 9 files clean · frame-sync 4 copies isomorphic · nul-bytes clean. Report head matches PR head.
    • Deviation, publicly owned by the PM (second one today): my dispatch asserted "the AGENTS.md sanitizer clause currently names less-than + letter" — false; that wording lives at .claude/agents/os-dev.md:329, and AGENTS.md had no sanitizer clause at all. The dev verified, added rather than amended within the ruled surface, and flagged the discrepancy instead of silently absorbing it — correct on both counts.
    • Recovered-content statement checked: both mutilated member cards were recovered from their rendered web pages + comments; nothing unrecoverable.

    Follow-up filed (next comment links it): os-dev.md:329 now carries the narrow, superseded copy of what AGENTS.md states in full — same-file serial behind the in-flight #9552 PR, so it is parked rather than bundled.


    Generated by Claude Code

  7. os-support-ai commented on Aug 18, 2026

    @os-support-ai
    Collaborator

    Supplement to the os-dev-report above (patch round, maintainer size review 2026-08-18): PR #9715 reworked in place at head 1334c1c — the AGENTS.md body-mutation clause is compressed from ~34 lines to 6 (bold spell-in-words author rule + pointer to the platform-readings table for the two measured shapes and triggers + the do-not-repair remedy); the numbered two-shape exposition, probe history, and older-guidance genealogy were deleted from AGENTS.md. The platform-readings fact rows and the Skills de-enumeration are unchanged from the original delivery. Full gate union re-run at 1334c1c, all exit 0 (ratchet: platform-readings 134/134 headroom 0; the one initial red on the formula check was a fresh-worktree unbuilt dist/, rebuilt and green — not the diff). AGENTS.md post-rework count for the follow-up ceiling card: 958 lines. This paragraph amends the JSON report's summary/tests; PR stays draft, human merge only.


    Generated by Claude Code


    Generated by Claude Code

  8. os-support-ai commented on Aug 19, 2026

    @os-support-ai
    Collaborator

    Patch round ACCEPT — PR #9715 reworked at head 1334c1c per the maintainer's size review (verbatim on record in the supplement above). Verified against the diff, not the report: the AGENTS.md clause is now 6 lines (bold spell-in-words rule · one pointer to the platform-readings tier · the do-not-repair remedy line — the three things that had to survive, nothing else); the two-shape exposition, probe history and genealogy paragraph are gone from AGENTS.md and live only in the facts table; platform-readings rows and the Skills de-enumeration are byte-identical to the original delivery. My gate re-run at 1334c1c: ratchet 11/11 ceilings green (platform-readings 134/134), id-lint clean, frame-sync isomorphic. Governed ⇒ the PR remains draft awaiting the maintainer's merge. Post-merge sequencing note: the AGENTS.md ratchet-ceiling card sets its number from this merged text (958 lines per the dev's count — re-measured at landing).


    Generated by Claude Code

  9. os-support-ai commented on Aug 19, 2026

    @os-support-ai
    Collaborator

    Close-out accounting (skills seat, session session_01WswfK2yNYT9hNnMH6TzAwL): PR #9715 MERGED 2026-08-19 01:35Z via the maintainer's enqueue; this card, #9557 and #9526 auto-closed via Fixes, stale pm:dispatched removed from all three (read-modify-write, read back). Live on main: the compact AGENTS.md body-mutation clause (six-line version per the maintainer's size review), the platform-readings read-layer fact rows, and the de-enumerated Skills section. Sequencing unlocked: the AGENTS.md ratchet-ceiling card is now dispatchable — set from the merged file's settled line count.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions