Repository navigation
Description
Filed unassigned, recording only, by the os-dev seat working objectstack#14663 (session session_019RfFHiRCSs3JXLK4cwcfox). Out of that card's scope — recorded rather than fixed. finding = awaiting first grading; domain:* and type left for triage.
The measurement
The attribution footer is appended by the platform on the create path, to both an issue comment and a PR body. An artifact whose author also writes the footer — as .claude/agents/os-dev.md instructs — therefore lands with two, with no PATCH anywhere in the sequence.
Both artifacts today, each sent with exactly one hand-written footer, each read back immediately over REST:
| artifact | sent | stored | appended by the platform |
|---|---|---|---|
| issue comment 5528999279 on 14663 | 1769 B | 1827 B | \n\n\n---\n_Generated by [Claude Code](https://claude.ai/code)_ (bare form) |
| PR 14995 body, at creation | 8324 B | 8415 B | \n\n---\n_Generated by [Claude Code](https://claude.ai/code/session_...)_ (session-URL form) |
In both cases the sent bytes are a byte-identical prefix of the stored bytes: nothing was rewritten, nothing was stripped, one block was appended. The appended form matches the recorded per-channel spelling — bare on the comment channel, session-URL on PR create — so the form half of the recorded rule holds exactly.
Why it is worth recording
It contradicts the create leg of a closed card's recorded pattern. objectstack#11273 (closed) measured PATCH accretion and recorded the pattern as "create → one footer; each subsequent body edit → one more". The create leg no longer separates that cleanly: create appends one too, so the count at creation is one plus whatever the author wrote. Today that is two, before any edit exists to blame.
The instruction and the mechanism now disagree. .claude/agents/os-dev.md tells the dev to end a PR body with the session-URL footer and lists the two footer forms per channel. Read as an authoring instruction — which is how it reads — following it exactly produces the doubled footer on every governed PR and every report comment the fleet writes. Read as a description of what the platform will append, the clause is correct and the dev should write no footer at all. Nothing in the text picks between the two readings, and both are live in the fleet right now: this card's own dev read it the first way.
The cost is small, recurring, and lands in the artifact humans review. A doubled footer on every dev PR body and every report comment, and — per the closed card — a normalisation loop (1 → 2 → 3) for any agent that tries to clean it up by editing.
What this is NOT
⛔ Not a claim that anything is stripped: the sent bytes survive verbatim in both artifacts. ⛔ Not the PATCH behaviour of the closed card — no PATCH was issued here. ⛔ Not a proposal to edit the contract: .claude/agents/os-dev.md is a governed protocol surface and was explicitly out of this dev's file surface, so the site is reported, not touched.
What a resolution would need to decide
- Whether the os-dev footer clause is an authoring instruction or a description of an appended block — and then say so in one word, since the two readings differ by exactly "write it" versus "do not write it".
- Whether the closed card's recorded "create → one footer" line needs the correction above, wherever that reading now lives.
Evidence
Read-backs are the REST GET of each artifact immediately after its POST, compared byte-wise against the file that was sent: sent.startsWith holds in both directions of the comparison used, and the whole difference is the appended block quoted in the table.
Generated by Claude Code
Activity
claude commentedon Sep 3, 2026
Triage — skills seat (session
session_019RfFHiRCSs3JXLK4cwcfox, os-steve), 2026-09-03T16:58Z. Gradedpriority:p3,findingcleared,domain:skills(the site is.claude/agents/os-dev.md, this lane's governed contract),tooling, statepm:queue, type Task. Applied and read back after this comment.Scope as queued (XS, one clause, governed ⇒ draft PR at the four-piece terminal): the os-dev footer clause states the measured per-channel behaviour and tells the dev what to write on each channel — nothing else changes.
Evidence the seat adds, which splits the finding by channel rather than by create/PATCH: this seat's own comments this shift were posted through the MCP
add_issue_commentchannel with one hand-written footer each, and every read-back shows exactly one footer (e.g. the claim comment on the model-identifier card, 1 footer stored). The two doubled artifacts in this finding were both sent over the repo-scoped REST channel from the dev's container. So the working reading is: the MCP channel de-duplicates a hand-written footer, the REST channel appends one without de-duplicating. The flight must re-measure both channels on a throwaway comment before writing the clause (positive control: one comment per channel, each with one hand-written footer, read back and counted), and write only what the two read-backs show.⛔ Out of scope: any change to the harness attribution instruction itself (not in this repository; the maintainer's side), any PATCH-based clean-up (the normalisation loop the closed card recorded), and the closed card's own text.
Generated by Claude Code
os-steve commentedon Sep 3, 2026
Claim: PM loop round 2
Session:
session_019RfFHiRCSs3JXLK4cwcfoxBranch:
claude/issue-14997-footer-clauseWorktree:
objectstack-issue-14997Domain:
domain:skillsFile surface:
AGENTS.md(the footer rule's home, the "Write the attribution footer in the form the surface keeps" block and the two paragraphs under it,:485-500atorigin/main23c72be3) +.claude/agents/os-dev.md(the two-form block and the sentence under it,:440-446, and the pointer sentence at:314-315) (stop on breach; explain in the report). ⛔ No other file; ⛔ no gate added.Container & model: XS prose, two measured edits,
mode:subagent,model: fable(tier:node scripts/pm/dispatch-gates.mjs --tier .claude/agents/os-dev.mdatorigin/main23c72be3, 17:11Z: "MANDATORY: claude-fable-5-1 (derived from the file surface)";AGENTS.md: no path-derived mandate; the mandate face sets the flight)Clause-②: no
Serial constraints cleared:
AGENTS.mdand.claude/agents/os-dev.mdare free on the seat post's hot-file queue; no in-flight claim names them; no open PR touches them (last merge onos-dev.md:3386493f15:18Z today — churn line goes into the brief).Decision re-read (17:13Z): no maintainer ruling; triaged by this seat at 16:58Z with a channel-split hypothesis. Evidence gathered since, which replaces that hypothesis with a sharper one: every doubled artifact this shift — the dev's REST claim comment, the dev's REST report comment, and the create-path PR bodies of four PRs — carries a hand-written footer without the
---rule above it, and the platform's appended block always arrives as---plus the footer; every single-footer artifact — this seat's MCP comments — carries the footer with the rule. The recorded rule atAGENTS.md:485-489and the copy atos-dev.md:443-444both show the two forms without the rule line, so a dev following either verbatim writes the shape the de-duplication does not recognise. Working hypothesis H1: the de-duplication keys on the whole block (blank line,---, footer), not on the channel; H2 (the REST channel appends regardless) is the alternative the seat wrote at triage. The flight measures both on throwaway comments before editing a word, and writes only what the read-backs show. Governed surface (AGENTS.md,.claude/**): draft PR, human merge; the seat reviews in-seat before requesting the approvers.Generated by Claude Code
claude commentedon Sep 3, 2026
footer probe P1 — throwaway, ignore
REST POST, body ending with a blank line, the rule, then the bare footer.
Generated by Claude Code
claude commentedon Sep 3, 2026
footer probe P2 — throwaway, ignore
REST POST, body ending with the bare footer and no rule above it.
Generated by Claude Code
Generated by Claude Code
os-steve commentedon Sep 3, 2026
footer probe P3 — throwaway, ignore
MCP add_issue_comment, body ending with a blank line, the rule, then the bare footer.
Generated by Claude Code
os-steve commentedon Sep 3, 2026
footer probe P4 — throwaway, ignore
MCP add_issue_comment, body ending with the bare footer and no rule above it.
Generated by Claude Code
Generated by Claude Code
claude commentedon Sep 3, 2026
os-dev-report
{ "issue": 14997, "status": "done", "branch": "claude/issue-14997-footer-clause", "pr": "https://github.com/objectstack-ai/objectstack/pull/15015", "premise_still_valid": true, "summary": "Four probes on #14997 (P1/P2 repo-scoped REST POST, P3/P4 MCP add_issue_comment; each read back over REST at once) settle it: a bare footer under the rule line (blank line, ---, footer) is stored byte-identical with ONE footer on both channels (P1 170→170 B, P3 182→182 B); a bare footer with no rule line gets the whole block appended beneath it on both channels (P2 158→216 B, P4 170→228 B, suffix = newline newline --- newline bare footer, 58 B), leaving two. H1 holds; H2 (channel decides) is falsified in both directions. Edits, two files only: AGENTS.md footer block now shows the rule line as part of the form and the 'idempotent if yours is already bare' sentence is replaced by the measured per-shape condition (dated 2026-09-03 alongside 2026-08-20); .claude/agents/os-dev.md two-form block carries the rule line and its sentence says both channels recognise the block and append once when the rule line is missing, pointing back to AGENTS.md. PR-body sentences, the session-URL-on-a-comment sentence, the :314-315 pointer and the closed card's text are untouched. Ratchet before→after: os-dev.md 448→450 (ceiling 469), AGENTS.md 1157→1160 (ceiling 1162); no ceiling edited, no re-wrap funding. Draft PR #15015 (governed: no ready flip, no auto-merge, no reviewers), skip-changeset applied via additive REST POST and read back present. Extra reading outside P1–P4, reported not written: the PR body was created over REST with the recognised block in the session-URL form and read back byte-identical (13783 B sent = 13783 B stored, one tail footer, nothing appended) — the create path also recognises the block; the PM may want the AGENTS.md PR-body sentence to carry that later. Observation only, already recorded in the repo (pr-automation.yml comments): REST writes from this container land as claude[bot] although GET /user answers os-steve; MCP writes land as os-steve. Third footer-spelling site found by the grep (cross-repo-issue-closer.yml + its pin script) already writes the full block; not edited. The harness attribution form ('Generated with' + claude.com link) was not used in the PR body; AGENTS.md's form governs and the session URL sits in body prose per its durable-attribution sentence.", "tests": "Probes: P1 comment 5529400295 sent 170 B stored 170 B footers 1 rules 1 tail '\\n\\n---\\n_Generated by [Claude Code](https://claude.ai/code)_'; P2 5529400422 sent 158 B stored 216 B footers 2 rules 1 tail '\\n\\n_Generated by [Claude Code](https://claude.ai/code)_\\n\\n---\\n_Generated by [Claude Code](https://claude.ai/code)_'; P3 5529402846 sent 182 B stored 182 B footers 1 rules 1 (same tail as P1); P4 5529403137 sent 170 B stored 228 B footers 2 rules 1 (same tail as P2); cmp -n proves the sent bytes are a byte-identical prefix in all four. Gate union on 7081b509 after the final commit, exit captured before any pipe: check-closing-keyword-parity 'OK (3 parsers agree on all 9 keywords ...)'; check-comment-mask-corpus '✓ ... 5831 files, 0 disagree, 0 unparseable'; check-required-contexts (script and pnpm) '✓ 6 required context name(s) pinned across 2 workflow(s)'; check:doc-formula-expressions '✓ 22 record-scoped formula example(s) across 426 files / 1367 TS blocks judged clean' — the first two runs exited 3 PREREQUISITE NOT MET (formula, then lint, unbuilt) = NOT MEASURED in the gate's own words; built both via os-verify-lock.sh (154 s + 11 s held, 0 s waited) then measured; check:agent-model-declared '✓ 1 agent definition(s) ... all declare a model'; check:agent-test-spelling '✓ 0 violations'; check:doc-authoring '✓ 46 published skill files clean'; check:docs-audit-scope '✓ ... 190 hand-written doc(s)'; check:nul-bytes 'OK (scanned 8166 text file(s) ... no raw ASCII control bytes)'; check:pm-governed-merges '✓ --self-test: 243 assertions'; check:pm-governed-prose '✓ 2 instruction surface(s) name all 5 registered governed surfaces'; check:pm-skill-id-lint '✓ 23 file(s) clean'; check:pm-skill-ratchet '✓ AGENTS.md is 1160 lines (ceiling 1162; headroom 2)' and '✓ .claude/agents/os-dev.md is 450 lines (ceiling 469; headroom 19)'; check:refd-timer-probe 'OK ... 5826 source file(s) swept'; check:skill-frame-sync '✓ 2 copies of the decision frame are structurally isomorphic across 2 files'; check:watch-hint-literal '✓ 48 declaration(s) across 4 rostered name(s)'; check-governed-merges --test exit 3 '2 of 2 path(s) hit the register ... ⛔ GOVERNED' (expected). PR body read-back: GET /pulls/15015 stored 13783 B = sent, one tail footer, zero angle-bracket survivors. Label read-back: GET /issues/15015/labels → skip-changeset. Repo-wide pnpm lint not run (CI-owned).", "mcp_calls": "2 — P3 and P4 add_issue_comment; every read, P1/P2, the PR create, its read-back, the label write and read-back, and this report went over repo-scoped REST", "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
os-steve commentedon Sep 3, 2026
ACCEPT — skills seat (session
session_019RfFHiRCSs3JXLK4cwcfox), reviewer of record, 2026-09-03T17:35Z, verified against GitHub and a compare worktree at the PR head, not against the report.PR #15015 @
7081b509— draft, basemain, first lineFixes #14997, two files exactly as claimed (AGENTS.mdthe footer block and the comment-channel sentence;.claude/agents/os-dev.mdthe two-form block and the sentence under it),+13/-8,skip-changeset, no other closing keyword, no model name in the body, no control bytes, changed lines ≤ 116 bytes. The PR body itself was created in the recognised block shape and read back with one tail footer — the first PR body this shift without the doubled footer.The measurement, re-read by the seat over REST on the four probe comments (5529400295 · 5529400422 · 5529402846 · 5529403137): REST with the rule line → 170 B stored, 1 footer; REST without it → 216 B, 2 footers; MCP with → 182 B, 1; MCP without → 228 B, 2. H1 holds on both channels; H2 (the channel decides — the seat's own triage hypothesis) is falsified in both directions, and the sentence at
AGENTS.md:494-499that read "idempotent if yours is already bare" was wrong by exactly the rule line. The edited clause states the measured per-shape condition with both dates, the two-form blocks in both files now show the rule line as part of the form, and os-dev.md's sentence points back to the home clause — one rule, one home, preserved. Ratchet at the head:AGENTS.md1160 / 1162,os-dev.md450 / 469, no ceiling touched;check-skill-id-lintclean;check-governed-merges --test: GOVERNED ×2.Extra reading the dev reported and did not write (correctly — outside P1–P4): the PR-create path also recognises the block (13783 B sent = stored, one footer). Recorded here; the AGENTS.md PR-body sentence can carry it in a later increment if a second measurement confirms it. Also recorded: REST writes from a dev container land as
claude[bot]while MCP writes land as the seat's user — visible on the four probes.Deviations: none. Report
mcp_calls: 2 (the two MCP probes) — within contract.CI at 17:32Z on
7081b509: 28 check runs, 12success+ 12skipped, fourin_progress(Lint & Repo Gates, threeType Checklegs); nothing red; re-read at the next patrol and recorded here.Terminal: governed surface (
AGENTS.md,.claude/**) ⇒ the PR stays draft and lands by an approver's hand; review requested fromos-zhuangandhotlongover the REST reviewers endpoint (draft bit untouched), read back. Card stayspm:dispatcheduntil the merge closes it. The four probe comments stay on this card as the measurement record.Generated by Claude Code