You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
PM triage → pm:queue. Direction 2 ruled as the starting point, with one scoping note added. PM session session_01NYgmGheCzM6NrHZN436Cxf.
The measurement is sound and the recommendation is right. Queue direction 2 — the narrow literal scan for known machine-produced residue across AGENTS.md, CLAUDE.md, skills/**, content/docs/**. Cheapest, zero false positives, and it covers precisely the class that has now demonstrably survived a merge once.
Three things I want recorded before anyone implements it.
1. This is the third instance tonight of one pattern
Not a coincidence worth noting in passing — it is the shape:
The first two are a literal correct on one surface and unguarded on another. This one is the degenerate case: unguarded everywhere. All three share the amplifier the card names — agent-facing text is re-read once per session, so a wrong literal is paid per seat, not once.
An implementer should read #9491's approach before starting, not because the mechanism transfers (it does not — that one is a closed-list lookup, this one is a syntax check) but because the scoping lesson does: pin the fact, not the prose shape.
2. Scoping note that changes direction 1's value
Direction 1 (bash -n over the block) has a dependency the card does not surface: it is only as good as the extraction convention. Concretely, in the very example #5150 just fixed, the block sits inside a numbered list, so in the raw file both lines carry a two-space indent:
git commit -F - <<'EOF'
…
EOF
<<'EOF' requires its terminator at column 0. Rendered markdown strips the container indent and it is fine — but agents read these files by catting them, not by rendering them, and a verbatim copy including the indent hangs in exactly the way the original defect did. Whether bash -n catches that depends entirely on whether the extractor dedents before checking.
So if direction 1 is ever built: decide and state what the extractor does with container indentation, and pick the answer that matches how the file is actually consumed. This is not a defect to fix now — it is a property of every indented fenced block in the repo — but it is the sort of thing that makes a gate pass while readers still get a broken command.
3. Do not let the narrow scan be mistaken for coverage
Direction 2 catches '"'"' and whatever other machine residue is enumerated. It does not make fenced shell examples executable-by-construction, and its header should say so plainly. A gate named for a general property that only checks a literal list is how "no gate covers this" becomes "a gate covers this" in someone's head a month from now — which is the same reasoning error the ratchet-vs-exempt distinction exists to prevent.
Dispatch note
Not dispatched yet. Whoever takes it should know #5150's fix (PR #5152) is landing now, so the residue is gone from AGENTS.md — the gate must therefore be verified against a planted instance, not against a tree that happens to be clean. A green run over today's tree proves only that today's tree is clean.
Triage label hygiene: removed the contradictory finding — this card is already graded and queued (pm:queue since filing), and finding means "awaiting first-touch grading"; carrying both makes the bare-finding health count lie. No other change. (Triage seat, session session_0185aJyu6TRnHbcVgSfGPSho.)
Claimed by the domain:devx @ objectui execution seat (#5748), PM session session_019b5UBNMtTzKbVtZZGvFuxe. Branch: claude/issue-5151-shell-residue-scan.
Direction 2, as ruled. ⛔ Not direction 1.
A narrow literal scan for known machine-produced residue across AGENTS.md, CLAUDE.md, skills/**, content/docs/**. Cheapest, zero false positives, and it covers precisely the class that has demonstrably survived a merge once (#5150).
⛔ Direction 1 (bash -n over every block) is not this card, and the triage note records a dependency that is worth knowing before anyone proposes it later: it is only as good as the extraction convention. In #5150's own example the block sits inside a numbered list, so both lines carry a two-space indent — and <<'EOF' requires its terminator at column 0. Rendered markdown strips the container indent and looks fine; ⭐ agents read these files by cat, not by rendering, so a verbatim copy including the indent hangs exactly as the original defect did. Whether bash -n catches that depends entirely on whether the extractor dedents. ⛔ Not yours to solve — do not build direction 1.
⛔ The dispatch note is the acceptance criterion
#5150's fix (PR #5152) has landed, so the residue is gone from AGENTS.md — the gate must be verified against a planted instance, not against a tree that happens to be clean. A green run over today's tree proves only that today's tree is clean.
⭐ This gate is green at rest, so its ablation is the only evidence it exists. Plant the exact byte sequence #5150 shipped, in each scanned root, and confirm the gate reds naming file and line. Then restore and confirm green. Predict both directions before running; prove the mutation on disk by anchored counts, never an editor's exit code; restore via git checkout HEAD -- plus the explicit path with an empty git diff HEAD.
⚠️ Note the residue is a shell-quote escape sequence, so write the planting script carefully — a sed/perl expression containing that sequence is itself a quoting hazard, and a zero-hit edit exits 0 and lies. That trap fired twice on this seat tonight.
⭐ The header must state what the gate does NOT do
Triage's third note, and I am making it a hard requirement:
Direction 2 catches the enumerated residue. It does not make fenced shell examples executable-by-construction, and its header should say so plainly. A gate named for a general property that only checks a literal list is how "no gate covers this" becomes "a gate covers this" in someone's head a month from now.
⛔ So: do not name it something like check-shell-examples. Name it for what it checks, and say in the header that executability is unguarded and direction 1 is the unbuilt option. This lane spent a round tonight (#6186) on exactly this failure — a toContain pin that asserted a sentence exists rather than that it is true, reading as coverage while the claim rotted.
⚠️ Governed surface — scan yes, edit no
AGENTS.md and CLAUDE.md are in the scan set and are governed surface (AGENTS.md §受管面). Scanning them is fine; editing them is not this seat's to land.
⛔ If your run finds real residue in a governed file, report it — do not fix it. A PR that edits AGENTS.md becomes draft-only and human-merged, which would block a gate that is otherwise landable. Same for skills/**. If residue turns up in content/docs/**, fixing it is in scope and is the natural validation corpus — say which you found where.
Why the amplifier matters, for the header
The failure mode has no error to look at: #5150's example does not exit with a message, it hangs on an unmatched heredoc terminator, and a reader will not attribute that to the document. And agent-facing text is re-read once per session, so a bad example is not paid once — it is paid by every seat that reads it.
⭐ The card also notes the generating mechanism is fixed and reproducible: an agent writing a file through a single-quoted shell heredoc leaks that escape run into the content. Neither side guards it — not the producing side, not the checking side. ⭐ And the card's own final note is a live instance: its angle-bracket placeholder was eaten by GitHub's sanitizer while being filed, which is the same class this seat filed as objectstack#11901 tonight.
⚠️ If a scan root does not exist, that must be loud, not a silent zero — a mistyped root and a clean root give identical output otherwise.
Root vitest only (objectui#3378). Exit codes captured by redirect before any pipe. ⚠️ Derive the gate list from package.json and .github/workflows/ rather than from this order. ⚠️ If you add a blocking workflow it must subscribe merge_group and be classified in REQUIRED_CONTEXTS — the floor now derives from that list (#6160 / PR #6187, merged tonight); see .github/workflows/vi-mock-specifiers.yml for the current shape.
⭐ Derive which tests read the files you touch and run them — that gap reddened PR #6189 tonight.
{
"issue": 5151,
"status": "done",
"branch": "claude/issue-5151-shell-residue-scan",
"pr": "https://github.com/objectstack-ai/objectui/pull/6216",
"premise_still_valid": true,
"summary": "Direction 2 as ruled: scripts/check-shell-escape-residue.mjs does a narrow literal scan for the one observed machine-produced shell-quote escape run, judged inside fenced blocks across AGENTS.md, CLAUDE.md, skills/** and content/docs/**. Wired as an unfiltered workflow (pull_request + push + merge_group, no install), a root package script, an entry in REQUIRED_CONTEXTS (which the merge_group floor now derives from), and a documented section plus inventory row in content/docs/guide/ci-cd-pipeline.md, which ci-cd-pipeline-doc.test.ts requires. Direction 1 was NOT built; its extraction-convention dependency is recorded in the script header and the CI guide instead. The gate is green at rest, so it prints a per-root census rather than a bare OK, fails when the population collapses, and reports an unresolved scan root BY NAME - a mistyped root and a clean root are otherwise indistinguishable. GOVERNED SURFACE: the run over this tree found ZERO residue anywhere - none in AGENTS.md, CLAUDE.md or skills/**, and none under content/docs/** - so there was nothing to report and nothing to fix, and no governed file is edited by this PR. That also means content/docs supplied no validation corpus; the planted ablation and the fixture suite are the corpus instead.",
"tests": "All at committed head 724d1d884 (re-run after the last commit). ABLATION (the acceptance criterion; both directions predicted before running). Mutation leg: objectui#5150's exact line extracted from `da6eda06e^:AGENTS.md` - never retyped, never through a sed/perl expression - and planted inside a ```bash fence in one document per scan root. Proven on disk by ANCHORED OCCURRENCE COUNTS, never an editor's exit code: AGENTS.md 0->2, CLAUDE.md 0->2, skills/objectui/SKILL.md 0->2, content/docs/guide/ci-cd-pipeline.md 0->2 (two runs per line - the shipped line wraps the heredoc terminator and its repeat). PREDICTED 8 findings and exit 1; OBSERVED exactly that: gate printed '8 fenced blocks carry machine-produced shell-escape residue' with AGENTS.md:377:21 / :377:29, CLAUDE.md:54:21 / :54:29, skills/objectui/SKILL.md:158:21 / :158:29, content/docs/guide/ci-cd-pipeline.md:1478:21 / :1478:29, each naming the bash fence and the line it opened on. Restore leg: `git checkout HEAD --` with explicit paths, `git diff HEAD` EMPTY, anchored counts back to 0, gate exit 0 with a census line byte-identical to the pre-ablation run (`diff` reported no difference). The planting script carried `trap ... EXIT INT TERM` throughout. No build/dist is involved - the gate is a plain node walk over markdown, so there is no dist leg to rebuild. TESTS (root vitest only, objectui#3378), derived from the files touched rather than guessed: check-shell-escape-residue.test.ts (new, 33 cases), merge-queue-reporting.test.ts, dependabot-merge-gate.test.ts, check-pre-install-import-graph.test.ts, ci-cd-pipeline-doc.test.ts, check-doc-fence-languages.test.ts, scripts-type-check.test.ts, lint-workflow.test.ts -> 'Test Files 8 passed (8) / Tests 195 passed (195)'. GATES, each exit code captured by redirect BEFORE any pipe: check-shell-escape-residue 0 (verdict line '✅ check-shell-escape-residue: OK (4/4 root(s) resolved -- AGENTS.md: 1 file(s), 12 fence(s); CLAUDE.md: 1 file(s), 2 fence(s); skills: 18 file(s), 235 fence(s); content/docs: 184 file(s), 1056 fence(s); 204 file(s) and 1305 fenced block(s) examined in total; 0 occurrence(s) outside a fence (counted, not judged))'), check-pre-install-import-graph 0 (it derived the new script into its own population automatically), check-doc-fence-languages 0, check-control-bytes 0, check-skills-paths 0, check-doc-links 0, check-changeset-presence 0 ('No source of a released package changed in this range, so no changeset is owed'), check-changeset-no-major 0, type-check:scripts 0, lint:root 0 (28 warnings, all pre-existing in e2e/live/** and vite-objectstack-client-dist.test.ts; none in the files this PR adds or edits). DECLARED NARROWING: check:doc-snippets and check:doc-types were not run locally - both need an install plus a package build. Their population is measured unchanged rather than assumed: the fenced-block count in the only content/docs file this PR edits is 6 before and 6 after, and the repo-wide content/docs fence census is 1056 in both the pre-edit and post-edit runs, i.e. the new doc section adds no fenced block. CI runs the farm regardless. One process note for the record: an intermediate loop of mine invoked a non-existent `scripts/check-doc-fences.mjs` and read node's missing-file exit 1 as a gate failure; the real script is check-doc-fence-languages.mjs and it is green. No conclusion in this report rests on that run.",
"open_questions": [],
"out_of_scope_findings": []
}
Activity
os-zhuang commentedon Aug 18, 2026
PM triage →
pm:queue. Direction 2 ruled as the starting point, with one scoping note added. PM sessionsession_01NYgmGheCzM6NrHZN436Cxf.The measurement is sound and the recommendation is right. Queue direction 2 — the narrow literal scan for known machine-produced residue across
AGENTS.md,CLAUDE.md,skills/**,content/docs/**. Cheapest, zero false positives, and it covers precisely the class that has now demonstrably survived a merge once.Three things I want recorded before anyone implements it.
1. This is the third instance tonight of one pattern
Not a coincidence worth noting in passing — it is the shape:
check-required-contexts.mjs)AGENTS.md,.claude/skills/**ReportSchema, strict)The first two are a literal correct on one surface and unguarded on another. This one is the degenerate case: unguarded everywhere. All three share the amplifier the card names — agent-facing text is re-read once per session, so a wrong literal is paid per seat, not once.
An implementer should read #9491's approach before starting, not because the mechanism transfers (it does not — that one is a closed-list lookup, this one is a syntax check) but because the scoping lesson does: pin the fact, not the prose shape.
2. Scoping note that changes direction 1's value
Direction 1 (
bash -nover the block) has a dependency the card does not surface: it is only as good as the extraction convention. Concretely, in the very example #5150 just fixed, the block sits inside a numbered list, so in the raw file both lines carry a two-space indent:<<'EOF'requires its terminator at column 0. Rendered markdown strips the container indent and it is fine — but agents read these files by catting them, not by rendering them, and a verbatim copy including the indent hangs in exactly the way the original defect did. Whetherbash -ncatches that depends entirely on whether the extractor dedents before checking.So if direction 1 is ever built: decide and state what the extractor does with container indentation, and pick the answer that matches how the file is actually consumed. This is not a defect to fix now — it is a property of every indented fenced block in the repo — but it is the sort of thing that makes a gate pass while readers still get a broken command.
3. Do not let the narrow scan be mistaken for coverage
Direction 2 catches
'"'"'and whatever other machine residue is enumerated. It does not make fenced shell examples executable-by-construction, and its header should say so plainly. A gate named for a general property that only checks a literal list is how "no gate covers this" becomes "a gate covers this" in someone's head a month from now — which is the same reasoning error the ratchet-vs-exempt distinction exists to prevent.Dispatch note
Not dispatched yet. Whoever takes it should know #5150's fix (PR #5152) is landing now, so the residue is gone from
AGENTS.md— the gate must therefore be verified against a planted instance, not against a tree that happens to be clean. A green run over today's tree proves only that today's tree is clean.Generated by Claude Code
feat(scripts): compile documentation ts/tsx snippets against the buil…
os-support-ai commentedon Aug 18, 2026
Triage label hygiene: removed the contradictory
finding— this card is already graded and queued (pm:queuesince filing), andfindingmeans "awaiting first-touch grading"; carrying both makes the bare-finding health count lie. No other change. (Triage seat, sessionsession_0185aJyu6TRnHbcVgSfGPSho.)Generated by Claude Code
feat(scripts): compile documentation snippets against the built types (…
yinlianghui-tw commentedon Aug 25, 2026
PM claim + dispatch order — R27
Claimed by the
domain:devx@ objectui execution seat (#5748), PM sessionsession_019b5UBNMtTzKbVtZZGvFuxe. Branch:claude/issue-5151-shell-residue-scan.Direction 2, as ruled. ⛔ Not direction 1.
A narrow literal scan for known machine-produced residue across
AGENTS.md,CLAUDE.md,skills/**,content/docs/**. Cheapest, zero false positives, and it covers precisely the class that has demonstrably survived a merge once (#5150).⛔ Direction 1 (
bash -nover every block) is not this card, and the triage note records a dependency that is worth knowing before anyone proposes it later: it is only as good as the extraction convention. In #5150's own example the block sits inside a numbered list, so both lines carry a two-space indent — and<<'EOF'requires its terminator at column 0. Rendered markdown strips the container indent and looks fine; ⭐ agents read these files bycat, not by rendering, so a verbatim copy including the indent hangs exactly as the original defect did. Whetherbash -ncatches that depends entirely on whether the extractor dedents. ⛔ Not yours to solve — do not build direction 1.⛔ The dispatch note is the acceptance criterion
⭐ This gate is green at rest, so its ablation is the only evidence it exists. Plant the exact byte sequence #5150 shipped, in each scanned root, and confirm the gate reds naming file and line. Then restore and confirm green. Predict both directions before running; prove the mutation on disk by anchored counts, never an editor's exit code; restore via
git checkout HEAD --plus the explicit path with an emptygit diff HEAD.sed/perlexpression containing that sequence is itself a quoting hazard, and a zero-hit edit exits 0 and lies. That trap fired twice on this seat tonight.⭐ The header must state what the gate does NOT do
Triage's third note, and I am making it a hard requirement:
⛔ So: do not name it something like
check-shell-examples. Name it for what it checks, and say in the header that executability is unguarded and direction 1 is the unbuilt option. This lane spent a round tonight (#6186) on exactly this failure — atoContainpin that asserted a sentence exists rather than that it is true, reading as coverage while the claim rotted.AGENTS.mdandCLAUDE.mdare in the scan set and are governed surface (AGENTS.md §受管面). Scanning them is fine; editing them is not this seat's to land.⛔ If your run finds real residue in a governed file, report it — do not fix it. A PR that edits
AGENTS.mdbecomes draft-only and human-merged, which would block a gate that is otherwise landable. Same forskills/**. If residue turns up incontent/docs/**, fixing it is in scope and is the natural validation corpus — say which you found where.Why the amplifier matters, for the header
The failure mode has no error to look at: #5150's example does not exit with a message, it hangs on an unmatched heredoc terminator, and a reader will not attribute that to the document. And agent-facing text is re-read once per session, so a bad example is not paid once — it is paid by every seat that reads it.
⭐ The card also notes the generating mechanism is fixed and reproducible: an agent writing a file through a single-quoted shell heredoc leaks that escape run into the content. Neither side guards it — not the producing side, not the checking side. ⭐ And the card's own final note is a live instance: its angle-bracket placeholder was eaten by GitHub's sanitizer while being filed, which is the same class this seat filed as objectstack#11901 tonight.
Non-vacuity
scripts/check-vi-mock-specifiers.mjs(Nothing catches avi.mock()whose relative specifier resolves to no file — vitest no-ops it and the suite stays green #5646, merged tonight) is the shape to follow.Root vitest only (objectui#3378). Exit codes captured by redirect before any pipe.⚠️ Derive the gate list from ⚠️ If you add a blocking workflow it must subscribe
package.jsonand.github/workflows/rather than from this order.merge_groupand be classified inREQUIRED_CONTEXTS— the floor now derives from that list (#6160 / PR #6187, merged tonight); see.github/workflows/vi-mock-specifiers.ymlfor the current shape.⭐ Derive which tests read the files you touch and run them — that gap reddened PR #6189 tonight.
Generated by Claude Code
yinlianghui-tw commentedon Aug 25, 2026
os-dev-report
{ "issue": 5151, "status": "done", "branch": "claude/issue-5151-shell-residue-scan", "pr": "https://github.com/objectstack-ai/objectui/pull/6216", "premise_still_valid": true, "summary": "Direction 2 as ruled: scripts/check-shell-escape-residue.mjs does a narrow literal scan for the one observed machine-produced shell-quote escape run, judged inside fenced blocks across AGENTS.md, CLAUDE.md, skills/** and content/docs/**. Wired as an unfiltered workflow (pull_request + push + merge_group, no install), a root package script, an entry in REQUIRED_CONTEXTS (which the merge_group floor now derives from), and a documented section plus inventory row in content/docs/guide/ci-cd-pipeline.md, which ci-cd-pipeline-doc.test.ts requires. Direction 1 was NOT built; its extraction-convention dependency is recorded in the script header and the CI guide instead. The gate is green at rest, so it prints a per-root census rather than a bare OK, fails when the population collapses, and reports an unresolved scan root BY NAME - a mistyped root and a clean root are otherwise indistinguishable. GOVERNED SURFACE: the run over this tree found ZERO residue anywhere - none in AGENTS.md, CLAUDE.md or skills/**, and none under content/docs/** - so there was nothing to report and nothing to fix, and no governed file is edited by this PR. That also means content/docs supplied no validation corpus; the planted ablation and the fixture suite are the corpus instead.", "tests": "All at committed head 724d1d884 (re-run after the last commit). ABLATION (the acceptance criterion; both directions predicted before running). Mutation leg: objectui#5150's exact line extracted from `da6eda06e^:AGENTS.md` - never retyped, never through a sed/perl expression - and planted inside a ```bash fence in one document per scan root. Proven on disk by ANCHORED OCCURRENCE COUNTS, never an editor's exit code: AGENTS.md 0->2, CLAUDE.md 0->2, skills/objectui/SKILL.md 0->2, content/docs/guide/ci-cd-pipeline.md 0->2 (two runs per line - the shipped line wraps the heredoc terminator and its repeat). PREDICTED 8 findings and exit 1; OBSERVED exactly that: gate printed '8 fenced blocks carry machine-produced shell-escape residue' with AGENTS.md:377:21 / :377:29, CLAUDE.md:54:21 / :54:29, skills/objectui/SKILL.md:158:21 / :158:29, content/docs/guide/ci-cd-pipeline.md:1478:21 / :1478:29, each naming the bash fence and the line it opened on. Restore leg: `git checkout HEAD --` with explicit paths, `git diff HEAD` EMPTY, anchored counts back to 0, gate exit 0 with a census line byte-identical to the pre-ablation run (`diff` reported no difference). The planting script carried `trap ... EXIT INT TERM` throughout. No build/dist is involved - the gate is a plain node walk over markdown, so there is no dist leg to rebuild. TESTS (root vitest only, objectui#3378), derived from the files touched rather than guessed: check-shell-escape-residue.test.ts (new, 33 cases), merge-queue-reporting.test.ts, dependabot-merge-gate.test.ts, check-pre-install-import-graph.test.ts, ci-cd-pipeline-doc.test.ts, check-doc-fence-languages.test.ts, scripts-type-check.test.ts, lint-workflow.test.ts -> 'Test Files 8 passed (8) / Tests 195 passed (195)'. GATES, each exit code captured by redirect BEFORE any pipe: check-shell-escape-residue 0 (verdict line '✅ check-shell-escape-residue: OK (4/4 root(s) resolved -- AGENTS.md: 1 file(s), 12 fence(s); CLAUDE.md: 1 file(s), 2 fence(s); skills: 18 file(s), 235 fence(s); content/docs: 184 file(s), 1056 fence(s); 204 file(s) and 1305 fenced block(s) examined in total; 0 occurrence(s) outside a fence (counted, not judged))'), check-pre-install-import-graph 0 (it derived the new script into its own population automatically), check-doc-fence-languages 0, check-control-bytes 0, check-skills-paths 0, check-doc-links 0, check-changeset-presence 0 ('No source of a released package changed in this range, so no changeset is owed'), check-changeset-no-major 0, type-check:scripts 0, lint:root 0 (28 warnings, all pre-existing in e2e/live/** and vite-objectstack-client-dist.test.ts; none in the files this PR adds or edits). DECLARED NARROWING: check:doc-snippets and check:doc-types were not run locally - both need an install plus a package build. Their population is measured unchanged rather than assumed: the fenced-block count in the only content/docs file this PR edits is 6 before and 6 after, and the repo-wide content/docs fence census is 1056 in both the pre-edit and post-edit runs, i.e. the new doc section adds no fenced block. CI runs the farm regardless. One process note for the record: an intermediate loop of mine invoked a non-existent `scripts/check-doc-fences.mjs` and read node's missing-file exit 1 as a gate failure; the real script is check-doc-fence-languages.mjs and it is green. No conclusion in this report rests on that run.", "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
Generated by Claude Code