# ARS v3.6.8 (roadmap slot) — Trust Provenance & Drift Transparency

> **Status (2026-05-05 banner):** **DESIGN-ONLY, NOT YET IMPLEMENTED.** This spec occupies ROADMAP §3.6.8 ("Trust provenance & drift transparency"). Filename and roadmap slot retain **v3.6.8**.
>
> **Release semver:** **`v3.7.1`** (settled 2026-05-07 round-1 codex F-006 amend; supersedes initial Q7 `v3.6.9`). Reason: main shipped v3.7.0 (plugin packaging) on 2026-05-05; tagging v3.6.9 after v3.7.0 would mean a maintenance-line backport, not a forward release. Trust-chain protections D1–D5 are forward features on the v3.7 line, so v3.7.1 is the correct semver. Roadmap slot stays `v3.6.8` and filename unchanged per the roadmap-slot-vs-release-semver decoupling pattern (precedent: `2026-04-22-ars-v3.7.3-reading-check-probe-design.md` filename retains roadmap slot v3.7.3 while actual release tag is v3.5.1).
>
> The substance of this spec — five upstream-trust-chain protections (D1–D5) — is unchanged from the 2026-04-30 draft. Sequencing per ROADMAP §3.6.8: v3.6.7 follow-up shipped 2026-05-05 (Step 6 + Step 8 = Phase 6.8 complete on main `a3b95fd`, PR #67), so v3.6.8 sequencing constraint is now **CLEARED**.
>
> ---
>
> **Brainstorm Decision Record (2026-05-07, 8-round Q&A — supersedes §9 Open Questions where overlapping):**
>
> | # | Decision | Spec sections affected | Cascade note |
> |---|---|---|---|
> | Q1 | Ship D1–D5 as one release (no D1+D2 first / no per-pattern split) | §4 (all 6 steps stay in one release), §5 acceptance criteria | None |
> | Q2 | `human_read_source: true` set via **explicit user command** (e.g. `/ars-mark-read <refcode>`); no inference, no session-activity heuristic. **Round-1 codex F-005 amend (2026-05-07)**: command writes to a peer file `<session>_human_read_log.yaml` (or session-stable user-owned location), NOT into `literature_corpus[]` schema (which is adapter-owned with `additionalProperties: false` and forbids consumer-agent mutation per `academic-pipeline/references/literature_corpus_consumers.md`). Orchestrator merges peer file at frontmatter-read time. | §3.1 frontmatter (clarify `human_read_source` is *derived*, not a literal field on the entry), §3.3 LOW WARN row, **NEW** §3.6 Human-Read Signal Protocol | Adds new subsection; closes §9 Q4 |
> | Q3 | Drift Log = **peer file** `<session>_drift_log.md`. Schema 9 untouched in v3.6.9 | §3.4 + §9 Q1 settled (no Schema 9 amendment in this release) | None |
> | Q4 | **Superseded by Q8 below** (originally "every emission" — replaced by per-stage hybrid) | §3.3 control flow, §9 Q3 | See Q8 |
> | Q5 | D2 Scope Report = **additive append** to v3.6.7 `codex_audit_multifile_template.md`, not rewrite. Preserves v3.6.7's 18-codex-round invariants. | §3.2 + §4 Step 2 | Acceptance must include regression: v3.6.7 `check_v3_6_7_pattern_protection.py` lint + 25 INV mutation tests still PASS on modified template. Add §3.7 cross-reference table covering v3.6.7 §3.7 invariant family A-F overlap audit |
> | Q6 | D5 retrieval fallback chain = **default ON**, no env flag. Backward compat via early-exit on first content-match success (Risk 4 mitigation already specified). **Round-1 codex F-007 amend (2026-05-07)**: default-ON applies to mechanical fallback steps only (publisher_direct, wayback_cdx_search, author_personal_website, scholar_all_versions, oa_aggregators). `researchgate_request` is **human-handoff** (not in the auto-chain): on chain exhaustion before RG, retrieval emits a `pending_user_action: researchgate_request_<refcode>` log entry; user manually requests via author RG profile and resumes. | §3.5 (split chain into 5 auto + 1 human-handoff), §8 Risk 4 (add explicit "no opt-out flag" rationale + RG human-handoff exception), §9 Q2 settled | None |
> | Q7 | Release tag = `v3.7.1` (round-1 codex F-006 amend). Roadmap slot stays `v3.6.8`. | This banner + filename unchanged. Cross-doc sweep: any reference to "v3.6.8" as ship tag → "v3.7.1 (roadmap slot v3.6.8)" | All `## v3.6.x` headers in CHANGELOG/README/`.claude/CLAUDE.md` for the trust-chain release become `## v3.7.1`. Plugin manifest version bumps to 3.7.1 |
> | Q8 | D3 Cite-Time Provenance Check = **hybrid**: (a) downstream agents (`synthesis_agent`, `draft_writer_agent`, `report_compiler_agent`) emit author-year citation followed by hidden refcode comment `Smith (2024) <!--ref:smith2024-->` at every citation emission **without reading frontmatter** (agents stay in-prompt-context, never reference orchestrator/stage gate, never resolve markers — strict partial-inversion discipline per round-1 codex F-004); (b) finalizer reads frontmatter, applies §3.3 4-cell matrix, replaces hidden comment-marker with one of: `<!--ref:slug ok-->` (no warning), `<!--ref:slug LOW-WARN-->` (adds to per-section pre-finalization checklist), `[UNVERIFIED CITATION — AI HAS NOT CROSS-CHECKED]<!--ref:slug-->` (MED WARN), `[UNVERIFIED CITATION — NO ORIGINAL]<!--ref:slug-->` (HIGH WARN); (c) `formatter_agent` hard-gates on any unresolved `<!--ref:` comment whose status is not `ok` or LOW-WARN-acknowledged, AND on any `[UNVERIFIED CITATION` marker. **Round-1 codex F-001 amend (2026-05-07)**: finalizer location is mode-dependent — `academic-pipeline` mode uses `pipeline_orchestrator_agent` at stage transition (architecturally mirrors v3.6.7 Step 6 audit_artifact gate); standalone `academic-paper` and `deep-research` modes use **inline finalize-on-deliverable** (a per-skill `cite_provenance_finalizer_agent` invoked at deliverable emission boundary, not on every cite emission). Both paths converge on the same matrix output; the standalone path is documented in §3.3 with mode-dependence table. **Round-1 codex F-002 amend (2026-05-07)**: target agent is `formatter_agent` (the actual repo path), not `format_converter_agent` (which does not exist). | §3.3 control flow rewrite (3 sub-flows: pipeline mode, standalone academic-paper, standalone deep-research) + §4 Step 3 split into 3a agent placeholder spec / 3b orchestrator finalize spec (pipeline) / 3c standalone finalize spec / 3d formatter hard-gate spec | Q4 ("every emission") superseded — placeholder is per-emission, finalization is per-stage (pipeline) or per-deliverable-emission (standalone). UX trade-off: user does not see resolved markers in-session until finalize fires; mitigated by finalize firing at every checkpoint (pipeline) or at deliverable boundary (standalone) |
>
> **Where to next:** This banner records contract-level decisions. The spec body (§3-§9) has not yet been edited to match. The intended workflow is to run **codex review round-1** against this banner + unedited body and let the cross-model audit surface every drift, cascade, and §9 Open Question that the 8-round Q&A has now closed or shifted. Memory: `feedback_codex_iterative_spec_review_to_zero.md` discipline (run rounds until 0 finding before impl).
>
> ---
>
> **Round-1 Codex Amend (2026-05-07, gpt-5.5 xhigh, 7 P1 + 11 P2 + 3 P3):**
>
> Round-1 was run against the brainstorm-amended banner + unedited body. Three architectural P1 findings (F-001 / F-003 / F-006) re-opened brainstorm; their decisions are folded into the Q-table above (Q2 / Q6 / Q7 / Q8 amend cells). The remaining 4 P1 findings are surgical:
>
> | F-id | Finding | Resolution (folded into surgical edits, not re-brainstormed) |
> |---|---|---|
> | F-001 | Q8 hybrid breaks in standalone modes (no `pipeline_orchestrator_agent`) | Q8 amend: pipeline mode uses orchestrator-at-stage-gate; standalone modes use inline finalize-on-deliverable via per-skill `cite_provenance_finalizer_agent` |
> | F-002 | Hard-gate target `format_converter_agent` does not exist; actual repo path is `formatter_agent` | Spec body sweep: replace `format_converter_agent` → `formatter_agent` everywhere (§3.3, §4 Step 3, §5 acceptance criteria) |
> | F-003 | Spec assumes `[refcode]` emissions but `draft_writer_agent` emits `Smith (2024)` author-year | Q8 amend: agent emits two-layer citation `Smith (2024) <!--ref:slug-->` (visible author-year + hidden refcode HTML comment); finalizer scans hidden comment, formatter strips on render |
> | F-004 | Q8 risks re-opening v3.6.7 fake-audit prompt leak (agents knowing about orchestrator finalize) | Q8 amend: agents must "emit placeholder, never read frontmatter, never mention orchestrator/stage gate, never resolve/remove markers." v3.6.9-specific lint manifest (NOT widening v3.6.7 frozen `_v3_6_7_inversion_manifest.json` scope per `feedback_codex_iterative_spec_review_to_zero.md` lessons learned). Add new `scripts/check_v3_6_8_pattern_protection.py` |
> | F-005 | `human_read_source` has no safe write location (`literature_corpus[]` is `additionalProperties: false` adapter-owned) | Q2 amend: `/ars-mark-read <refcode>` writes to peer file `<session>_human_read_log.yaml`; orchestrator merges at frontmatter-read time. `human_read_source` is *derived* not stored on entry |
> | F-006 | v3.6.9 tag is maintenance-line backport given main is at v3.7.0 | Q7 amend: release tag = `v3.7.1` (forward release on v3.7 line); filename / roadmap slot stays v3.6.8 |
> | F-007 | ResearchGate Request Full-Text in default-ON auto-chain creates unsafe automated outreach | Q6 amend: 5 auto-chain steps + RG as human-handoff (pending_user_action log) |
>
> **P2 (11) and P3 (3) findings**: documented in PR #74 round-1 codex review output (full transcript retained in maintainer's local session log; key cascades summarized below). All are cascade or doc-sweep findings addressed by surgical edits to §3.1 / §3.2 / §3.3 / §3.5 / new §3.6 / new §3.7 / §4 Step 0–6 / §5 acceptance / §6 / §7 / §8 / §9 in this same PR (not deferred). Round-2 codex review will run after surgical edits to confirm 0-finding convergence before implementation.
>
> ---

**Status:** Design — spec input from real-world chapter-writing session, brainstorm-record-amended 2026-05-07, round-1 codex amend 2026-05-07
**Date:** 2026-04-30 (substance) / 2026-05-07 (brainstorm + round-1 codex decisions)
**Target release:** **v3.7.1** (settled 2026-05-07 round-1 codex F-006 amend; roadmap slot v3.6.8)
**Scope:** Pipeline-wide hallucination defense at the **trust-claim layer** (frontmatter granularity, audit scope disclosure) and **session transparency layer** (drift logging, cite-time verification check, retrieval fallback). Complements v3.6.7 downstream-agent pattern protection by addressing the **upstream trust-chain** between user, source artifacts, and AI-produced descriptions.

---

## 1. Background

A 2026-04-30 production session (Phase 1+2+3 outputs already at V2_CLEAN per v3.6.5/v3.6.6 standard) revealed a class of **silent over-claim** that the downstream-agent pattern protection layer does not catch.

The user, an experienced QA/AI-writing practitioner, repeatedly **left the pipeline phase** to manually verify entries against original PDFs. This was not user-flow noise; it was rational defensive behavior in response to LLM hallucination risk. Each manual return surfaced new findings:

- `bibliography_v2.md` itself contained a **fabricated quote** attributed to D14 (OECD/UNESCO 2005) that does not appear in the retrieved PDF
- F1 Becker (2013) and F4 UWN (2012) entries cited **wrong case lists** (Malaysia/Dubai/Fiji) when the actual articles concerned a **Singapore IBC cluster**
- F3 Yale Daily News entry cited **wrong author + wrong date** (2024-09-23 community-reaction piece) when the load-bearing source is a 2021-09-07 announcement-aftermath article by a different reporter
- D13 INQAAHE ISG was paraphrased as "discipline-specific thematic standards" when the actual ISG architecture is **QA-context modules**
- G4 SEAMEO RIHED 2012 attribution had the **regional QA picture inverted**
- The Indonesian decree arc cited **the wrong Permendikbudristek as statutory anchor**, missing PMu 53/2023 entirely until the user retrieved the correct PDF

Three observations follow:

**Observation 1 — Derivative pollution.** The bibliography file (a derivative artifact AI produced earlier) was treated as ground truth in downstream entries. Each entry's frontmatter carried a `verified: <date>` field that conflated three distinct trust strengths: (a) AI viewed the entry .md, (b) AI cross-checked entry .md against the derivative bibliography, (c) AI cross-checked entry .md against the original publication PDF. To the user, `verified: 2026-04-30` reads as "this source is safe to cite." The conflation is a silent over-claim that scales hallucination risk into chapter prose.

**Observation 2 — Audit scope blind spot.** Three rounds of cross-model codex audit reported "ADDRESSED" status on the entry corpus. Coverage analysis after the fact showed the audit could only verify against original PDF for ~22 of ~53 entries (those with retrieved sources). The remaining ~31 entries were "verified" only against the derivative bibliography — i.e., the audit confirmed internal consistency of two same-source artifacts, not correctness against original publications. The audit pipeline did not disclose this scope coverage gap, and the user almost moved into chapter prose under the false confidence that the corpus was uniformly verified.

**Observation 3 — Phase drift as healthy signal.** The user's repeated phase departures (chapter drafting → retrieval → metadata audit → intake) were not pipeline-discipline failures. They were the only mechanism that surfaced the v2 fabrications, the wrong case lists, and the missing statutory anchor. **A pipeline design that nudges the user to "stay on track" would have suppressed the very behavior that caught the hallucinations.** The intervention surface should be transparency (let the user reconstruct their drift trajectory after the session) rather than enforcement (interrupting drift mid-session).

The lesson is that ARS pipeline ship-quality is bounded not only by the weakest downstream agent but also by **the granularity of trust claims** (frontmatter), **the honesty of audit reports** (scope disclosure), and **the user's ability to audit their own session trajectory** (drift transparency). v3.6.7 hardened agents against producing new hallucinations during their own work; v3.6.8 hardens the **trust-chain layer** that decides whether prior content is safe to consume downstream.

---

## 2. Goal & Non-Goals

### 2.1 Goal

Codify five upstream-trust-chain protections into ARS spec, with prompt-level integration into `bibliography_agent` and orchestrator layers, plus tooling for retrieval pipeline robustness. Target outcome: end-of-pipeline deliverables carry an **auditable trust chain** from final claim back to either (a) original-source verification or (b) explicit unverified-flag, with no `verified` claim stronger than the underlying evidence supports.

### 2.2 Non-Goals (out of v3.7.1 scope)

- No keep-on-track enforcement. Drift is healthy; transparency is the intervention surface.
- No new pipeline phase. Mechanisms attach to existing agents and orchestrator.
- No mandatory user blocking. Cite-time provenance check is **warn-only** (consistent with the advisory-not-blocking precedent set by v3.5 Collaboration Depth Observer).
- No automated source acquisition for paywalled material. Retrieval fallback chain is for OA / archived / author-self-hosted sources only.

---

## 3. Pattern Inventory

### 3.1 D1 — Frontmatter trust-strength conflation

A bibliography entry carries `verified: <date>` (or equivalent single field) that does not distinguish between (a) entry-self-consistency, (b) entry-vs-derivative-bibliography consistency, (c) entry-vs-original-source verification. Downstream agents and human readers treat all three as equivalent confidence.

**Mechanism:** `bibliography_agent` and downstream entry writers emit a single `verified` field after performing whichever check is available. When original source is not retrieved, the field is still emitted, indicating only (a) or (b) but reading as (c).

**Protection:** Frontmatter schema must split into orthogonal fields. **Two storage layers:** (a) the existing `literature_corpus_entry.schema.json` carries the seven adapter-owned / AI-owned fields below; (b) the new peer file `<session>_human_read_log.yaml` (per §3.6) carries user-owned `human_read_source` markers as a session-scoped derivative that the finalizer joins at frontmatter-read time. This split honors the v3.6.5 Iron Rule "no consumer-side corpus mutation" (`literature_corpus[]` stays adapter-owned with `additionalProperties: false`) while still surfacing the `human_read_source: true | false` semantic at finalizer / audit / cite-time matrix lookup.

```yaml
# Stored on the entry (literature_corpus_entry.schema.json — adapter or AI writes):
source_acquired: true | false           # Original PDF/HTML in repo
source_acquisition_date: <ISO 8601>     # When acquired
source_acquisition_path: <relative path># Where it lives
source_verified_against_original: true | false  # AI cross-checked against original
source_verification_method: codex_audit | manual_grep | vision_check | none
description_source: original_pdf | bibliography_v<n> | secondary_summary
description_last_audit: <round_id> | none

# Derived at read-time from peer file <session>_human_read_log.yaml (§3.6):
human_read_source: true | false         # USER explicitly ran /ars-mark-read <slug>
human_read_at: <ISO 8601> | null        # When the mark-read command fired
```

Three firm rules (per round-1 codex F-005 amend, three rules total):
- `source_verified_against_original: true` REQUIRES `source_acquired: true` AND `source_verification_method` ∈ `{codex_audit, manual_grep, vision_check}` (round-2 R2-007 amend: `none` is enumerated but is forbidden in conjunction with `source_verified_against_original: true`; the rule "non-empty" was insufficient because `none` is a non-empty string. Lint must enforce the affirmative-method enumeration, not just non-emptiness.)
- `source_acquired: false` REQUIRES `description_last_audit: none` (no original means audit cannot be substantive). Lint must enforce.
- `human_read_source` is **NEVER stored on the entry** — adapters and consumer agents MUST NOT emit it as part of the entry. The field is computed at read-time by joining `<session>_human_read_log.yaml` against the entry's `citation_key`. Lint must reject entries that ship a literal `human_read_source` field. (Rationale: `literature_corpus_entry.schema.json` is `additionalProperties: false` and adapter-owned per `academic-pipeline/references/literature_corpus_consumers.md`; mutating it from a consumer would break the v3.6.5 corpus-consumer protocol.)

`bibliography_agent` prompt must specify these fields with examples, plus a refusal rule: when source is not retrieved, agent MUST NOT emit `source_verified_against_original: true` regardless of internal-consistency checks performed. The agent must also NOT emit `human_read_source` — that field is set only by the user-issued `/ars-mark-read` command (see §3.6).

### 3.2 D2 — Audit scope coverage non-disclosure

A cross-model audit (codex round) reports "PASSED" or "ADDRESSED" without disclosing how many corpus entries were independently verifiable (had retrieved source) versus how many were only self-consistency-checked (no retrieved source, audit fell back to derivative comparison).

**Mechanism:** Audit reports are written as global pass/fail summaries. Coverage breakdown is computable from frontmatter (count entries with `source_acquired: true` vs `false`) but is not surfaced in the audit report header.

**Protection:** Audit report template (in `shared/templates/codex_audit_multifile_template.md` and any subsequent codex audit prompt) must require a Section 0 **Scope Report** block. Per round-1 codex Q5 amend (round-2 R2-008 polish), the Scope Report is added as an **additive prepend** to the v3.6.7 template, NOT a rewrite: it precedes the existing Sections 1–7 as a new Section 0 without renumbering them. The 7 existing v3.6.7 audit dimensions and the §3 "Patterns surfaced" Section 4(f) check stay byte-equivalent in title, ordinal label, and order. See §3.7 for the v3.6.7 invariant overlap audit confirming this preserves INV-1 / INV-2 / INV-3 (`check_v3_6_7_pattern_protection.py`) plus families A–F (`check_audit_artifact_consistency.py`).

```markdown
## Codex Audit Round N — Scope Report

**Total entries audited:** <N_total>
**Entries with retrieved original source:** <N_with_source> (verified against original publication)
**Entries description-only (no retrieved source):** <N_without_source> (verified only against derivative bibliography or self-consistency)

**Audit scope warning:** <N_without_source> entries cannot be independently verified by this audit round. Their `verified` status reflects internal consistency between entry .md and the derivative bibliography source, NOT correctness against the original publication. These entries should be treated as **unverifiable until original sources are retrieved**.

**Affected refcodes (description-only):** <comma-separated list>
```

Two firm rules:
- The Scope Report block must appear **before** any pass/fail summary
- Aggregate "PASSED" status MUST be split into:
  - `verified-against-source: PASS | FAIL` (over the retrieved-source subset)
  - `description-internally-consistent: PASS | FAIL` (over the non-retrieved subset)
  - `unaudited-due-to-missing-source: <count>` (always reported, never hidden)

The combined-aggregate "PASSED" verb is forbidden in audit summary.

### 3.3 D3 — Cite-time trust-chain non-check

When narrative-construction agents (`synthesis_agent`, `draft_writer_agent`, `report_compiler_agent`) emit a citation, no automated provenance check fires against the cited entry's frontmatter. The agent assumes the entry exists and is citable, and produces declarative claims about its content.

**Mechanism:** Agent prompts treat the bibliography as an opaque context. When a citation is emitted, no downstream layer intercepts to verify trust-chain status of the underlying entry.

**Protection (3-step pipeline; mode-dependent finalizer location):**

**Step 1 — Agent emits two-layer citation (uniform across all modes).** Downstream agents emit citations as `<author-year visible form>` immediately followed by a hidden HTML comment `<!--ref:<slug>-->`, where `<slug>` is the `citation_key` from the frontmatter (e.g. `Smith (2024) <!--ref:smith2024-->` or `(Smith, 2024)<!--ref:smith2024-->`). Agents emit this two-layer form at every citation emission **without reading the frontmatter** — they only know the slug from the corpus context already in their prompt. Agents must NOT mention the finalizer, the orchestrator, or stage gates (strict partial-inversion discipline per round-1 codex F-004; v3.6.7 Pattern C3 attack-surface stays closed). The hidden comment is invisible in markdown rendering but mechanically extractable.

**Step 2 — Finalizer applies the 4-cell matrix and resolves the hidden comment (mode-dependent location):**

| Mode | Finalizer agent | Trigger boundary | Hard-gate agent |
|---|---|---|---|
| `academic-pipeline` | `pipeline_orchestrator_agent` | Stage transition (mirrors v3.6.7 Step 6 audit_artifact gate) | `formatter_agent` (academic-paper terminal) |
| `academic-paper` standalone | `cite_provenance_finalizer_agent` (new, per-skill) | After `draft_writer_agent` deliverable emission, before `formatter_agent` | `formatter_agent` |
| `deep-research` standalone | `cite_provenance_finalizer_agent` (new, per-skill) | **After `report_compiler_agent` deliverable emission**, before terminal hard-gate (round-2 R2-001 amend: deep-research has no `formatter_agent`; `report_compiler_agent` is its compilation step, so finalizer must run AFTER compilation, not before) | **`cite_provenance_terminal_gate_agent`** (new, deep-research per-skill; round-3 R3-001 amend): a separate single-purpose agent that runs AFTER `cite_provenance_finalizer_agent`, reads the resolved draft, and refuses to emit the final report if any `[UNVERIFIED CITATION ...]` or unresolved `<!--ref:slug-->` (status neither `ok` nor LOW-WARN-acknowledged) remains. **NOT a re-invocation of `report_compiler_agent`** (that would require two-pass dispatch and conflict with the v3.6.7 partial-inversion discipline; `report_compiler_agent` must NEVER read frontmatter or resolve markers, including a hypothetical second pass). The terminal-gate agent never compiles; it only inspects + emits/refuses. |

The finalizer reads `<!--ref:<slug>-->` comments, dereferences `<slug>` against frontmatter (entry from `literature_corpus[]` joined with peer file `<session>_human_read_log.yaml` from §3.6 — see Q2 amend), and applies this matrix to mutate the comment in place:

| `source_acquired` | `source_verified_against_original` | `human_read_source` | Resolution |
|-------------------|-----------------------------------|---------------------|--------|
| false             | —                                  | —                   | **HIGH WARN**: cite has no original source on file. Replace `<!--ref:slug-->` with `[UNVERIFIED CITATION — NO ORIGINAL]<!--ref:slug-->` |
| true              | false                             | —                   | **MED WARN**: PDF in repo but AI has not cross-checked (regardless of `human_read_source`; AI verification is the gating condition for MED — Step 3b R3 codex P1 closure made the matrix total over the 8 input combinations). Replace with `[UNVERIFIED CITATION — AI HAS NOT CROSS-CHECKED]<!--ref:slug-->` |
| true              | true                              | false               | **LOW WARN**: AI cross-checked, user has not. Replace with `<!--ref:slug LOW-WARN-->`; also append slug to per-section pre-finalization checklist artifact |
| true              | true                              | true                | OK, replace with `<!--ref:slug ok-->` |

Each finalizer pass is idempotent on its own resolved markers (re-running on already-resolved `<!--ref:slug ok-->` is a no-op). On revision loops (Stage 4 → reviewer → Stage 4 revise; or `academic-paper` Phase 6 → Phase 4 loops), the finalizer re-runs against the current draft and re-resolves any newly-emitted bare `<!--ref:slug-->` comments; resolved markers do not invalidate.

**Step 3 — Terminal hard-gate at output boundary** (mode-dependent agent; per round-2 R2-001 + round-3 R3-001 amend):

- For `academic-pipeline` and standalone `academic-paper`: **`formatter_agent`** is the hard-gate. It MUST refuse to convert any draft that contains either (a) a literal `[UNVERIFIED CITATION ...]` marker, or (b) any unresolved `<!--ref:slug-->` HTML comment whose status is neither `ok` nor LOW-WARN-acknowledged.
- For standalone `deep-research`: **`cite_provenance_terminal_gate_agent`** (round-3 R3-001 amend) is the hard-gate. It runs AFTER `cite_provenance_finalizer_agent` and is the deep-research terminal artifact emitter. It refuses to emit the final report if any `[UNVERIFIED CITATION ...]` or unresolved `<!--ref:slug-->` (status neither `ok` nor LOW-WARN-acknowledged) remains. **`report_compiler_agent` does NOT carry the hard-gate** — it only compiles (per Step 3a strict-partial-inversion: never read frontmatter, never resolve markers). The dispatch order is `report_compiler_agent` (compile, emit two-layer placeholders) → `cite_provenance_finalizer_agent` (read frontmatter, resolve placeholders) → `cite_provenance_terminal_gate_agent` (inspect resolved draft, emit final report or refuse). Single-pass, no re-invocation of `report_compiler_agent`.

In all modes, the user must either acquire/verify the source (which removes the upstream HIGH/MED WARN cell condition) or rewrite to remove the citation, before final output. LOW-WARN-acknowledged means the user has explicitly run `/ars-mark-read <refcode>` (see §3.6) for that slug, which on the next finalizer pass promotes `<!--ref:slug LOW-WARN-->` to `<!--ref:slug ok-->`.

Markers are **draft-only** — they render as invisible HTML comments (or `[UNVERIFIED CITATION ...]` visible warnings for HIGH/MED WARN) in draft prose but are stripped from final output by the terminal hard-gate agent only after the hard-gate passes (i.e. all comments are `ok` or LOW-WARN-acknowledged).

Consistent with v3.5 Collaboration Depth Observer precedent: warn, surface, but never silently block user choice. The conversion-time hard gate is the single non-negotiable point.

### 3.4 D4 — Session drift untracked

User leaves expected pipeline phase (e.g., from `academic-paper:plan` mode to manual retrieval to ad-hoc tool building back to `academic-paper:plan`). Session ends. User has no way to reconstruct **what work was done in which phase** vs **what was ad-hoc tooling** vs **what was backflow verification**. Future sessions and audit replay treat all session output as equivalent phase deliverable.

**Mechanism:** ARS session does not emit a structured phase-trajectory log. Phase information lives implicitly in agent invocation order; ad-hoc work (user manually editing files, writing scratch artifacts) is invisible to the pipeline orchestrator.

**Protection:** Add **Session Drift Log** as an end-of-session orchestrator artifact. Orchestrator emits `<session>_drift_log.md` containing:

```markdown
## Session <session_id> drift log

**Session start phase:** <phase>
**Session end phase:** <phase>
**Pipeline mode:** <mode>

### Phase trajectory
- HH:MM <action> (in-phase | backflow-to-<phase> | crossphase-jump-to-<phase> | ad-hoc)
- HH:MM ...

### Session deliverables

**Phase-standard artifacts produced:**
- <filename> (phase: <phase>, agent: <agent>)

**Ad-hoc artifacts produced (NOT phase-standard):**
- <filename> (rationale recorded by user: <text> | inferred: <text>)

**Sources newly verified-against-original:**
- <refcode list>

**Sources still unverified-against-original:**
- <refcode list>

### Phase status diff (from session start to session end)
- <artifact>: <before> → <after>

### Recommended next-session work (dependency-ordered)
- <bullet list>
```

The Drift Log is **not enforcement**. It is a transparency artifact: the user reads it after the session to reconstruct what happened, decide whether ad-hoc artifacts should be promoted to phase-standard, and plan the next session.

Two firm rules:
- Backflow events are NOT failures. The Drift Log uses neutral language (`backflow-to-<phase>`), never `deviation` / `out-of-spec` / `error`.
- Ad-hoc artifacts must be enumerated, not hidden. If `bibliography_agent` did not emit a particular file, the file is ad-hoc; this is fine but must be visible to the user.

### 3.5 D5 — Retrieval pipeline single-channel fragility

`retrieval_agent` (or upstream `bibliography_agent` retrieval stage) attempts a single retrieval channel (publisher direct via DOI). On failure (paywall, WAF, 403, redirect to login) the entry is marked `retrieval_failed` and the corpus moves on. Legitimate alternative channels — Wayback Machine CDX API, author personal websites, Google Scholar all-versions, OA aggregators (Unpaywall, OpenAlex, CORE) — are not attempted.

**Mechanism:** Retrieval logic is implemented as a single attempt rather than a fallback chain. False negatives are common: the 2026-04-30 session recovered F3 (Yale Daily News, Vercel-WAF-blocked) via Wayback CDX search and E1 (Harvey & Stensaker 2008, Wiley paywall) via author's institutional repository — both legitimate, both invisible to single-channel retrieval.

A second failure mode in single-channel retrieval: success-criterion is too weak. A 200 OK with `Content-Type: application/pdf` does NOT prove the retrieved file is the requested paper. The 2026-04-30 session retrieved an 8 MB PDF from `peraturan.bpk.go.id` with valid PDF header; first page revealed it was a Banjarmasin city tax regulation, not the requested Permendikbudristek 53/2023. The wrong-record case must be caught by content-grep at retrieval time.

**Protection:** `retrieval_agent` (or equivalent retrieval stage) must implement a **fallback chain** with content verification:

**The fallback chain has 5 mechanical auto-steps + 1 human-handoff terminal step** (per round-1 codex F-007 amend; ResearchGate is human-handoff so default-ON does not mean automated outreach).

```python
def retrieve(refcode, citation):
    # 5 mechanical auto-steps; default ON, no env flag (per round-1 Q6).
    auto_chain = [
        publisher_direct,        # DOI → publisher PDF
        wayback_cdx_search,      # CDX API → archived snapshot
        author_personal_website, # site:<author_lastname>.<inst-tld> grep
        scholar_all_versions,    # Scholar's "All N versions" → [PDF]-marked
        oa_aggregators,          # Unpaywall / OpenAlex / CORE
    ]
    for method in auto_chain:
        result = method(citation)
        if not result.acquired:
            log_failure(refcode, method.name, result.failure_reason)
            continue
        if not verify_content_match(result.pdf, citation):
            log_failure(refcode, method.name, "content_match_failed")
            continue
        return result
    # All auto-steps exhausted. Emit human-handoff event for ResearchGate
    # Request Full-Text. RG is NOT in the auto-chain because asking strangers
    # for files on the user's behalf without consent is unsafe automated outreach.
    log_pending_user_action(refcode, "researchgate_request", citation)
    return RetrievalFailed(
        refcode,
        attempts=auto_chain_log,
        pending_user_action="researchgate_request",
    )
```

`verify_content_match()` MUST do at minimum:
- Read first page of retrieved PDF
- Grep for citation title (or significant title fragment)
- Grep for at least one citation author surname
- Reject if either fails

Three firm rules:
- Each fallback step's failure reason must be logged (`paywall_403`, `waf_blocked`, `not_indexed`, `content_match_failed`, etc.). No silent skips.
- `Content-Type: application/pdf` + HTTP 200 is NEVER sufficient for retrieval success. Content match is mandatory.
- `researchgate_request` is **human-handoff**, not in the auto-chain. On auto-chain exhaustion, retrieval emits a `pending_user_action: researchgate_request_<refcode>` log entry; the user manually requests via the author's RG profile and resumes when the file arrives. Default-ON applies to the 5 mechanical auto-steps, never to RG outreach.

### 3.6 Human-Read Signal Protocol (Q2 amend, round-1 codex F-005)

The §3.3 4-cell matrix and the §3.1 frontmatter schema both reference `human_read_source: true | false`. This subsection defines the user-facing affordance that sets the value, and the storage / merge contract that keeps `literature_corpus[]` schema unmutated.

**Affordance:** explicit user command (no inference, no session-activity heuristic).

```
/ars-mark-read <citation_key>     # mark a single entry as human-read
/ars-mark-read <citation_key>... # batch form (space-separated)
/ars-unmark-read <citation_key>   # rescind (in case of erroneous mark)
/ars-list-read                    # print the current session's mark-read log
```

**Storage:** session-scoped peer file at `<passport-path-parent>/<passport-stem>_human_read_log.yaml` (round-5 R5-003 amend; the `<session>_human_read_log.yaml` shorthand used elsewhere in this spec is the passport-derived path computed per §3.6 cross-session block). NOT the entry's frontmatter. Schema:

```yaml
# <session>_human_read_log.yaml
session_id: <session_id>
created_at: <ISO 8601>
human_read:
  - citation_key: smith2024
    marked_at: <ISO 8601>
  - citation_key: oecd_unesco_2005
    marked_at: <ISO 8601>
```

The peer file lives next to other session artifacts (Material Passport, Drift Log) and is user-owned. The orchestrator / finalizer reads it at frontmatter-read time and joins on `citation_key` to derive `human_read_source: true`.

**Three firm rules:**

1. **Adapters and consumer agents MUST NOT mutate `literature_corpus[]` to add `human_read_source` or `human_read_at`** — those keys are derived, not stored. Lint must reject any entry that ships them literally (per §3.1 firm rule #3).
2. **Invalid `<citation_key>` is a hard error**, not a silent miss. `/ars-mark-read` MUST validate that the slug exists in the active corpus before writing the log entry; on miss, emit `[ARS-MARK-READ ERROR: citation_key '<slug>' not in literature_corpus[]]` and refuse to write.
3. **`<session>_human_read_log.yaml` is append-only across the session**; rescind operations write a `rescinded_at` field instead of deleting the original entry, so audit replay can reconstruct the user's signal trajectory.

**Cross-session semantics (round-2 R2-003 + round-3 R3-002 amend):** v3.6.3's `ARS_PASSPORT_RESET` is a context-reset boundary, NOT an evidence-reset; per `academic-pipeline/references/passport_as_reset_boundary.md`, append-only ledger entries (audit_artifact ledger, reset_boundary ledger) survive across reset. Human-read signals are user-issued evidence and follow the same survival semantics. **Concrete handoff mechanism (round-3 R3-002 amend; Schema 9 untouched per Q3):**

- **Filesystem-deterministic discovery via passport-path derivation (round-4 R4-003 amend).** v3.6.3's reset contract requires the user/orchestrator to know the passport file path (per `passport_as_reset_boundary.md`); it does NOT define a session artifact directory. v3.7.1 derives the read-log location from the passport path rather than introducing a new convention or env var:
  - **Read-log path (per active session):** the orchestrator computes `<passport-path-parent>/<passport-stem>_human_read_log.yaml`, where `<passport-stem>` is the passport filename without extension. Example: passport `/work/proj/.ars/passport_abc123.json` → read-log `/work/proj/.ars/passport_abc123_human_read_log.yaml`.
  - **Fail-fast modes (round-5 R5-003 amend):** `/ars-mark-read` MUST hard-fail (NOT silently create) on any of these conditions:
    - **No active passport path known**: emit `[ARS-MARK-READ ERROR: no active passport path; run a session with passport handoff first or pass --passport-path explicitly]` and refuse to write.
    - **Passport file does not exist** at the resolved path: emit `[ARS-MARK-READ ERROR: passport file not found at <path>]` and refuse.
    - **Passport-parent directory unreadable** (no `R_OK` permission): emit `[ARS-MARK-READ ERROR: passport parent directory <path> unreadable]` and refuse.
    - **Read-log path target is unwritable** (no `W_OK` on parent): emit `[ARS-MARK-READ ERROR: cannot write read-log at <path>; parent directory not writable]` and refuse.
    - **First-time write** (no existing read-log file at the computed path): allowed — the command creates the file with the YAML schema header per §3.6 storage block, then appends the entry. This is NOT a hard-fail case.
  - **Cross-session merge target (read-only):** the orchestrator globs the passport-path's parent directory (resolved via `realpath` to follow symlinks once and detect link cycles) for `*_human_read_log.yaml`, enumerates all matching files including the active one, and merges them. The active session's read-log is the only APPEND target; all other matches are read-only at merge time.
  - **No new env var.** `$ARS_SESSION_ARTIFACT_DIR` is NOT introduced (round-4 R4-003 amend; preserves v3.6.3 minimal-contract discipline). The user-supplied passport path remains the single discovery anchor.
  - **Filesystem-edge cases:** on case-insensitive filesystems (macOS HFS+ / APFS in default mode, Windows NTFS), if two read-log files would collide under casefold (e.g. `Smith_human_read_log.yaml` vs `smith_human_read_log.yaml`), the orchestrator MUST fail-fast with `[ARS-MARK-READ ERROR: casefold-colliding read-log filenames at <path>]` and refuse to merge. Symlinks within the parent dir are followed exactly once via `realpath`; circular symlinks are detected and rejected with `[ARS-MARK-READ ERROR: symlink cycle in read-log discovery]`.
- **Merge precedence:** if the same `citation_key` appears in multiple session logs (e.g. user marked a refcode in session A, rescinded in session B), the **most recent entry by `marked_at` / `rescinded_at` ISO 8601 timestamp** wins. Append-only is preserved (no log file is mutated; precedence is computed at merge time by the orchestrator).
- **Under both `ARS_PASSPORT_RESET=1` and `ARS_PASSPORT_RESET=0`,** prior `human_read` entries carry forward via this filesystem discovery — reset does NOT erase them, since reset only clears in-memory context, never user-owned filesystem evidence.
- **A separate user-initiated affordance** (`/ars-clear-read-log` — out-of-scope for v3.7.1; future enhancement) would be required to actively rescind prior signals across sessions; no automatic erasure occurs at any reset boundary.

### 3.7 v3.6.7 Audit Template Invariant Overlap Audit (Q5 amend)

Per Q5 amend, D2's Scope Report block is added as an **additive prepend** (new Section 0 / Scope Report ahead of the existing Sections 1–7, without renumbering them) to `shared/templates/codex_audit_multifile_template.md` rather than a rewrite (round-2 R2-008 amend). The template's existing 7-section inventory stays byte-equivalent in section title, ordinal labels, and order; Scope Report is prefixed before Section 1 with its own Section-0 header.

**Two distinct v3.6.7 lint surfaces apply (round-2 R2-005 amend):**

1. **`scripts/check_v3_6_7_pattern_protection.py`** enforces line-position-sensitive **prompt-side** invariants on 3 manifest files (synthesis_agent.md, research_architect_agent.md, report_compiler_agent.md): INV-1 / INV-2 / INV-3.
2. **`scripts/check_audit_artifact_consistency.py`** enforces 6 **artifact-side** invariant families (A–F per v3.6.7 Step 6 spec §3.7) over `audit_artifact[]` ledger entries and their JSONL / sidecar / verdict counterparts.

These are different scripts checking different artefacts. The original §3.7 prose conflated them. The corrected mapping:

| Invariant surface | What it checks | Effect of additive Scope Report on the audit template | Preserved? |
|---|---|---|---|
| INV-1 (`check_v3_6_7_pattern_protection.py`) | Canonical Clause 1 line "Sub-agents have been observed..." appears exactly once in each of 3 manifest files (`synthesis_agent.md`, `research_architect_agent.md`, `report_compiler_agent.md`) | Scope Report block lives in `shared/templates/codex_audit_multifile_template.md`, NOT in any of the 3 manifest files. Manifest scope unchanged. | ✅ |
| INV-2 (`check_v3_6_7_pattern_protection.py`) | No Clause 2 disclosure phrases (a)–(d) (e.g. "the orchestrator runs codex audit afterward") inside PATTERN PROTECTION blocks of the 3 manifest files | Same: Scope Report is in audit template, not in any manifest file. INV-2 scope lint scans manifest blocks only. | ✅ |
| INV-3 (`check_v3_6_7_pattern_protection.py`) | Canonical Clause 1 line confined to the 3 manifest files (frozen scope manifest at `scripts/v3_6_7_inversion_manifest.json`) | Audit template not in manifest scope; Scope Report addition does not introduce Clause 1 text. | ✅ |
| Family A (per-artifact cross-field rules A1–A6, `check_audit_artifact_consistency.py`) | Constraints on `audit_artifact[]` Schema 9 entries, not the audit template body | Scope Report is template prose, not Schema 9 data. | ✅ |
| Family B (cross-file / Layer 3 rules B1–B10, `check_audit_artifact_consistency.py`) | Constraints on `audit_jsonl` / `audit_sidecar` / `audit_verdict` schemas | Scope Report does not modify these JSON schemas. | ✅ |
| Family C (mirror rules C1–C4, `check_audit_artifact_consistency.py`) | C3 in particular forbids "the orchestrator runs audit afterward" leaking from agent prompts. Scope Report mentions that the audit was run by the orchestrator — but it is in the **audit report template**, not in the agent prompt. | Reading the audit report after the fact does not give a downstream agent prompt knowledge of orchestrator behavior at draft time. | ✅ |
| Family D (ordering rules D1–D4, `check_audit_artifact_consistency.py`) | D1 strict-monotonic `verified_at_ms` etc. are Schema 9 ledger semantics | Scope Report does not write `audit_artifact[]`. | ✅ |
| Family E (lifecycle ownership E1–E9, `check_audit_artifact_consistency.py`) | Ownership of audit JSONL/sidecar/verdict file emission | Scope Report is text inside the verdict file body; ownership unchanged. | ✅ |
| Family F (naming convention F1–F4, `check_audit_artifact_consistency.py`) | Run-ID format and similar | Scope Report adds no new identifiers. | ✅ |

**Acceptance (round-2 R2-005 amend; corrected regression gate):** Step 2 (§4) MUST include regression tests against BOTH lint surfaces:
- `python scripts/check_v3_6_7_pattern_protection.py` PASSES (12/12 invariants) on the modified template branch
- `pytest scripts/test_check_v3_6_7_pattern_protection.py -q` PASSES 58/58 mutation tests
- `python scripts/check_audit_artifact_consistency.py` PASSES on a synthesized audit_artifact ledger that includes a verdict file body containing the new Section 0 Scope Report block (verifies family A–F invariants are not perturbed by template prose changes)

If any of the three fails, the additive-prepend claim is broken and Q5 must be re-discussed.

---

## 4. Implementation Steps

### Step 0 — Lint manifest separation (round-1 codex F-004 amend)

Per round-1 codex F-004, v3.7.1 introduces new prompt-level invariants on the three downstream agents (synthesis_agent / draft_writer_agent / report_compiler_agent) for the two-layer citation emission discipline. Widening the v3.6.7 frozen `scripts/v3_6_7_inversion_manifest.json` scope would re-open the 18-codex-round v3.6.7 convergence, so v3.7.1 ships its **own** manifest and lint instead.

**Files to create:**
- `scripts/v3_6_8_inversion_manifest.json` — frozen scope manifest covering v3.7.1 prompt invariants. Initial entries: synthesis_agent / draft_writer_agent / report_compiler_agent for the "Two-Layer Citation Emission" prompt block invariants. Schema mirrors v3.6.7 manifest (file list + per-file invariant assertions) but is a separate JSON file and a separate `EXPECTED_MANIFEST_FILES` tuple in the v3.7.1 lint.
- `scripts/check_v3_6_8_pattern_protection.py` — see Step 3a. References `v3_6_8_inversion_manifest.json`, NOT the v3.6.7 manifest.

**Acceptance (round-2 R2-006 + round-3 R3-003 amend; corrected boundary statement + canonical range definition):**
- v3.6.7 lint regression: `python scripts/check_v3_6_7_pattern_protection.py` PASSES 12/12; `pytest scripts/test_check_v3_6_7_pattern_protection.py -q` PASSES 58/58. The boundary rule is: **v3.7.1 work does NOT modify the v3.6.7-tagged PATTERN PROTECTION blocks** in synthesis_agent.md / research_architect_agent.md / report_compiler_agent.md (those blocks stay byte-equivalent under v3.6.7 INV-1/2/3 enforcement). v3.7.1 MAY add **new** prompt sections (e.g. "Two-Layer Citation Emission") to the same files, OUTSIDE the v3.6.7 PATTERN PROTECTION fenced block.
- **Canonical range definition (round-3 R3-003 + round-4 R4-001 + round-5 R5-004 amend; uses existing heading-to-next-heading extraction, no marker mutation):** each protected block is extracted by the same heading-based extractor that v3.6.7 lint already uses (per `scripts/check_v3_6_7_pattern_protection.py` block isolation logic at line ~256) — start at the line containing `## PATTERN PROTECTION (v3.6.7)` heading; end at the line before the next H1 / H2 / H3 (`# `, `## `, or `### `) heading or EOF, whichever comes first (round-5 R5-004 amend: `H1/H2/H3` matches the existing extractor's actual termination set; previous wording said only H2 which would have produced a different byte range than v3.6.7 lint). The byte range is from the start of the heading line through the end of the last block line (excluding the next-heading line itself). **No new BEGIN/END markers are introduced** (introducing markers would mutate v3.6.7 protected blocks, contradicting the boundary rule).
- **SHA check normalization rules**: bytes are read raw (no LF→CRLF conversion); the file's BOM (if any) is excluded; trailing whitespace of the last block line is preserved; SHA-256 is computed over the resulting byte sequence. The extractor is the byte-equivalent function shared between v3.6.7 lint and v3.7.1 lint to guarantee identical results.
- **Single source of truth (round-4 R4-002 + round-5 R5-001 + round-6 R6-002 amend; no dual stored truth, base commit derived not stored, shallow-clone safe):** the v3.6.7 frozen manifest at `scripts/v3_6_7_inversion_manifest.json` is the single source of truth for the protected file *list*; the v3.6.7 *content* is whatever the file shows at the manifest's most recent modifying commit (derived via `git log -1 --format=%H scripts/v3_6_7_inversion_manifest.json`). v3.7.1 lint computes the SHA on demand at runtime by (a) reading the v3.6.7 manifest's file list, (b) extracting each file's heading-based block range at PR HEAD, (c) hashing the bytes, (d) extracting + hashing the same files at the v3.6.7 manifest's most recent modifying commit (the "v3.6.7 base commit"), (e) asserting (c) == (d). v3.7.1 manifest does NOT store `expected_v3_6_7_block_sha256` values (avoiding concurrent / out-of-order PR drift). v3.6.7 manifest does NOT need a new `base_commit` field — `git log -1` derivation makes that drift-proof.
- **Shallow-clone safety (round-6 R6-002 + round-7 R7-001 amend):** `actions/checkout@v4` defaults to `fetch-depth: 1` in CI, which would make `git log -1` return only HEAD (rendering the comparison vacuous). v3.7.1 lint MUST first call `git rev-parse --is-shallow-repository`; if `true`, lint MUST either (a) call `git fetch --unshallow origin <default-branch>` to deepen the clone, OR (b) hard-fail with `[ARS-V3.7.1 LINT ERROR: shallow clone detected; set fetch-depth: 0 in checkout step before running v3.7.1 byte-equivalence check]`. **Default-branch lookup order (round-7 R7-001 amend):** (1) `git symbolic-ref --quiet --short refs/remotes/origin/HEAD` (strip the `origin/` prefix); (2) GitHub Actions fallback `github.event.repository.default_branch` env var; (3) hard-fail with `[ARS-V3.7.1 LINT ERROR: default branch unresolvable; clone must include origin/HEAD or set GITHUB_DEFAULT_BRANCH env]`. Step 0 acceptance MUST also amend `.github/workflows/spec-consistency.yml` to add `fetch-depth: 0` on the `actions/checkout@v4` step that runs the v3.7.1 lint, so production CI does not rely on the unshallow fallback. The "same-run hashes against itself" fallback from round-4 prose is removed (round-5 R5-001 amend: it was vacuous for drift detection).
- v3.7.1 lint scope: confined to v3.7.1-tagged sections only; does NOT scan or mutate v3.6.7-tagged blocks. The SHA check is the only v3.7.1 lint that *reads* v3.6.7-tagged bytes (read-only, byte-equivalence assertion).

### Step 1 — Frontmatter schema split

**Files to modify:**
- `shared/contracts/passport/literature_corpus_entry.schema.json` — add the **seven** entry-stored fields per §3.1 (round-1 codex F-005 amend: `human_read_source` and `human_read_at` are derived, NOT entry-stored — they live in §3.6 peer file `<session>_human_read_log.yaml`). Schema stays `additionalProperties: false`; no widening to admit user-mutable fields.
- `deep-research/agents/bibliography_agent.md` — add prompt section "Trust-Chain Frontmatter Discipline" specifying field semantics + the **three** firm rules (the third being "NEVER emit `human_read_source` literally; that field is user-set via §3.6 command") + refusal-on-uncertain rule
- `academic-paper/agents/literature_strategist_agent.md` — same prompt addition for downstream consumer

**New CI lint:**
- `scripts/check_v3_6_8_frontmatter_trust_schema.py` — validates the three firm rules across all entry .md files in a sample corpus, including the "no literal `human_read_source` on entry" rule

**Wire into `.github/workflows/spec-consistency.yml`.**

**Acceptance:**
- `bibliography_agent` and `literature_strategist_agent` carry the new prompt block with all three firm rules
- Lint enforces all three firm rules on test fixtures
- Mutation test: an entry that ships a literal `human_read_source: true` field is rejected by both schema validation (`additionalProperties: false`) AND the v3.7.1 lint (defense in depth)
- Mutation tests confirm refusal-on-uncertain behavior

### Step 2 — Audit report Scope Report block

**Files to modify:**
- `shared/templates/codex_audit_multifile_template.md` — add Scope Report block as opening section, before any pass/fail summary
- Per-mode codex audit prompts that reference the template

**New CI lint:**
- `scripts/check_v3_6_8_audit_scope_block.py` — checks audit report templates for required Scope Report header + forbidden combined-aggregate "PASSED" verb

**Acceptance:**
- All audit templates carry the Scope Report block
- Lint enforces template compliance
- Sample audit report run on the 2026-04-30 production session corpus reproduces the correct coverage breakdown (22 verifiable / 31 description-only of 53)
- **v3.6.7 invariant regression (per §3.7 + Q5 amend)**: `python scripts/check_v3_6_7_pattern_protection.py` PASSES 12/12 invariants on the modified template; `pytest scripts/test_check_v3_6_7_pattern_protection.py -q` PASSES 58/58 mutation tests. If either fails, additive-prepend is broken; reopen Q5.

### Step 3 — Cite-Time Provenance Check (4 sub-steps per round-1 codex Q8 amend)

Step 3 splits into 4 sub-steps to honor the strict partial-inversion discipline (agents emit, finalizer resolves, formatter gates) and the mode-dependent finalizer location (pipeline-orchestrator vs. per-skill standalone finalizer).

#### Step 3a — Agent two-layer citation emission (uniform across all modes)

**Files to modify:**
- `deep-research/agents/synthesis_agent.md` — add prompt block "Two-Layer Citation Emission" specifying `<author-year> <!--ref:slug-->` form, the strict partial-inversion rules (NEVER read frontmatter, NEVER mention finalizer / orchestrator / stage gate, NEVER resolve markers)
- `academic-paper/agents/draft_writer_agent.md` — same prompt block
- `deep-research/agents/report_compiler_agent.md` — same prompt block (per round-1 codex P2 finding 10: agent coverage)

**New CI lint:**
- `scripts/check_v3_6_8_pattern_protection.py` — separate v3.7.1 lint with its own roadmap-slot-namespaced manifest at `scripts/v3_6_8_inversion_manifest.json` (filename retains `v3_6_8` slot per Q7 / spec_location_semver_decoupling). Does NOT modify the v3.6.7 frozen `_v3_6_7_inversion_manifest.json` scope (per round-1 codex F-004 amend; preserves 18-codex-round v3.6.7 convergence). Lint enforces (i) two-layer form regex on emitted citations in agent test fixtures, (ii) absence of resolver-layer prose inside the new "Two-Layer Citation Emission" prompt blocks (forbidden term set: `finalizer` / `orchestrator` / `stage gate` / `terminal gate` / `resolver`, plus plural variants and underscore-bounded substring matches like `cite_provenance_finalizer_agent`; broader than the spec's narrow three-term list per Step 3a R2/R3 codex closures, intentionally over-inclusive to close attack surface for Step 3c/3d agent names), (iii) absence of any frontmatter-read instruction in those blocks (variants covered: `frontmatter` / `front matter` / `front-matter` / `front_matter`; verbs `read` / `look up` / `dereference` / `consult` / `open` / `parse` / `load` / `access` / `query` / `fetch` with identifier-aware boundaries that catch function-style calls like `read_frontmatter()`; negation must be ≤30 chars before the verb and not separated from the verb by a sentence terminator including markdown bullet boundaries). Step 3a R4 codex review confirms 0 P0+P1 against this enforcement surface.

**Acceptance:**
- All 3 agents carry the two-layer citation prompt block
- v3.7.1 lint enforces strict partial-inversion (3 invariants above)
- v3.6.7 lint regression: `python scripts/check_v3_6_7_pattern_protection.py` PASSES (no widening of v3.6.7 manifest; v3.7.1 lint is separate)

#### Step 3b — Pipeline finalizer (academic-pipeline mode)

**Files to modify:**
- `academic-pipeline/agents/pipeline_orchestrator_agent.md` — add subsection "Cite-Time Provenance Finalizer (v3.7.1)" specifying §3.3 4-cell matrix, peer-file `<session>_human_read_log.yaml` join semantics, idempotency on revision loops

**New CI lint:**
- `scripts/check_v3_6_8_cite_provenance_pipeline.py` — checks that `pipeline_orchestrator_agent` carries the finalizer subsection with all 4 matrix rows and the idempotency clause

**Acceptance:**
- Orchestrator subsection present
- Mutation test: removing any of the 4 matrix rows fails lint
- Revision-loop test (per round-1 codex P2 finding 11): a draft passed through finalizer twice (Stage 4 → reviewer → Stage 4 revise) produces identical resolved markers; new bare `<!--ref:slug-->` comments in the revised pass are resolved correctly without invalidating prior `ok` markers

#### Step 3c — Standalone finalizer (academic-paper / deep-research standalone modes)

**Files to create:**
- `academic-paper/agents/cite_provenance_finalizer_agent.md` — per-skill finalizer for `academic-paper` standalone mode, invoked at deliverable emission boundary AFTER `draft_writer_agent` finishes drafting and BEFORE the draft is handed to `formatter_agent`. Implements the same §3.3 4-cell matrix as Step 3b.
- `deep-research/agents/cite_provenance_finalizer_agent.md` — per-skill finalizer for `deep-research` standalone mode, invoked **AFTER** `report_compiler_agent` finishes compiling its draft (round-2 R2-001 + round-3 R3-001 amend). Same §3.3 matrix. The finalizer reads/resolves markers, but does NOT emit final report; that is the next agent's job (Step 3d).

**New CI lint:**
- `scripts/check_v3_6_8_cite_provenance_standalone.py` — checks that both standalone finalizer agents exist, carry the §3.3 matrix, and are referenced from the appropriate dispatch points in `academic-paper/SKILL.md` and `deep-research/SKILL.md`. For deep-research, also asserts that `cite_provenance_finalizer_agent` runs AFTER `report_compiler_agent` (NOT before) per the dispatch order.

**Acceptance:**
- Both finalizer agents exist
- Academic-paper standalone test: a draft from `academic-paper full` mode (no pipeline orchestrator) reaches `formatter_agent` with all `<!--ref:slug-->` comments resolved (no unresolved bare comments cause format-time hard-block in healthy path)
- Deep-research standalone test (round-2 R2-001 + round-3 R3-001 amend): a report from `deep-research full` mode passes through `report_compiler_agent` (compiles, emits two-layer placeholders per Step 3a) → `cite_provenance_finalizer_agent` (resolves markers) → `cite_provenance_terminal_gate_agent` (inspects resolved draft, emits final report). Three single-purpose agents, no re-invocation. The terminal report is emitted only if the gate agent passes.

#### Step 3d — Terminal hard-gate (mode-dependent: `formatter_agent` for academic-paper, `cite_provenance_terminal_gate_agent` for deep-research; round-3 R3-001 amend)

**Files to modify:**
- `academic-paper/agents/formatter_agent.md` — add hard-gate refusal rule: refuse any draft containing (a) `[UNVERIFIED CITATION ...]` literal markers, or (b) unresolved `<!--ref:slug-->` HTML comments whose status is neither `ok` nor LOW-WARN-acknowledged

**Files to create (round-3 R3-001 amend):**
- `deep-research/agents/cite_provenance_terminal_gate_agent.md` — separate single-purpose terminal-gate agent. Reads the resolved draft from `cite_provenance_finalizer_agent`, applies the same refusal conditions as `formatter_agent`, emits the final report or refuses. Does NOT compile (that is `report_compiler_agent`), does NOT resolve markers (that is `cite_provenance_finalizer_agent`). Pure inspect + emit/refuse. This avoids the two-pass `report_compiler_agent` dispatch problem and keeps the v3.6.7 strict-partial-inversion discipline intact for `report_compiler_agent`.

**New CI lint:**
- `scripts/check_v3_6_8_formatter_hard_gate.py` — checks that `formatter_agent` carries both refusal rules
- `scripts/check_v3_6_8_terminal_gate_agent.py` (round-3 R3-001 amend) — checks that `cite_provenance_terminal_gate_agent` exists, carries both refusal rules, and is wired into deep-research dispatch AFTER `cite_provenance_finalizer_agent`. Asserts (a) the agent never reads frontmatter (per partial-inversion discipline of Step 3a), (b) the agent never modifies any `<!--ref:slug-->` marker (only inspects), (c) `report_compiler_agent` is NOT modified to carry hard-gate (preserves v3.6.7 PATTERN PROTECTION block byte-equivalence per Step 0)

**Acceptance:**
- `formatter_agent` carries both refusal rules
- `cite_provenance_terminal_gate_agent` exists and carries both refusal rules; `report_compiler_agent` is unchanged from v3.6.7 (per Step 0 boundary rule + round-3 R3-001 amend)
- Mutation tests: removing either refusal rule from `formatter_agent` fails lint; removing the terminal-gate agent or its rules fails lint; modifying `report_compiler_agent`'s v3.6.7 PATTERN PROTECTION block fails Step 0 lint
- End-to-end test (academic-paper): a draft with one HIGH WARN marker is hard-refused at `formatter_agent`; same draft after `/ars-mark-read` acknowledgement passes hard gate
- End-to-end test (deep-research, round-3 R3-001 amend): a report with one HIGH WARN marker emitted during `report_compiler_agent` compilation is hard-refused at `cite_provenance_terminal_gate_agent`; same report after `/ars-mark-read` acknowledgement + `cite_provenance_finalizer_agent` re-pass passes the terminal gate

#### Step 3e — Deep-research 3-agent handoff schema (round-4 R4-005 amend)

The 3-agent linear dispatch (`report_compiler_agent` → `cite_provenance_finalizer_agent` → `cite_provenance_terminal_gate_agent`) needs a concrete handoff contract. **Partial-inversion preserved (round-5 R5-002 amend):** `report_compiler_agent` outputs ONLY standard markdown with two-layer citations per §3a; a thin **dispatcher wrapper** (single-purpose orchestration code, not an LLM agent) reads that markdown and constructs the handoff payload (`draft_path` / `draft_text` / `compilation_metadata`) for the next agent. The finalizer and terminal-gate agents consume the schema directly because §3a explicitly authorizes them to know about frontmatter / dispatch state.

**Files to create:**
- `deep-research/scripts/cite_provenance_dispatcher.py` (round-6 R6-001 + round-7 R7-002 amend) — single-purpose dispatcher wrapper for the deep-research standalone path. Reads `report_compiler_agent`'s markdown output, computes `compilation_metadata` (word count, section count, citation count, two-layer placeholder count) by static parse, constructs the handoff payload per `shared/contracts/cite_provenance/handoff_schema.json`, and dispatches to `cite_provenance_finalizer_agent`. Not an LLM agent — pure orchestration code, mirrors the v3.6.7 wrapper pattern. **Convention note (round-7 R7-002 amend):** `deep-research/scripts/` is a new per-skill subdirectory introduced by v3.7.1 alongside the existing `agents/` / `examples/` / `references/` subdirs (root `scripts/` continues to host cross-skill helpers); v3.7.1 explicitly blesses this convention because the dispatcher is skill-local runtime code with no cross-skill use. Plugin packaging via `skills/deep-research -> ../deep-research` symlink (per v3.7.0 `.claude-plugin/` packaging) automatically includes the new subdir. For the academic-pipeline path the equivalent dispatcher logic lives in `pipeline_orchestrator_agent.md` per Step 3b (no separate file needed; orchestrator already handles handoff state).
- `shared/contracts/cite_provenance/handoff_schema.json` — JSON Schema for the per-step handoff payload (round-5 R5-002 amend; partial-inversion-preserving allocation of populator roles):
  - `draft_path` (string, absolute or repo-relative): location of the current draft markdown file. Populated by the **orchestrator/dispatcher** wrapping `report_compiler_agent`'s standard markdown output (NOT by `report_compiler_agent` itself; partial-inversion preserved per §3a).
  - `draft_text` (string, optional alternative to `draft_path`): inline draft content for in-memory dispatch. Same population rule.
  - `compilation_metadata` (object, populated by **the orchestrator/dispatcher** by computing over `report_compiler_agent`'s output): word count, section count, citation count, two-layer placeholder count. `report_compiler_agent` itself emits ONLY standard markdown with two-layer citations (per §3a strict-partial-inversion); it does NOT populate this field. The orchestrator counts/computes after receiving the markdown.
  - `citation_resolution_summary` (object, populated by `cite_provenance_finalizer_agent`): per-status counts (`ok`, `LOW-WARN`, `MED-WARN`, `HIGH-WARN`), unresolved-marker count, refcodes that triggered each status. The finalizer reads frontmatter + emits this summary as part of its job; this is consistent with §3a since the finalizer is explicitly authorized to read frontmatter.
  - `unresolved_marker_count` (integer, populated by finalizer; copied forward by terminal gate without modification): number of `<!--ref:slug-->` comments that did NOT resolve to `ok` or LOW-WARN-acknowledged.
  - `terminal_gate_decision` (object, populated by `cite_provenance_terminal_gate_agent`): `decision: "EMITTED" | "REFUSED"`, `reason: <string|null>` (refusal reason if REFUSED), `final_report_path: <string|null>` (set if EMITTED).
  - **Partial-inversion ratification**: `report_compiler_agent` outputs only markdown; the dispatcher (single-purpose wrapper, not an LLM agent) computes `draft_path` / `draft_text` / `compilation_metadata` from that markdown. This preserves §3a's "agent never knows about finalizer / terminal-gate / orchestrator." Lint at Step 3e MUST verify that no agent prompt file (`report_compiler_agent.md`) references the handoff schema or its field names.

**Files to modify:**
- `deep-research/SKILL.md` — add subsection "Cite-Provenance Pipeline (v3.7.1)" describing the 3-agent dispatch order with reference to the handoff schema. The existing `report_compiler_agent` → final-report dispatch (per current SKILL.md) is replaced (in standalone mode) with the 3-agent chain. The PATTERN PROTECTION block in `report_compiler_agent` is unchanged; only the SKILL.md dispatch wiring updates.
- `deep-research/agents/cite_provenance_finalizer_agent.md` — add explicit prompt instruction "consume handoff payload per `shared/contracts/cite_provenance/handoff_schema.json`; emit the same payload with `citation_resolution_summary` and `unresolved_marker_count` populated."
- `deep-research/agents/cite_provenance_terminal_gate_agent.md` — add explicit prompt instruction "consume handoff payload; emit same payload with `terminal_gate_decision` populated; emit final report file if EMITTED."

**New CI lint:**
- `scripts/check_v3_6_8_handoff_schema.py` — validates the JSON Schema shape; verifies `deep-research/SKILL.md` references it; verifies both new agent prompts mention `handoff_schema.json` and the field names they're responsible for.

**Acceptance:**
- `handoff_schema.json` exists and validates
- `deep-research/scripts/cite_provenance_dispatcher.py` exists, parses markdown, populates the schema's orchestrator-owned fields, and dispatches to `cite_provenance_finalizer_agent` (round-6 R6-001 amend)
- `deep-research/SKILL.md` 3-agent dispatch wiring documented, naming the dispatcher script as the standalone-mode invocation surface
- Both new agent prompts reference the schema by path
- `report_compiler_agent.md` does NOT reference the schema or its field names (round-5 R5-002 lint enforcement)
- Mutation tests confirm: (a) removing any schema reference from finalizer/terminal-gate fails lint; (b) adding any schema reference to `report_compiler_agent.md` fails lint; (c) renaming or deleting `cite_provenance_dispatcher.py` fails lint
- Integration test: a synthetic 3-agent dispatch with a draft containing one HIGH WARN marker propagates the correct `citation_resolution_summary` (1 HIGH-WARN, 0 ok), correct `unresolved_marker_count` (1), and `terminal_gate_decision` (REFUSED, reason cites HIGH WARN refcode)

### Step 4 — Session Drift Log emission

**Files to modify:**
- `academic-pipeline/agents/pipeline_orchestrator_agent.md` — add Drift Log artifact spec per §3.4 (peer file `<session>_drift_log.md`, NOT a Schema 9 amendment per Q3 amend)
- `shared/templates/session_drift_log_template.md` — new file, canonical template

**Acceptance:**
- Orchestrator emits `<session>_drift_log.md` at session end
- Template enforces neutral language (no `deviation` / `out-of-spec` / `error` for backflow)
- Manual run on 2026-04-30 production session reproduces a plausible Drift Log (validation against this paper's authoring session as case study)

### Step 5 — Retrieval fallback chain (5 auto + 1 human-handoff)

**Files to modify:**
- `deep-research/agents/bibliography_agent.md` — add retrieval-stage prompt block per §3.5 with the 5 mechanical auto-step chain (publisher_direct → wayback_cdx_search → author_personal_website → scholar_all_versions → oa_aggregators), content-match mandatory rule, AND the `pending_user_action: researchgate_request` human-handoff terminal step (per round-1 codex F-007 amend)
- New shared reference: `shared/references/retrieval_fallback_chain.md` — canonical fallback method spec, failure-reason vocabulary, content-match procedure, RG human-handoff protocol (how user resumes after acquiring the file via RG)

**Acceptance:**
- `bibliography_agent` retrieval prompt enumerates 5 mechanical auto-fallback methods + 1 human-handoff terminal
- Each auto-method has documented failure-reason vocabulary
- `verify_content_match()` procedure spec'd in the reference file
- RG human-handoff is documented as terminal (NOT in auto-chain); fallback emits `pending_user_action: researchgate_request_<refcode>` log entry, never auto-sends RG message
- Sample run: F3 (Wayback recoverable) and E1 (author site recoverable) successfully retrieved by auto-chain; one paywalled-only refcode reaches RG human-handoff terminal and emits the `pending_user_action` log entry without making any outbound RG request

### Step 6 — Integration tests

**New synthetic eval cases:**
- `tests/eval_cases/v3_6_8_trust_chain_violation.md` — corpus with mixed `source_acquired` states; verifies (a) `bibliography_agent` does not emit unsupported `verified` claims, (b) audit emits correct Scope Report, (c) cite-time hook injects markers correctly, (d) `formatter_agent` refuses to convert academic-paper drafts with `[UNVERIFIED CITATION ...]` markers or unresolved `<!--ref:slug-->` comments, (e) `cite_provenance_terminal_gate_agent` refuses deep-research reports with same markers (round-3 R3-001 + round-4 R4-004 amend; gate owner is the separate single-purpose agent, NOT `report_compiler_agent`)
- `tests/eval_cases/v3_6_8_retrieval_fallback.md` — corpus with paywall-blocked, Wayback-recoverable, and content-mismatch entries; verifies fallback chain behavior end-to-end

**Acceptance:**
- Both eval cases pass
- Wired into the v3.7.1 release CI gate

### Step 7 — `/ars-mark-read` plugin commands (round-2 R2-002 amend)

The `/ars-mark-read` / `/ars-unmark-read` / `/ars-list-read` commands defined in §3.6 Human-Read Signal Protocol need a concrete implementation target that fits the existing v3.7.0 plugin commands convention (`commands/ars-*.md`).

**Files to create:**
- `commands/ars-mark-read.md` — slash command frontmatter + body. Validates `<citation_key>` against active `literature_corpus[]`; on miss, emit `[ARS-MARK-READ ERROR: citation_key '<slug>' not in literature_corpus[]]` and refuse to write. On success, append entry to `<session>_human_read_log.yaml`. Model: `sonnet` (per `feedback_no_haiku.md`); routing: per `feedback_delegation_mode_ask.md`, this is a per-keystroke command, not an agent dispatch.
- `commands/ars-unmark-read.md` — slash command frontmatter + body. Append `rescinded_at: <ISO 8601>` to the matching `<session>_human_read_log.yaml` entry (NOT delete; per §3.6 third firm rule, log is append-only).
- `commands/ars-list-read.md` — slash command frontmatter + body. Reads `<session>_human_read_log.yaml` and prints active marks (those without `rescinded_at`).
- `commands/ars-mark-read.zh-TW.md` (optional) — zh-TW translation if English-only commands break the consumer surface.

**New CI lint:**
- `scripts/check_v3_6_8_mark_read_commands.py` — verifies the 3 commands exist, carry the validation rule (citation_key must be in `literature_corpus[]`), and write to `<session>_human_read_log.yaml` (NOT to entry frontmatter, per §3.1 firm rule #3 / round-1 F-005).

**Acceptance:**
- 3 commands exist with sonnet model routing in frontmatter
- Invalid `<citation_key>` (not in corpus) produces hard error, no log write
- Valid `<citation_key>` appends to the passport-derived read-log path (`<passport-path-parent>/<passport-stem>_human_read_log.yaml` per §3.6 R5-003 amend) with `marked_at: <ISO 8601>`
- `/ars-unmark-read` writes `rescinded_at`, never deletes original entry (append-only firm rule)
- `/ars-list-read` returns only entries without `rescinded_at`
- End-to-end with Step 3 finalizer: after `/ars-mark-read smith2024`, the next finalizer pass promotes `<!--ref:smith2024 LOW-WARN-->` to `<!--ref:smith2024 ok-->`
- **Fail-fast (round-5 R5-003 amend):** all 4 fail-fast modes from §3.6 (no active passport / passport not found / parent unreadable / read-log unwritable) emit the canonical `[ARS-MARK-READ ERROR: ...]` message and exit non-zero. First-time write (read-log file does not yet exist) is NOT a fail mode — the command creates the file with the YAML schema header before appending.

---

## 5. Acceptance Criteria

ARS v3.7.1 (roadmap slot v3.6.8) ships when:

1. All five Patterns D1–D5 carry prompt-level protection in the relevant agent(s)
2. Frontmatter schema split is enforced by CI lint, including the rule that `human_read_source` is NEVER stored on the entry (per §3.6 + round-1 codex F-005)
3. Audit report Scope Report block is present in all audit templates as an additive opening section, AND v3.6.7 invariant regression PASSES (`check_v3_6_7_pattern_protection.py` 12/12 + 58 mutation tests; per §3.7 + Q5 amend)
4. Cite-Time Provenance Check finalizer is integrated (mode-dependent: `pipeline_orchestrator_agent` at stage transition for academic-pipeline; per-skill `cite_provenance_finalizer_agent` at deliverable boundary for standalone academic-paper / deep-research) AND mode-dependent terminal hard-gate is wired (round-3 R3-004 amend): `formatter_agent` enforces hard gate for academic-pipeline + standalone academic-paper; `cite_provenance_terminal_gate_agent` enforces hard gate for standalone deep-research. Both refusal targets cover `[UNVERIFIED CITATION ...]` markers and unresolved `<!--ref:slug-->` comments.
5. Session Drift Log is emitted at session end as a peer file (NOT a Schema 9 amendment per Q3)
6. Retrieval fallback chain is documented with 5 mechanical auto-steps + 1 human-handoff terminal (RG, per round-1 codex F-007), and `bibliography_agent` retrieval prompt references it
7. Two synthetic eval cases pass end-to-end
8. Static lint suite (`scripts/check_v3_6_8_*.py` family) enforces all the above; v3.7.1 lint manifest is **separate** from v3.6.7's frozen manifest (per Step 0 + round-1 codex F-004)
9. Independent xhigh codex audit on the 2026-04-30 production session corpus, replayed under v3.7.1 protections, would produce a Scope Report disclosing the 22/31 split and inject `[UNVERIFIED CITATION ...]` markers on the 31 description-only entries before the user reaches chapter prose
10. `/ars-mark-read <citation_key>` command works end-to-end: writes to `<session>_human_read_log.yaml`, finalizer joins on next pass, LOW-WARN markers are promoted to `ok` (per §3.6)
11. Standalone-mode test (per round-1 codex F-001): a draft from `academic-paper full` mode (no pipeline orchestrator) reaches `formatter_agent` with all `<!--ref:slug-->` comments resolved by the per-skill `cite_provenance_finalizer_agent`; same for `deep-research full` mode
12. Revision-loop test (per round-1 codex P2 finding 11): a draft passed through finalizer twice produces idempotent resolved markers; new bare comments in the revised pass are resolved without invalidating prior `ok` markers
13. Cross-doc release sweep complete (per round-1 codex P3 finding 19): CHANGELOG.md / README.md / README.zh-TW.md / `.claude/CLAUDE.md` / MODE_REGISTRY.md / `.claude-plugin/plugin.json` / docs/ARCHITECTURE.md / new `/ars-mark-read` command docs all reference `v3.7.1` (roadmap slot v3.6.8) consistently

---

## 6. Out-of-Scope (Future Work)

- **Auto-acquisition for paywalled material via institutional VPN integration** — too environment-specific; user-handled
- **Per-user trust-policy configuration** (e.g., "always require human-read for journal X") — future extension; v3.7.1 ships uniform schema
- **Drift Log → automatic phase-promotion suggestion** (e.g., "your ad-hoc Quote Registry should be promoted to Phase 2 deliverable") — too prescriptive; transparency only in v3.7.1
- **Real-time during-session warnings on phase departure** — explicit non-goal per §2.2; transparency surface is end-of-session only
- **Schema 9 `passport.session_history[]` integration of Drift Log** (per Q3 amend; v3.7.x+ candidate)
- **Auto-RG outreach** — explicitly forbidden per round-1 codex F-007; RG always human-handoff

---

## 7. Cross-References

### Generative session evidence (this paper's ground truth)
- 2026-04-30 production session (book chapter authoring; corpus = 53 entries spanning institutional QA literature)
- Session deliverables (private; described abstractly): an `_AUDIT_FINDINGS.md` for the round-3 codex audit cross-check, a `PENDING_RETRIEVAL.md` for unsourced entries, a per-domain quote-registry for the dominant source family, and a `ROADMAP.md` tracking chapter-section progress
- User-side memory entries (Claude Code persistent memory):
  - `feedback_ars_user_drift_is_verification_behavior.md`
  - `feedback_ars_verification_provenance_layer.md`
  - `feedback_ars_audit_scope_disclosure.md`
  - `feedback_ars_session_drift_log.md`
  - `feedback_ars_retrieval_fallback_chain.md`

### Prior-version specs this builds on
- v3.6.7: `docs/design/2026-04-29-ars-v3.6.7-downstream-agent-pattern-protection-spec.md` — downstream agent pattern protection (D1–D5 patterns are the **upstream** complement to v3.6.7's downstream-agent narrative/instrument/publication patterns)
- v3.6.5: literature_corpus consumer integration — frontmatter schema split (§3.1) extends `literature_corpus_entry.schema.json`
- v3.5: Collaboration Depth Observer — advisory-not-blocking precedent (Cite-Time Provenance Check follows the same advisory model except at format-conversion hard gate)
- v3.6.6 generator-evaluator contract: cite-time hook builds on the agent-output-evaluation pattern

### Related downstream-agent feedback (different patterns, same era)
- `feedback_ars_bibliography_agent_hallucination_patterns.md` (2026-04-29) — five upstream `bibliography_agent` patterns (JSIE prestigious anchoring, online vs print year, author mashup, phantom source, annotation overclaim). v3.7.1 D1 protection mitigates the **downstream consequence** of those upstream patterns by making trust-chain transparent.
- `feedback_subagent_tool_hallucination.md` (2026-04-29) — sub-agent tool hallucination (claiming to have run codex audit / simulated fixes). v3.7.1 D2 (audit scope disclosure) is the structural protection: audit reports must declare what they actually verified.

### Process / discipline memory (cited by spec banner)
- `feedback_codex_iterative_spec_review_to_zero.md` — convergence target rationale (run codex review until 0 finding before impl)
- `feedback_codex_review_vs_resume_audit_scope.md` — "补 counter 不改 rule → 停" stop signal vs. architectural inflection
- `feedback_architectural_inflection_after_repeated_p1.md` — when 3+ same-finding partials = architectural smell, escalate

---

## 8. Risks & Mitigations

**Risk 1:** Frontmatter schema split breaks existing user adapters that emit only `verified: <date>`.
**Mitigation:** Adapters can map legacy `verified` to the most conservative of the new fields (`source_verified_against_original: false` unless adapter has affirmative source-acquisition signal). Document migration path in `academic-pipeline/references/literature_corpus_consumers.md`.

**Risk 2:** Cite-Time Provenance Check warnings are noisy in early-corpus drafts.
**Mitigation:** Markers are draft-only and removed before final output. The hard gate is at format-conversion only. Users self-pace marker resolution.

**Risk 3:** Session Drift Log produces "yet another file to read" with low signal-to-noise.
**Mitigation:** Drift Log is end-of-session, not real-time. User reads only when reflecting on long sessions. Template structure surfaces top-3 actionable items first; full trajectory in collapsible section.

**Risk 4:** Retrieval fallback chain extends retrieval time meaningfully.
**Mitigation:** Steps are sequential with early-exit on first content-match success. Wayback CDX is fast (<5s); author-website grep is moderate; OA aggregators are batch-able; chain exhaustion takes <30s for typical paper. Acceptable for batch retrieval. Default-ON for the 5 mechanical auto-steps **without env-flag opt-out** is intentional (per Q6 amend) — under v3.6.5+ ARS the corpus is already user-owned via `literature_corpus[]` adapters; there is no failure mode where a user wants single-channel retrieval back. RG human-handoff is the explicit safety boundary: default-ON never means automated outreach (per round-1 codex F-007).

**Risk 5:** Spec is misread as enforcement of user behavior.
**Mitigation:** §2.2 explicitly states "no keep-on-track enforcement." All warnings are advisory; only `formatter_agent` enforces a hard gate, and that gate exists to prevent silent shipment of unverified citations to formal output — a different concern from in-session user behavior.

**Risk 6 (round-1 codex F-001 amend):** Standalone-mode finalizer fails to fire — a draft from `academic-paper full` mode (no pipeline orchestrator) reaches `formatter_agent` with unresolved bare `<!--ref:slug-->` comments and gets hard-blocked, leaving the user no resolver path.
**Mitigation:** Step 3c ships per-skill `cite_provenance_finalizer_agent` for both `academic-paper` and `deep-research` standalone modes. Standalone-mode test (acceptance criterion #11) explicitly exercises this path. If a future skill adds a new mode that bypasses both the pipeline orchestrator AND the per-skill finalizer, the v3.7.1 lint should reject the dispatch as `cite_provenance_finalizer_unwired`.

**Risk 7 (round-1 codex F-004 amend):** v3.7.1 lint widens the v3.6.7 frozen manifest scope and re-opens 18 codex rounds of v3.6.7 convergence work.
**Mitigation:** Step 0 introduces `scripts/v3_6_8_inversion_manifest.json` (filename retains roadmap-slot namespace per Q7) and `scripts/check_v3_6_8_pattern_protection.py` as **separate** artifacts from the v3.6.7 frozen manifest. Step 0 acceptance includes v3.6.7 lint regression PASS gate. v3.7.1 PRs that touch any file in v3.6.7's frozen manifest list require an explicit "byte-equivalent v3.6.7-tagged block preserved" SHA assertion (per Step 0 canonical range definition / round-3 R3-003 amend).

---

## 9. Open Questions

All four original §9 open questions are now **closed** by the 2026-05-07 brainstorm + round-1 codex amend cycle:

| # | Original question | Resolution |
|---|---|---|
| 1 | Schema 9 location of Drift Log artifact (passport.session_history[] or peer file?) | **Closed by Q3**: peer file `<session>_drift_log.md`; Schema 9 integration deferred to v3.7.x+ (see §6 Out-of-Scope). |
| 2 | ResearchGate Request Full-Text in auto-chain or human-mediated step? | **Closed by round-1 codex F-007**: human-handoff terminal step (NOT in auto-chain); auto-chain emits `pending_user_action: researchgate_request_<refcode>`; default-ON does not apply to RG. |
| 3 | Cite-Time hook fires on every emission or only at deliverable-finalization? | **Closed by Q4 → Q8 supersede**: per-emission placeholder + per-stage (pipeline) or per-deliverable (standalone) finalize. Hybrid architecture mirrors v3.6.7 Step 6 audit_artifact gate. |
| 4 | `human_read_source` user signal via UI/command or inference? | **Closed by Q2 + round-1 codex F-005**: explicit `/ars-mark-read <citation_key>` command writes to peer file `<session>_human_read_log.yaml`; orchestrator merges at frontmatter-read time; field is derived, never stored on entry (§3.6 Human-Read Signal Protocol). |

No open questions remain after round-1 codex amend. Round-2 codex review will run to confirm 0-finding convergence on the post-surgical-edit body before implementation begins (per `feedback_codex_iterative_spec_review_to_zero.md`).

---

## 10. Spec Traceability

Each pattern in §3 is traceable to a specific event in the 2026-04-30 session:

| Pattern | Generative event | Memory entry |
|---------|------------------|--------------|
| D1 | `verified: 2026-04-30` written on entries that were never cross-checked against original | `feedback_ars_verification_provenance_layer.md` |
| D2 | Round 3 codex audit reported "ADDRESSED" without disclosing 22/31 split | `feedback_ars_audit_scope_disclosure.md` |
| D3 | Risk articulated: user could have written chapter prose citing description-only entries before realizing scope gap | `feedback_ars_verification_provenance_layer.md` (cite-time provision) |
| D4 | User repeatedly left phase to verify; session-end visibility of trajectory absent | `feedback_ars_user_drift_is_verification_behavior.md`, `feedback_ars_session_drift_log.md` |
| D5 | F3 Wayback recovery + E1 Harvey personal-site recovery + PMu wrong-record content match failure | `feedback_ars_retrieval_fallback_chain.md` |

Patterns are not speculative; each is a real-world hallucination-defense gap that materialized in production use.
