docs: per-channel control-availability matrix (#757) (#768)
* docs: per-channel control-availability matrix (#757)
Add docs/CONTROL_AVAILABILITY.md — one row per enforcement mechanism,
one column per install channel (plugin / skills copy / repo clone /
Cowork / claude.ai Project / Claude Science / Pi), with honest
active / conditional / absent cells, per-channel notes citing the
existing scattered sources (README Requirements, SETUP methods,
pi/README.md, hooks/run_guard.sh), and the guard's environment
degradation table. Linked from README (Requirements + SETUP pointer)
and SETUP (Installation methods intro).
Evidence re-verified against the working tree: the channel set has
grown past the six named in the issue (SETUP now also documents
Cowork and the claude.ai 4a/4b split), so the matrix covers all
seven documented channels.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* refactor: apply /simplify pass + add CA-1..CA-3 defrift lint (#757)
Simplify round (4-agent review, findings deduped):
- Drop the 'How to read an integrity claim' section (it had already
drifted from the matrix) and the all-identical Upstream row; both
replaced by one legend sentence and one paragraph.
- Move channel-scoped caveats (Cowork / claude.ai / Claude Science / Pi)
from per-cell footnotes into a 'Channel-wide limitation' column of the
channel table; notes drop from 11 to 7.
- De-drift row labels: no inline allowlist contents (canonical list is
pinned by check_tools_allowlist.py), no exhaustive feature list, no
hard-coded Claude Code minimum version (lives in SETUP Method 0).
- README: single slimmed pointer (second link and both enumerations
removed); pointer mirrored to the four translated READMEs and
docs/SETUP.zh-TW.md.
- Degradations table scoped to actual guard degradations (the slash-form
version row was misfiled); registry backpointer added; guard-launcher
registry registration split to #769.
Lint (per the new-claim-surface-needs-lint-in-same-PR discipline):
- scripts/check_control_availability.py — CA-1 links/anchors resolve,
CA-2 every SETUP '### Method' heading reachable from the channel
table, CA-3 README + SETUP inbound links pinned. Cell semantics stay
owned by code review (degradation-registry posture).
- 9 mutation tests; wired into spec-consistency.yml + pytest manifest
(150 entries).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R1 findings — 4 P2 accuracy corrections (#757)
- SessionStart announce/update-reminder row: Conditional, not Active
(bash launcher on Windows needs Git Bash; reminder needs curl) — new
note 8.
- Cross-model note 6 no longer claims credentials+curl universally; the
citation-only Codex subscription transport is named as the alternative
transport behind the same consent boundary.
- Pi channel limitation reworded: the wrapper supplies no orchestration
but uses an installed Pi capability when available.
- 'Enforcement mechanisms' claim language aligned to 'controls' in the
purpose statement and all five README pointers (consistent with note
7's trust-based posture).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R2 findings — lint mis-pass cases + note-8 wording (#757)
- CA-1 link grammar accepts optional quoted titles so a titled dead
link cannot silently skip the check.
- CA-2 counts only fragments on links whose resolved destination IS
docs/SETUP.md — a same-slug anchor into a copied file no longer
satisfies method coverage.
- CA-3 checks resolved link destinations, not a filename substring — a
label that keeps the filename while the target moves now fails.
- Note 8: singular SessionStart hook (hooks.json defines one; the
announce script runs the update check internally).
- 3 new mutation tests pinning each mis-pass case (12 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R3 finding — commented-out markdown counts for nothing (#757)
Strip HTML comments before extracting links and headings in all three
invariants: a commented-out inbound link no longer satisfies CA-3, a
commented-out SETUP method heading no longer demands CA-2 coverage, and
a commented-out dead link no longer fires CA-1. Two mutation tests pin
both directions (14 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R4 finding — GFM type-2 HTML-block semantics (#757)
A line beginning with <!-- opens a raw-HTML block through the --> line
(including trailing text on the closing line) or to EOF if unclosed;
nothing on those lines renders. The comment stripper now models that
line-level behavior before the inline-span strip, so a link after -->
on a comment line cannot satisfy CA-3 and a dead link after an unclosed
comment cannot fire CA-1. Two mutation tests pin both (16 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* test: fix R4 mutation scenario — line-start vs inline comment (#757)
The previous commit's CA-3 HTML-block test inserted the comment mid-line
(inside the blockquote), where GFM renders the link normally and the
lint correctly stays quiet — the test scenario was wrong, not the lint.
Replaced with a whole-line mutation that actually begins with <!--, and
added the inline-comment symmetry case (link still renders → CA-3
satisfied). 17 tests green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R5 finding — block-quoted HTML-block lines (#757)
The type-2 HTML-block rule applies to block-quote content: the stripper
now looks through leading '> ' markers before the line-start test, so
'> <!-- note --> [link]' cannot satisfy CA-3. Deeper CommonMark
laminations are declared out of scope in the docstring (the surfaces do
not use them; a full parser is out of proportion for a maintainer-slip
guard). 18 tests green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R6 finding — repo-containment on CA-1 targets (#757)
A relative link that resolves outside the repository root now fails
CA-1 even when the host path exists — an over-deep ../.. slip must not
be masked by an existing host file. Mutation test added (19 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R7 finding — fenced code excluded from extraction (#757)
Fenced code regions render literally, and README/SETUP use fences
today, so they are in-scope: a link inside a fence no longer satisfies
CA-3, and a sample "### Method" heading inside a SETUP fence no longer
demands CA-2 coverage. Fence stripping runs before the comment pass so
a comment opener inside a fence stays literal. Two mutation tests (21
total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R8 finding — CommonMark fence-length closing rule (#757)
The fence stripper now tracks the opening run character and length: a
closer must be a same-character run at least that long with only
trailing whitespace, so a four-backtick fence demonstrating an inner
triple-backtick block is no longer closed early. Mutation test added
(22 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 23:57:07 +08:00
# Control Availability by Install Channel
**Purpose. ** ARS documentation names several controls — the write-scope guard, the
citation-verification gate, mandatory checkpoints, the tools allowlist. Which of those
actually operate depends on * how you installed ARS * . This page maps mechanism ×
channel in one place, so a user evaluating an integrity claim can see whether it holds
in their channel. The linked source documents remain authoritative for each fact.
**Origin. ** ISO/IEC 42001-spirit gap assessment
([`audits/iso42001-spirit-gap-assessment-2026-08-17.md` ](../audits/iso42001-spirit-gap-assessment-2026-08-17.md ),
finding T-6, [#757 ](https://github.com/Imbad0202/academic-research-skills/issues/757 )).
Transparency here is one of this repo's distilled operating principles (with informative
anchors to ISO/IEC 42001) — not an ISO-mandated artifact.
## Install channels
| Channel | Documented in | Channel-wide limitation |
|---|---|---|
| **Plugin ** — Claude Code plugin install | [SETUP Method 0 ](SETUP.md#method-0-claude-code-plugin-v370-recommended-for-claude-code-cli--ide-users ) | None — the reference channel. |
| **Skills copy ** — skill folders copied into a project's `.claude/skills/` or the global `~/.claude/skills/` | [SETUP Method 1 ](SETUP.md#method-1-as-project-skills-recommended ) | Nothing wired by the plugin manifest runs (note 3). |
| **Repo clone ** — Claude Code run inside a clone of this repository | [SETUP Method 2 ](SETUP.md#method-2-as-a-standalone-project ) | Nothing wired by the plugin manifest runs (note 3). |
| **Cowork ** — skills uploaded to Claude Cowork (desktop) | [SETUP Method 3 ](SETUP.md#method-3-claude-cowork-desktop ) | Each skill runs standalone: no Task-tool subagent dispatch, so the coordinated pipeline — and its staged checkpoints — does not run as designed. |
| **claude.ai Project ** — repo attached to a claude.ai Project as retrievable knowledge | [SETUP Method 4 ](SETUP.md#method-4-use-with-claudeai-web ) | Read-only knowledge: Claude can read and cite the skill bodies, but nothing executes — no activation, routing, hooks, scripts, or orchestration. (The Method 4a upload path is documented but not recommended; see SETUP § Method 4a.) |
| **Claude Science ** — skills imported via "Import from GitHub" | [SETUP Method 5 ](SETUP.md#method-5-claude-science-import-v3140 ) | Methodology layer only; Claude Code-specific machinery does not transfer, and Claude Science substitutes its own agent system (details: SETUP Method 5). Imports are point-in-time snapshots. |
| **Pi port ** — community-maintained wrapper for the Pi coding agent | [`pi/README.md` ](../pi/README.md ) | Two documented boundaries: the wrapper itself supplies no agent isolation or orchestration — an installed Pi orchestration capability is used when available, otherwise roles run sequentially (degraded execution, disclosed, not independent multi-agent review) — and no Claude hooks (write-scope enforcement stays prompt-level). `/ars-pi-doctor` reports what the local environment supplies. |
## Availability matrix
Legend: **Active ** = operates as documented · **Conditional ** = operates only under the
noted conditions, with a defined degraded state otherwise · **Absent ** = does not operate
in this channel. Read down your channel's column: a claim about a mechanism holds only
where its row says Active — or Conditional with the linked note's conditions met — after
applying your channel's channel-wide limitation above.
| Mechanism | Plugin | Skills copy | Repo clone | Cowork | claude.ai Project | Claude Science | Pi port |
|---|---|---|---|---|---|---|---|
| Methodology layer (the four skills' `SKILL.md` protocols) | Active | Active | Active | Active | Conditional | Active | Active |
| Skill auto-routing (trigger keywords → skill activation) | Active | Active | Active | Active | Absent | Conditional | Conditional |
| `/ars-*` slash commands | Active ⁽¹⁾ | Absent | Absent | Absent | Absent | Absent | Conditional |
| SessionStart announce + update reminder | Conditional ⁽⁸⁾ | Absent ⁽³⁾ | Absent ⁽³⁾ | Absent | Absent | Absent | Absent |
| Write-scope guard (`PreToolUse` hook) | Conditional ⁽²⁾ | Absent ⁽³⁾ | Absent ⁽³⁾ | Absent | Absent | Absent | Absent |
| Plugin agents with tools allowlist (#514 ) ⁽⁴⁾ | Active | Absent ⁽³⁾ | Absent ⁽³⁾ | Absent | Absent | Absent | Absent |
| Subagent orchestration (Task-tool multi-agent dispatch) | Active | Active | Active | Absent | Absent | Absent | Conditional |
| Python-backed opt-in features (repo `scripts/` ) | Conditional ⁽⁵⁾ | Conditional ⁽⁵⁾ | Conditional ⁽⁵⁾ | Absent | Absent | Absent | Conditional ⁽⁵⁾ |
| Cross-model verification (consent-gated second model) | Conditional ⁽⁶⁾ | Conditional ⁽⁶⁾ | Conditional ⁽⁶⁾ | Absent | Absent | Absent | Absent |
| Prompt-level checkpoints and integrity gates | Active ⁽⁷⁾ | Active ⁽⁷⁾ | Active ⁽⁷⁾ | Conditional | Absent | Conditional | Conditional |
CI-side checks (mutation-tested lints, content locks, changelog gates) are deliberately
docs: CI workflow enforcement-class table + inventory lint (#755) (#774)
* docs: CI workflow enforcement-class table + WC-1/WC-2 lint (#755)
docs/ARCHITECTURE.md gains §7.1: all 14 workflows classified by
trigger / what it checks / enforcement class (blocking / advisory /
administrative / post-push detection) / bypass token, with the honest
count line (8 blocking on at least one event class, 2 advisory, 1
administrative, 3 post-push detection) and the explicit statement that
tag workflows detect after the push — their stop-power is the
maintainer acting on the failure. Per-workflow facts verified against
the workflow files (eval-harness ack token + PR-only gating; changelog
gate release/** head scope; pytest path filters; the three tag
triggers).
CONTRIBUTING release-checklist prose now points at the classification
instead of implying uniform CI enforcement.
Lint (same-PR drift-point discipline): check_workflow_classification.py
— WC-1 inventory sync both directions (a new, renamed, or removed
workflow fails CI until the table matches; duplicates refused), WC-2
class cells begin with the closed four-term vocabulary. Class
semantics stay review-owned (degradation-registry posture). 9 mutation
tests; wired into spec-consistency.yml + the pytest manifest.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* refactor: apply /simplify + codex R1 — table accuracy + lint hardening (#755)
Review round (3 cleanup agents + codex gpt-5.6-sol xhigh R1), findings
deduped and applied:
Table accuracy (codex 3 P2 + 1 P3, cleanup F2/F3): every trigger cell
now states its actual branch/path/tag filters (repository-hygiene and
command-invariants had birth-drifted cells; several rows omitted
targeting-main scopes); freshness-check reclassified honestly
(Advisory for staleness, but malformed protocol metadata is a hard
failure); bypass cells say "justification requested, not
machine-validated" (both workflows accept the bare token);
command-invariants "what it checks" gains its other two enforced
checks; bypass column normalized to "none"; the legend absorbs the
tag-workflows sentence and the duplicated qualifier prose is trimmed.
Lint hardening: section extraction switches to the shared
_skill_lint.heading_section (exact full-line heading incl. the #755
anchor, fence-aware — 15 fewer bespoke lines); rows parse once with
escaped-pipe-aware cell splitting; the inventory glob covers *.yaml;
WC-2 matches vocabulary terms as whole words (Blockingg fails); the
arity guard moves under WC-1 with a test; new WC-3 recomputes the
bolded count line from the Class column (the honesty sentence can no
longer self-invalidate when a workflow is added); new WC-4 pins every
[bypass-token] in a Bypass cell to verbatim presence in its workflow
file. 14 mutation tests.
Surfaces: docs/CONTROL_AVAILABILITY.md corrects its "on every change"
claim and links §7.1; the ARCHITECTURE "How to read" §7 bullet indexes
the CI sub-view.
Skipped with reason: read_or_exit2 exit-2 convention (sibling lints in
this fleet use the exit-1 missing-doc violation shape; consistency
wins).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R2 findings — .yaml fixture parity + comment-blind WC-4 (#755)
- The mutation fixture copies *.yaml alongside *.yml, so a future
.yaml workflow with a valid row passes the fixture as it passes the
real lint.
- WC-4 strips full-comment lines before the token search: a renamed
executable token surviving only in a YAML comment no longer
satisfies the pin (token in a non-comment echo/log string recorded
as an accepted edge). Mutation test added (15 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R3 finding — tag pushes reach three more workflows (#755)
GitHub Actions matches tag pushes on unfiltered or paths-only push:
triggers (paths filters are not evaluated for tags), so
spec-consistency, command-invariants, and freshness-check also run on
every v* tag push — where their failures are post-push detection like
the tag-only workflows. Trigger cells amended and a subtlety note
added above the table; "three tag workflows" narrowed to "three
tag-only workflows".
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R4 finding — malformed token spellings fail loudly (#755)
Any bracketed span in a Bypass cell must be a well-formed
[lowercase-hyphen] token: a typo like [skip_cooldown] now yields a
WC-4 violation instead of silently falling out of the token grammar.
Mutation test added (16 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R5 finding — whitespace token typos caught (#755)
The any-bracket span matcher now accepts any non-] content, so
[skip cooldown] (space typo) reaches the well-formedness check and
fails loudly. Mutation test added (17 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R6 finding — bogus rows fail instead of dropping out (#755)
Every pipe row in the section that is not the header or the separator
must open with a backticked workflow filename; a malformed row now
yields a WC-1 violation instead of silently leaving the inventory and
the WC-3 count. Mutation test added (18 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* test: mirror docs/ARCHITECTURE.md into the CA fixture (#755)
The new CONTROL_AVAILABILITY link to ARCHITECTURE §7.1 made the #768
test fixture (which mirrors only the files the doc links) miss its
target, failing CA-1 in the fixture tree while the real tree passes —
caught by CI, not locally, because the local sweep re-ran the lint but
not its sibling test file. ARCHITECTURE.md joins the mirrored list.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-18 09:03:53 +08:00
not a matrix row: they run in this repository's GitHub Actions, protecting the
published artifact all channels ship from, and never run on a user machine —
identical for every channel. They do not all enforce at the same strength or fire on
every change: the per-workflow classification (blocking / advisory / administrative /
post-push detection, with triggers and bypass tokens) is
[ARCHITECTURE.md §7.1 ](ARCHITECTURE.md#71-ci-workflow-enforcement-classes-755 ). The machine-readable index of the suite's
docs: per-channel control-availability matrix (#757) (#768)
* docs: per-channel control-availability matrix (#757)
Add docs/CONTROL_AVAILABILITY.md — one row per enforcement mechanism,
one column per install channel (plugin / skills copy / repo clone /
Cowork / claude.ai Project / Claude Science / Pi), with honest
active / conditional / absent cells, per-channel notes citing the
existing scattered sources (README Requirements, SETUP methods,
pi/README.md, hooks/run_guard.sh), and the guard's environment
degradation table. Linked from README (Requirements + SETUP pointer)
and SETUP (Installation methods intro).
Evidence re-verified against the working tree: the channel set has
grown past the six named in the issue (SETUP now also documents
Cowork and the claude.ai 4a/4b split), so the matrix covers all
seven documented channels.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* refactor: apply /simplify pass + add CA-1..CA-3 defrift lint (#757)
Simplify round (4-agent review, findings deduped):
- Drop the 'How to read an integrity claim' section (it had already
drifted from the matrix) and the all-identical Upstream row; both
replaced by one legend sentence and one paragraph.
- Move channel-scoped caveats (Cowork / claude.ai / Claude Science / Pi)
from per-cell footnotes into a 'Channel-wide limitation' column of the
channel table; notes drop from 11 to 7.
- De-drift row labels: no inline allowlist contents (canonical list is
pinned by check_tools_allowlist.py), no exhaustive feature list, no
hard-coded Claude Code minimum version (lives in SETUP Method 0).
- README: single slimmed pointer (second link and both enumerations
removed); pointer mirrored to the four translated READMEs and
docs/SETUP.zh-TW.md.
- Degradations table scoped to actual guard degradations (the slash-form
version row was misfiled); registry backpointer added; guard-launcher
registry registration split to #769.
Lint (per the new-claim-surface-needs-lint-in-same-PR discipline):
- scripts/check_control_availability.py — CA-1 links/anchors resolve,
CA-2 every SETUP '### Method' heading reachable from the channel
table, CA-3 README + SETUP inbound links pinned. Cell semantics stay
owned by code review (degradation-registry posture).
- 9 mutation tests; wired into spec-consistency.yml + pytest manifest
(150 entries).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R1 findings — 4 P2 accuracy corrections (#757)
- SessionStart announce/update-reminder row: Conditional, not Active
(bash launcher on Windows needs Git Bash; reminder needs curl) — new
note 8.
- Cross-model note 6 no longer claims credentials+curl universally; the
citation-only Codex subscription transport is named as the alternative
transport behind the same consent boundary.
- Pi channel limitation reworded: the wrapper supplies no orchestration
but uses an installed Pi capability when available.
- 'Enforcement mechanisms' claim language aligned to 'controls' in the
purpose statement and all five README pointers (consistent with note
7's trust-based posture).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R2 findings — lint mis-pass cases + note-8 wording (#757)
- CA-1 link grammar accepts optional quoted titles so a titled dead
link cannot silently skip the check.
- CA-2 counts only fragments on links whose resolved destination IS
docs/SETUP.md — a same-slug anchor into a copied file no longer
satisfies method coverage.
- CA-3 checks resolved link destinations, not a filename substring — a
label that keeps the filename while the target moves now fails.
- Note 8: singular SessionStart hook (hooks.json defines one; the
announce script runs the update check internally).
- 3 new mutation tests pinning each mis-pass case (12 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R3 finding — commented-out markdown counts for nothing (#757)
Strip HTML comments before extracting links and headings in all three
invariants: a commented-out inbound link no longer satisfies CA-3, a
commented-out SETUP method heading no longer demands CA-2 coverage, and
a commented-out dead link no longer fires CA-1. Two mutation tests pin
both directions (14 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R4 finding — GFM type-2 HTML-block semantics (#757)
A line beginning with <!-- opens a raw-HTML block through the --> line
(including trailing text on the closing line) or to EOF if unclosed;
nothing on those lines renders. The comment stripper now models that
line-level behavior before the inline-span strip, so a link after -->
on a comment line cannot satisfy CA-3 and a dead link after an unclosed
comment cannot fire CA-1. Two mutation tests pin both (16 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* test: fix R4 mutation scenario — line-start vs inline comment (#757)
The previous commit's CA-3 HTML-block test inserted the comment mid-line
(inside the blockquote), where GFM renders the link normally and the
lint correctly stays quiet — the test scenario was wrong, not the lint.
Replaced with a whole-line mutation that actually begins with <!--, and
added the inline-comment symmetry case (link still renders → CA-3
satisfied). 17 tests green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R5 finding — block-quoted HTML-block lines (#757)
The type-2 HTML-block rule applies to block-quote content: the stripper
now looks through leading '> ' markers before the line-start test, so
'> <!-- note --> [link]' cannot satisfy CA-3. Deeper CommonMark
laminations are declared out of scope in the docstring (the surfaces do
not use them; a full parser is out of proportion for a maintainer-slip
guard). 18 tests green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R6 finding — repo-containment on CA-1 targets (#757)
A relative link that resolves outside the repository root now fails
CA-1 even when the host path exists — an over-deep ../.. slip must not
be masked by an existing host file. Mutation test added (19 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R7 finding — fenced code excluded from extraction (#757)
Fenced code regions render literally, and README/SETUP use fences
today, so they are in-scope: a link inside a fence no longer satisfies
CA-3, and a sample "### Method" heading inside a SETUP fence no longer
demands CA-2 coverage. Fence stripping runs before the comment pass so
a comment opener inside a fence stays literal. Two mutation tests (21
total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R8 finding — CommonMark fence-length closing rule (#757)
The fence stripper now tracks the opening run character and length: a
closer must be a same-character run at least that long with only
trailing whitespace, so a four-backtick fence demonstrating an inner
triple-backtick block is no longer closed early. Mutation test added
(22 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 23:57:07 +08:00
runtime graceful-degradation mechanisms is
[`shared/contracts/degradation_registry.json` ](../shared/contracts/degradation_registry.json ).
## Notes
1. Plugin installs namespace commands as `/academic-research-skills:ars-<mode>` ; a bare
`/ars-<mode>` alias also works on recent Claude Code versions — the exact minimum
version and the older-version behavior are documented in SETUP Method 0 (#633 ).
2. The write-scope guard needs a **real Python interpreter ** and a `bash` to run its
launcher; missing either produces a * defined degraded state * , never a block — see
the [environment degradations ](#environment-degradations-within-a-channel ) table.
The guard is optional subagent hardening; core skills are unaffected when it is
inactive (README Requirements).
3. Hooks and plugin agents are wired by the **plugin manifest ** (`hooks/hooks.json` ,
`agents/` , resolved via `CLAUDE_PLUGIN_ROOT` ). A skills-copy or repo-clone install
does not wire them: the `PreToolUse` write-scope guard and the SessionStart announce
do not run, and agent dispatch uses the in-skill prompt templates without the
frontmatter tools allowlist. A user may wire the hook into their own Claude Code
settings manually, at which point the note-2 conditions apply.
4. The allowlist's canonical contents live in the three plugin agents' frontmatter,
pinned in CI by `scripts/check_tools_allowlist.py` — this page deliberately does not
restate the list.
5. These features (e.g. the citation-verification gate CLI, the revision
token-conservation checker, the submission-package verifier, the PDF read preflight,
the cache commands — a non-exhaustive, growing set) shell out to Python scripts at
the repository root (`scripts/` , `shared/` ), not inside the four skill folders. They
need (a) a real Python interpreter and (b) the repo checkout present: automatic for
the plugin channel (the plugin root is the repo snapshot) and repo clones; for a
skills-copy install, keep the original clone — the copied skill folders alone cannot
run them. On Pi, they work if Python and the repo are present (`pi/README.md` ).
6. Note-5 conditions, plus a transport: provider API credentials and `curl` for the
general transports, or — for the citation-only calls — a Codex CLI
ChatGPT-subscription login (`ARS_CROSS_MODEL_TRANSPORT=codex` ). All transports sit
behind the same boundary defined in
[`shared/cross_model_verification.md` ](../shared/cross_model_verification.md ): the
user's **explicit consent per session ** — the `ARS_CROSS_MODEL` environment variable
is configuration, not consent. Unset, the feature is invisible and makes zero
network calls.
7. The MANDATORY checkpoints, integrity gates, and IRON RULE constraints are
**prompt-level, trust-based controls with audit trails ** , executed by the session
model following the skill instructions — not coercive runtime enforcement. Documented
overrides require recorded reasoning, and final integrity responsibility stays with
the human researcher (see the
[gap assessment §3 ](../audits/iso42001-spirit-gap-assessment-2026-08-17.md )).
This row says the * instructions * are present and active in the channel, nothing
stronger.
8. The SessionStart hook is launched through `bash` , so on Windows it needs Git Bash
(the same PowerShell limitation as the guard launcher); its update-reminder path
additionally needs `curl` , stays silent on any failure, and is disabled entirely by
`ARS_UPDATE_CHECK=0` (SETUP Method 0).
## Environment degradations within a channel
feat: register write-scope guard launcher degradations in degradation_registry.json (#769) (#792)
* feat: register write-scope guard launcher degradations in the degradation registry (#769)
The registry claims to index every graceful-degradation mechanism in the
suite, but hooks/run_guard.sh's documented degraded states had no rows,
and the #757 prose table in docs/CONTROL_AVAILABILITY.md stood up a
second, unpinned authority for those facts.
Four write_scope_guard_* rows added (no-python, no-git-bash,
no-timeout-binary, subprocess-misbehaves), each with verbatim D3
authority anchors into hooks/run_guard.sh + the README Requirements
bullet; pinned_by names scripts/test_run_guard_launcher.py where a
CI-executable pin exists (the Windows-without-Git-Bash path never
executes the launcher, so its row honestly carries no pin). Registry
1.2.0 -> 1.3.0; _EXPECTED_MECHANISMS updated in the same commit (D5
lock semantics). The CONTROL_AVAILABILITY degradations table now
declares itself a convenience summary backpointing at the registry.
Closes #769
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015NZwcSFBwiJBZEtsSTcCxq
* review: address codex findings on #769 — permission phrasing, no-timeout decision forwarding, launcher-internal failure coverage
- Rows no longer claim "writes are never blocked" or relitigate what an
'allow' decision would do: the launcher emits no permissionDecision,
so the session's normal permission rules still decide.
- The no-timeout row's terminal_policy_effect states that the healthy
watchdog fallback forwards the guard's real decision (including deny);
only an overrun resolves to pass-through.
- The misbehaves row now also covers the two remaining documented
launcher-internal degradations (SELF_DIR self-resolution failure and
the POSIX payload-length cap on multi-megabyte Writes), with verbatim
anchors; CHANGELOG + CONTROL_AVAILABILITY backpointer updated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015NZwcSFBwiJBZEtsSTcCxq
* review: round-2 codex findings on #769 — per-row quantifiers, actual validity-check shape, payload-edge honesty
- terminal_policy_effect now speaks per failure path, not "every degraded
path"; the no-Git-Bash row states the hook simply does not run.
- The misbehaves row names the launcher's ACTUAL validity check (a JSON
object carrying a top-level hookSpecificOutput key — deliberately
shallow, not full hook-schema validation).
- The multi-megabyte payload edge is recorded as a documented accepted,
untested case with no pinned outcome — no deterministic claim.
- The no_python row's authority anchor swaps to the no-permissionDecision
pass-through line (the launcher's disputed 'allow' comment is
pre-existing text this PR neither adds nor endorses).
- CONTROL_AVAILABILITY prose quantifier fixed to match ("none of which
ever blocks", with the no-timeout forwarding stated).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015NZwcSFBwiJBZEtsSTcCxq
* review: round-3 codex findings on #769 — payload edge split into its own no-pinned-outcome row
- write_scope_guard_payload_capacity_edge becomes a dedicated row whose
every field honestly declares "no pinned outcome" — the misbehaves
row's pass-through claims are now unconditionally true for its own
failure classes (registry 20 -> 21 rows, D5 lock updated).
- CONTROL_AVAILABILITY prose reworded: degraded states never INTRODUCE a
block; the no-timeout swap keeps the guard operating normally (real
decisions, including deny, still apply).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015NZwcSFBwiJBZEtsSTcCxq
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 12:54:36 +08:00
Independent of install channel, the write-scope guard has documented degraded states.
None of them * introduces * a block: launcher failure paths resolve to **pass-through ** ,
and a missing `timeout` binary is a bounding-mechanism swap under which the guard keeps
operating normally — its real decisions (including deny) still apply, with only an
overrun resolving to pass-through. The guard is an optional
docs: per-channel control-availability matrix (#757) (#768)
* docs: per-channel control-availability matrix (#757)
Add docs/CONTROL_AVAILABILITY.md — one row per enforcement mechanism,
one column per install channel (plugin / skills copy / repo clone /
Cowork / claude.ai Project / Claude Science / Pi), with honest
active / conditional / absent cells, per-channel notes citing the
existing scattered sources (README Requirements, SETUP methods,
pi/README.md, hooks/run_guard.sh), and the guard's environment
degradation table. Linked from README (Requirements + SETUP pointer)
and SETUP (Installation methods intro).
Evidence re-verified against the working tree: the channel set has
grown past the six named in the issue (SETUP now also documents
Cowork and the claude.ai 4a/4b split), so the matrix covers all
seven documented channels.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* refactor: apply /simplify pass + add CA-1..CA-3 defrift lint (#757)
Simplify round (4-agent review, findings deduped):
- Drop the 'How to read an integrity claim' section (it had already
drifted from the matrix) and the all-identical Upstream row; both
replaced by one legend sentence and one paragraph.
- Move channel-scoped caveats (Cowork / claude.ai / Claude Science / Pi)
from per-cell footnotes into a 'Channel-wide limitation' column of the
channel table; notes drop from 11 to 7.
- De-drift row labels: no inline allowlist contents (canonical list is
pinned by check_tools_allowlist.py), no exhaustive feature list, no
hard-coded Claude Code minimum version (lives in SETUP Method 0).
- README: single slimmed pointer (second link and both enumerations
removed); pointer mirrored to the four translated READMEs and
docs/SETUP.zh-TW.md.
- Degradations table scoped to actual guard degradations (the slash-form
version row was misfiled); registry backpointer added; guard-launcher
registry registration split to #769.
Lint (per the new-claim-surface-needs-lint-in-same-PR discipline):
- scripts/check_control_availability.py — CA-1 links/anchors resolve,
CA-2 every SETUP '### Method' heading reachable from the channel
table, CA-3 README + SETUP inbound links pinned. Cell semantics stay
owned by code review (degradation-registry posture).
- 9 mutation tests; wired into spec-consistency.yml + pytest manifest
(150 entries).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R1 findings — 4 P2 accuracy corrections (#757)
- SessionStart announce/update-reminder row: Conditional, not Active
(bash launcher on Windows needs Git Bash; reminder needs curl) — new
note 8.
- Cross-model note 6 no longer claims credentials+curl universally; the
citation-only Codex subscription transport is named as the alternative
transport behind the same consent boundary.
- Pi channel limitation reworded: the wrapper supplies no orchestration
but uses an installed Pi capability when available.
- 'Enforcement mechanisms' claim language aligned to 'controls' in the
purpose statement and all five README pointers (consistent with note
7's trust-based posture).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R2 findings — lint mis-pass cases + note-8 wording (#757)
- CA-1 link grammar accepts optional quoted titles so a titled dead
link cannot silently skip the check.
- CA-2 counts only fragments on links whose resolved destination IS
docs/SETUP.md — a same-slug anchor into a copied file no longer
satisfies method coverage.
- CA-3 checks resolved link destinations, not a filename substring — a
label that keeps the filename while the target moves now fails.
- Note 8: singular SessionStart hook (hooks.json defines one; the
announce script runs the update check internally).
- 3 new mutation tests pinning each mis-pass case (12 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R3 finding — commented-out markdown counts for nothing (#757)
Strip HTML comments before extracting links and headings in all three
invariants: a commented-out inbound link no longer satisfies CA-3, a
commented-out SETUP method heading no longer demands CA-2 coverage, and
a commented-out dead link no longer fires CA-1. Two mutation tests pin
both directions (14 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R4 finding — GFM type-2 HTML-block semantics (#757)
A line beginning with <!-- opens a raw-HTML block through the --> line
(including trailing text on the closing line) or to EOF if unclosed;
nothing on those lines renders. The comment stripper now models that
line-level behavior before the inline-span strip, so a link after -->
on a comment line cannot satisfy CA-3 and a dead link after an unclosed
comment cannot fire CA-1. Two mutation tests pin both (16 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* test: fix R4 mutation scenario — line-start vs inline comment (#757)
The previous commit's CA-3 HTML-block test inserted the comment mid-line
(inside the blockquote), where GFM renders the link normally and the
lint correctly stays quiet — the test scenario was wrong, not the lint.
Replaced with a whole-line mutation that actually begins with <!--, and
added the inline-comment symmetry case (link still renders → CA-3
satisfied). 17 tests green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R5 finding — block-quoted HTML-block lines (#757)
The type-2 HTML-block rule applies to block-quote content: the stripper
now looks through leading '> ' markers before the line-start test, so
'> <!-- note --> [link]' cannot satisfy CA-3. Deeper CommonMark
laminations are declared out of scope in the docstring (the surfaces do
not use them; a full parser is out of proportion for a maintainer-slip
guard). 18 tests green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R6 finding — repo-containment on CA-1 targets (#757)
A relative link that resolves outside the repository root now fails
CA-1 even when the host path exists — an over-deep ../.. slip must not
be masked by an existing host file. Mutation test added (19 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R7 finding — fenced code excluded from extraction (#757)
Fenced code regions render literally, and README/SETUP use fences
today, so they are in-scope: a link inside a fence no longer satisfies
CA-3, and a sample "### Method" heading inside a SETUP fence no longer
demands CA-2 coverage. Fence stripping runs before the comment pass so
a comment opener inside a fence stays literal. Two mutation tests (21
total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R8 finding — CommonMark fence-length closing rule (#757)
The fence stripper now tracks the opening run character and length: a
closer must be a same-character run at least that long with only
trailing whitespace, so a four-backtick fence demonstrating an inner
triple-backtick block is no longer closed early. Mutation test added
(22 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 23:57:07 +08:00
hardening layer, and a broken guard must not lock a user out of their own files
(maintainer decision recorded in `hooks/run_guard.sh` ; user-facing summary in the
feat: register write-scope guard launcher degradations in degradation_registry.json (#769) (#792)
* feat: register write-scope guard launcher degradations in the degradation registry (#769)
The registry claims to index every graceful-degradation mechanism in the
suite, but hooks/run_guard.sh's documented degraded states had no rows,
and the #757 prose table in docs/CONTROL_AVAILABILITY.md stood up a
second, unpinned authority for those facts.
Four write_scope_guard_* rows added (no-python, no-git-bash,
no-timeout-binary, subprocess-misbehaves), each with verbatim D3
authority anchors into hooks/run_guard.sh + the README Requirements
bullet; pinned_by names scripts/test_run_guard_launcher.py where a
CI-executable pin exists (the Windows-without-Git-Bash path never
executes the launcher, so its row honestly carries no pin). Registry
1.2.0 -> 1.3.0; _EXPECTED_MECHANISMS updated in the same commit (D5
lock semantics). The CONTROL_AVAILABILITY degradations table now
declares itself a convenience summary backpointing at the registry.
Closes #769
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015NZwcSFBwiJBZEtsSTcCxq
* review: address codex findings on #769 — permission phrasing, no-timeout decision forwarding, launcher-internal failure coverage
- Rows no longer claim "writes are never blocked" or relitigate what an
'allow' decision would do: the launcher emits no permissionDecision,
so the session's normal permission rules still decide.
- The no-timeout row's terminal_policy_effect states that the healthy
watchdog fallback forwards the guard's real decision (including deny);
only an overrun resolves to pass-through.
- The misbehaves row now also covers the two remaining documented
launcher-internal degradations (SELF_DIR self-resolution failure and
the POSIX payload-length cap on multi-megabyte Writes), with verbatim
anchors; CHANGELOG + CONTROL_AVAILABILITY backpointer updated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015NZwcSFBwiJBZEtsSTcCxq
* review: round-2 codex findings on #769 — per-row quantifiers, actual validity-check shape, payload-edge honesty
- terminal_policy_effect now speaks per failure path, not "every degraded
path"; the no-Git-Bash row states the hook simply does not run.
- The misbehaves row names the launcher's ACTUAL validity check (a JSON
object carrying a top-level hookSpecificOutput key — deliberately
shallow, not full hook-schema validation).
- The multi-megabyte payload edge is recorded as a documented accepted,
untested case with no pinned outcome — no deterministic claim.
- The no_python row's authority anchor swaps to the no-permissionDecision
pass-through line (the launcher's disputed 'allow' comment is
pre-existing text this PR neither adds nor endorses).
- CONTROL_AVAILABILITY prose quantifier fixed to match ("none of which
ever blocks", with the no-timeout forwarding stated).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015NZwcSFBwiJBZEtsSTcCxq
* review: round-3 codex findings on #769 — payload edge split into its own no-pinned-outcome row
- write_scope_guard_payload_capacity_edge becomes a dedicated row whose
every field honestly declares "no pinned outcome" — the misbehaves
row's pass-through claims are now unconditionally true for its own
failure classes (registry 20 -> 21 rows, D5 lock updated).
- CONTROL_AVAILABILITY prose reworded: degraded states never INTRODUCE a
block; the no-timeout swap keeps the guard operating normally (real
decisions, including deny, still apply).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015NZwcSFBwiJBZEtsSTcCxq
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 12:54:36 +08:00
README Requirements bullet). This table is a convenience summary, not a second
authority: the indexed rows are the `write_scope_guard_*` mechanisms in
[`shared/contracts/degradation_registry.json` ](../shared/contracts/degradation_registry.json )
(#769 ), whose anchors into `hooks/run_guard.sh` are lint-pinned, and which also cover
two states this table omits — guard subprocess misbehaves or the launcher fails
internally (→ pass-through), and the documented multi-megabyte payload edge (an
accepted, untested case with no pinned outcome):
docs: per-channel control-availability matrix (#757) (#768)
* docs: per-channel control-availability matrix (#757)
Add docs/CONTROL_AVAILABILITY.md — one row per enforcement mechanism,
one column per install channel (plugin / skills copy / repo clone /
Cowork / claude.ai Project / Claude Science / Pi), with honest
active / conditional / absent cells, per-channel notes citing the
existing scattered sources (README Requirements, SETUP methods,
pi/README.md, hooks/run_guard.sh), and the guard's environment
degradation table. Linked from README (Requirements + SETUP pointer)
and SETUP (Installation methods intro).
Evidence re-verified against the working tree: the channel set has
grown past the six named in the issue (SETUP now also documents
Cowork and the claude.ai 4a/4b split), so the matrix covers all
seven documented channels.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* refactor: apply /simplify pass + add CA-1..CA-3 defrift lint (#757)
Simplify round (4-agent review, findings deduped):
- Drop the 'How to read an integrity claim' section (it had already
drifted from the matrix) and the all-identical Upstream row; both
replaced by one legend sentence and one paragraph.
- Move channel-scoped caveats (Cowork / claude.ai / Claude Science / Pi)
from per-cell footnotes into a 'Channel-wide limitation' column of the
channel table; notes drop from 11 to 7.
- De-drift row labels: no inline allowlist contents (canonical list is
pinned by check_tools_allowlist.py), no exhaustive feature list, no
hard-coded Claude Code minimum version (lives in SETUP Method 0).
- README: single slimmed pointer (second link and both enumerations
removed); pointer mirrored to the four translated READMEs and
docs/SETUP.zh-TW.md.
- Degradations table scoped to actual guard degradations (the slash-form
version row was misfiled); registry backpointer added; guard-launcher
registry registration split to #769.
Lint (per the new-claim-surface-needs-lint-in-same-PR discipline):
- scripts/check_control_availability.py — CA-1 links/anchors resolve,
CA-2 every SETUP '### Method' heading reachable from the channel
table, CA-3 README + SETUP inbound links pinned. Cell semantics stay
owned by code review (degradation-registry posture).
- 9 mutation tests; wired into spec-consistency.yml + pytest manifest
(150 entries).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R1 findings — 4 P2 accuracy corrections (#757)
- SessionStart announce/update-reminder row: Conditional, not Active
(bash launcher on Windows needs Git Bash; reminder needs curl) — new
note 8.
- Cross-model note 6 no longer claims credentials+curl universally; the
citation-only Codex subscription transport is named as the alternative
transport behind the same consent boundary.
- Pi channel limitation reworded: the wrapper supplies no orchestration
but uses an installed Pi capability when available.
- 'Enforcement mechanisms' claim language aligned to 'controls' in the
purpose statement and all five README pointers (consistent with note
7's trust-based posture).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R2 findings — lint mis-pass cases + note-8 wording (#757)
- CA-1 link grammar accepts optional quoted titles so a titled dead
link cannot silently skip the check.
- CA-2 counts only fragments on links whose resolved destination IS
docs/SETUP.md — a same-slug anchor into a copied file no longer
satisfies method coverage.
- CA-3 checks resolved link destinations, not a filename substring — a
label that keeps the filename while the target moves now fails.
- Note 8: singular SessionStart hook (hooks.json defines one; the
announce script runs the update check internally).
- 3 new mutation tests pinning each mis-pass case (12 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R3 finding — commented-out markdown counts for nothing (#757)
Strip HTML comments before extracting links and headings in all three
invariants: a commented-out inbound link no longer satisfies CA-3, a
commented-out SETUP method heading no longer demands CA-2 coverage, and
a commented-out dead link no longer fires CA-1. Two mutation tests pin
both directions (14 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R4 finding — GFM type-2 HTML-block semantics (#757)
A line beginning with <!-- opens a raw-HTML block through the --> line
(including trailing text on the closing line) or to EOF if unclosed;
nothing on those lines renders. The comment stripper now models that
line-level behavior before the inline-span strip, so a link after -->
on a comment line cannot satisfy CA-3 and a dead link after an unclosed
comment cannot fire CA-1. Two mutation tests pin both (16 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* test: fix R4 mutation scenario — line-start vs inline comment (#757)
The previous commit's CA-3 HTML-block test inserted the comment mid-line
(inside the blockquote), where GFM renders the link normally and the
lint correctly stays quiet — the test scenario was wrong, not the lint.
Replaced with a whole-line mutation that actually begins with <!--, and
added the inline-comment symmetry case (link still renders → CA-3
satisfied). 17 tests green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R5 finding — block-quoted HTML-block lines (#757)
The type-2 HTML-block rule applies to block-quote content: the stripper
now looks through leading '> ' markers before the line-start test, so
'> <!-- note --> [link]' cannot satisfy CA-3. Deeper CommonMark
laminations are declared out of scope in the docstring (the surfaces do
not use them; a full parser is out of proportion for a maintainer-slip
guard). 18 tests green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R6 finding — repo-containment on CA-1 targets (#757)
A relative link that resolves outside the repository root now fails
CA-1 even when the host path exists — an over-deep ../.. slip must not
be masked by an existing host file. Mutation test added (19 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R7 finding — fenced code excluded from extraction (#757)
Fenced code regions render literally, and README/SETUP use fences
today, so they are in-scope: a link inside a fence no longer satisfies
CA-3, and a sample "### Method" heading inside a SETUP fence no longer
demands CA-2 coverage. Fence stripping runs before the comment pass so
a comment opener inside a fence stays literal. Two mutation tests (21
total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
* fix: close codex R8 finding — CommonMark fence-length closing rule (#757)
The fence stripper now tracks the opening run character and length: a
closer must be a same-character run at least that long with only
trailing whitespace, so a four-backtick fence demonstrating an inner
triple-backtick block is no longer closed early. Mutation test added
(22 total).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EosnA4RdUYgbF2KmZ1DTmc
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 23:57:07 +08:00
| Condition | Behavior |
|---|---|
| No real Python found (Git Bash / POSIX shell present) | Guard silently no-ops (pass-through); core skills unaffected. On Windows, the 0-byte Microsoft Store `python3` stub is rejected, not mistaken for Python. |
| Windows without Git Bash | Claude Code falls back to PowerShell, which cannot run the `.sh` launcher: guard inactive, and the `PreToolUse` hook logs an error per call (accepted degradation — noisy, never blocking). |
| No `timeout` binary | Portable background-watchdog fallback with the same wall-clock bound and the same pass-through-on-overrun posture. |