"""Prompt-lock pin (phase 112, task 03 — owner decision iii, 2026-09-14). The persona + HONESTY GATE text is **locked verbatim** (PLAN §6): it changes through the plan, never in code. This module byte-pins the locked prompt constants against their pre-phase-112 anchor values — sha256 + exact prefix/suffix + total length, so *any* byte change (option (i)'s copy tightening, option (ii)'s plan amendment, or an accidental edit) fails loudly until the anchors are re-cut as part of the same plan revision. ``tests.unit.test_prompts`` pins the assembled-prompt structure and the behavioral contracts on top of these constants; this file pins the constants themselves. """ from __future__ import annotations import hashlib from app.rag.prompts import ( ORIGIN_RULE, PERSONA, SEARCH_DISCIPLINE_RULE, SUGGEST_INTRO, TOOLS_SECTION, _base, build_deflect_prompt, ) def _sha256(text: str) -> str: return hashlib.sha256(text.encode("utf-8")).hexdigest() # ---------- PERSONA (the locked base of BOTH the HIGH and LOW prompts) ---------- #: Pre-phase-112 anchors for ``PERSONA`` (the ``{relevance}`` placeholder #: and the line wrapping included). PERSONA_SHA256 = "e31792a73e64c53853097e0f7b6df8b96c5f2d05c286944c3edba16dde7777fe" PERSONA_LEN = 706 PERSONA_PREFIX = ( 'You are "Brain of Reese" — the digital brain of Reese, a self-hoster and\n' "homelab tinkerer. Personality: chippy, upbeat, warm, and genuinely\n" "optimistic about the user's ability to do things.\n" "\n" "Rules:\n" ) PERSONA_SUFFIX = ( "4. Never invent facts, hosts, or steps that are not in the context.\n" "5. Keep answers tight: short paragraphs, bullets where helpful.\n" "\n" "{relevance}" ) def test_persona_byte_locked() -> None: """Any byte change to the locked persona (opening, any rule line, the ```` placeholder) fails on the sha256; the prefix/suffix anchors name the damaged region for the diff.""" assert len(PERSONA) == PERSONA_LEN assert _sha256(PERSONA) == PERSONA_SHA256 assert PERSONA.startswith(PERSONA_PREFIX) assert PERSONA.endswith(PERSONA_SUFFIX) def test_high_and_low_bases_byte_locked() -> None: """``_base`` only substitutes ``{relevance}`` — the per-mode base lengths pin the substitution against a moved or re-spelled placeholder in the locked text.""" assert len(_base("HIGH")) == 699 # PERSONA_LEN - 11 + 4 assert len(_base("LOW")) == 698 # PERSONA_LEN - 11 + 3 # ---------- TOOLS_SECTION (the HIGH prompt's locked ```` copy) ---------- #: Anchors for ``TOOLS_SECTION`` — pre-phase-112 values, RE-CUT for #: phase 118 (task 04, A6, owner directive 2026-09-15): the ``read`` #: clause was rewritten for the summary-seed mode (the ```` #: section holds SUMMARIES — ``read`` adds the full text; only an #: already-read document is refused). RE-CUT again for phase 141 #: (task 02): the re-read sentence was re-cut to the coverage-true #: form — do not re-read a document read IN FULL (answer from it); #: a PARTIAL document (a range read, or a truncated read) is not #: complete in the context until read all — read the other parts with #: ``offset``/``limit``. RE-CUT again for phase 145 (task 02): the #: ``read`` clause gains the original-source rule — :data:`ORIGIN_RULE`, #: the one sentence-group appended at the ``read`` clause's end (the #: truncation workflow sentence) and BEFORE the ``grep`` clause begins #: (the ``origin:`` line is a read-result fact; the rule binds the #: ANSWER that uses what the read added). Only that sentence-group was #: inserted — the prefix (the ``ls``-clause opening) and the suffix #: (the discipline-rules ending) survived byte-identical, so they are #: the same anchors as pre-phase-145; the pre-phase-145 sha/length are #: kept below for the chained diff-style pin. RE-CUT again for phase 162 #: (task 03, LOCKED A3+A4): the ``grep`` sentence's ``(case-insensitive)`` #: parenthetical widened to the folded contract ``(case- and #: accent-insensitive — accents fold: besta matches BESTÅ)``, and the #: LOCKED search-discipline sentence (:data:`SEARCH_DISCIPLINE_RULE`) was #: inserted immediately after the grep sentence (before the ``For a normal #: search pass`` clause). Only those two byte-groups moved — the prefix #: (the ``ls``-clause opening) and the suffix (the discipline-rules #: ending) survive byte-identical; the pre-phase-162 sha/length are kept #: below for the chained diff-style pin. TOOLS_SECTION_SHA256 = "988642f9dc6bb2a4a1d44a83b5368ff4cdb9df4e181b2fe3dc2fb241b1857595" TOOLS_SECTION_LEN = 3818 # The pre-phase-162 anchors — the section BEFORE phase 162's grep-fold + # search-discipline insertion. Kept for the chained diff-style pin. TOOLS_SECTION_PRE_PHASE_162_SHA256 = ( "41a84885be98d4e15b95205694d59d364296a30e27758d39ae737881d5bacaa7" ) TOOLS_SECTION_PRE_PHASE_162_LEN = 3279 # The grep contract parenthetical exactly as it changed in phase 162 # (LOCKED A3): the pre-phase ``(case-insensitive)`` vs the folded one now # embedded in ``TOOLS_SECTION``. Used to revert phase 162 for the diff pin. _GREP_CONTRACT_PRE_PHASE_162 = "(case-insensitive)" _GREP_CONTRACT_PHASE_162 = ( "(case- and accent-insensitive — accents fold: `besta` matches `BESTÅ`)" ) TOOLS_SECTION_PREFIX = ( "\n" "You may extend your context with three tools. `ls` lists the " "knowledge base as a tree, one level at a time: " ) TOOLS_SECTION_SUFFIX = ( "Never repeat a call that was refused or already succeeded — the refusal " "already told you the correct form. Answer as soon as you have what " "you need.\n" ) #: The pre-phase-145 anchors — the section BEFORE :data:`ORIGIN_RULE` was #: inserted. Kept for the diff-style pin: the ONLY byte change is the #: rule's insertion, so removing the rule reproduces these exact bytes. TOOLS_SECTION_PRE_PHASE_145_SHA256 = ( "3671680bbf4e04efe1186690c18d24869e4974ceb29485cedc3e34a9286bf3b2" ) TOOLS_SECTION_PRE_PHASE_145_LEN = 2656 #: Phase 145 (task 02) — the original-source rule the ``read`` teaching #: carries is :data:`app.rag.prompts.ORIGIN_RULE` (imported above, LOCKED #: verbatim). :data:`TOOLS_SECTION` embeds that exact sentence-group at #: the ``read`` clause's end (the truncation workflow sentence) and #: BEFORE the ``grep`` clause begins. A read result for a git-sourced #: document carries an ``origin:`` line (and a ``branch:`` line when a #: branch is pinned) — the read contract's fact — so when the answer uses #: such a document it includes the original source in the answer: a link #: to the repository (the ``origin`` line) with the document's path (the #: ``Document …`` header) named and the pinned branch when one is shown, #: as the repository's file-view URL where the model can tell it #: (``/blob//``), or the repository URL plus the #: path as plain text otherwise. The rule is CONDITIONAL on the ``origin`` #: line's presence — a local-sourced document's read result carries none, #: so the rule adds nothing to those answers (the model has no URL to #: cite; it must not invent one — the sentence's conditioning does that #: job). def test_tools_section_byte_locked() -> None: """The ```` teaching is LOCKED verbatim too (the E2E mock keys on the ```` marker's presence; the wording is the owner's): sha256 + exact prefix/suffix + total length.""" assert len(TOOLS_SECTION) == TOOLS_SECTION_LEN assert _sha256(TOOLS_SECTION) == TOOLS_SECTION_SHA256 assert TOOLS_SECTION.startswith(TOOLS_SECTION_PREFIX) assert TOOLS_SECTION.endswith(TOOLS_SECTION_SUFFIX) def test_tools_section_origin_rule_verbatim_at_its_position() -> None: """Phase 145 (task 02): the original-source rule is LOCKED verbatim and sits at its EXACT position — the ``read`` clause's end (the truncation workflow sentence) and BEFORE the ``grep`` clause begins. The sentence-group is pinned byte-for-byte, and the surrounding boundary (the truncation sentence's tail → the rule → the ``grep`` clause's opening) is pinned as one contiguous substring, so a move or re-spelling of ANY byte (the rule's or the boundary's) fails.""" # Verbatim presence. assert ORIGIN_RULE in TOOLS_SECTION assert TOOLS_SECTION.count(ORIGIN_RULE) == 1 # exactly once # Exact position: after the truncation sentence, before the grep # clause — one contiguous span, no drift at either seam. assert ( "it searches the whole document. " + ORIGIN_RULE + " `grep` locates an exact string" ) in TOOLS_SECTION def test_tools_section_search_discipline_rule_verbatim_at_its_position() -> None: """Phase 162 (task 03, LOCKED A4): the search-discipline rule is LOCKED verbatim and sits at its EXACT position — immediately after the grep sentence (the ``…retry with the plain text you expect to see.`` clause) and BEFORE the ``For a normal search pass`` clause. The rule + its exact boundaries are pinned as one contiguous span, so a move or re-spelling of ANY byte fails.""" assert SEARCH_DISCIPLINE_RULE in TOOLS_SECTION assert TOOLS_SECTION.count(SEARCH_DISCIPLINE_RULE) == 1 # exactly once assert ( "retry with the plain text you expect to see. " + SEARCH_DISCIPLINE_RULE + " For a normal search pass only `pattern`" ) in TOOLS_SECTION def test_tools_section_grep_fold_contract_present() -> None: """Phase 162 (task 03, LOCKED A3): the grep sentence now states the FOLDED contract — the ``(case-insensitive)`` parenthetical is replaced byte-for-byte by the folded one, and the old one is gone.""" assert _GREP_CONTRACT_PHASE_162 in TOOLS_SECTION assert _GREP_CONTRACT_PRE_PHASE_162 not in TOOLS_SECTION def test_tools_section_phase162_and_145_are_the_only_byte_changes() -> None: """Chained diff-style pin: the ONLY byte changes are phase 162's (the folded grep contract + :data:`SEARCH_DISCIPLINE_RULE`) and phase 145's (:data:`ORIGIN_RULE`). Reverting phase 162 (drop the rule + its separating space, restore the pre-phase grep parenthetical) reproduces the pre-phase-162 section byte-for-byte; reverting the origin rule on top of that reproduces the pre-phase-145 section byte-for-byte.""" # Revert phase 162 -> pre-phase-162. pre_162 = TOOLS_SECTION.replace(SEARCH_DISCIPLINE_RULE + " ", "") pre_162 = pre_162.replace(_GREP_CONTRACT_PHASE_162, _GREP_CONTRACT_PRE_PHASE_162) assert len(pre_162) == TOOLS_SECTION_PRE_PHASE_162_LEN assert _sha256(pre_162) == TOOLS_SECTION_PRE_PHASE_162_SHA256 # Revert phase 145 -> pre-phase-145. pre_145 = pre_162.replace(ORIGIN_RULE + " ", "") assert len(pre_145) == TOOLS_SECTION_PRE_PHASE_145_LEN assert _sha256(pre_145) == TOOLS_SECTION_PRE_PHASE_145_SHA256 # ---------- the LOW prompt's locked DEFLECT_MODE body ---------- #: The ``DEFLECT_MODE`` body exactly as it was pre-phase-112 (the #: phase-71 plain-text line included) — inline in #: :func:`app.rag.prompts.build_deflect_prompt`, so it is pinned through #: the built prompt rather than a module constant. LOW_BODY_SHA256 = "c9868cfccdd0ff79d7c1de5df5f6dea0182d3726ca912c9ef609ab54b563a0a4" LOW_BODY_LEN = 259 LOW_BODY = ( "DEFLECT_MODE: retrieval was weak — the titles below are the closest " "your notes come to the question. They are titles only; do not pretend " "they answer it. Use them to propose 2-3 alternative questions.\n" "Reply in plain text only — you have no tools in this mode." ) def test_deflect_body_byte_locked() -> None: """The LOW build = locked base + exactly the locked DEFLECT_MODE body + the weak-hit title list — byte for byte (the mock keys on the ``DEFLECT_MODE`` marker's presence; the body wording is locked).""" assert len(LOW_BODY) == LOW_BODY_LEN assert _sha256(LOW_BODY) == LOW_BODY_SHA256 assert build_deflect_prompt(["T1", "T2"]) == _base("LOW") + "\n" + LOW_BODY + "\n- T1\n- T2" prompt = build_deflect_prompt(["T1", "T2"]) assert prompt.count(LOW_BODY) == 1 assert prompt.index("DEFLECT_MODE") < prompt.index( "Reply in plain text only" ) # the marker precedes the plain-text line #: The full LOW prompt build on the canonical fixture titles — sha-pinned #: (phase 118, task 03): the deflection path is UNTOUCHED by the #: summary-seed re-revision (LOCKED A8) — the same inputs must produce #: the pre-phase bytes, so this anchor is a pre-phase-118 value. LOW_PROMPT_SHA256 = "726eddb4eb3bcc26c840011f6f8635d6af55aa09d4d064bbb9e256caa9665837" LOW_PROMPT_LEN = 968 def test_low_prompt_build_byte_identical_to_pre_phase() -> None: """Phase 118 contract: the LOW prompt output is byte-identical to pre-phase for identical inputs — the summary seeding (and the new ``SUGGEST_INTRO`` line) never leaks into the deflection path.""" prompt = build_deflect_prompt(["T1", "T2"]) assert len(prompt) == LOW_PROMPT_LEN assert _sha256(prompt) == LOW_PROMPT_SHA256 assert "SUGGEST_INTRO" not in prompt and "" not in prompt # ---------- SUGGEST_INTRO (phase 118 framing, re-cut for phase 119, LOCKED A5) ---------- #: Anchors for ``SUGGEST_INTRO`` — the ```` section's intro #: line (the owner's "start here if these summaries seem right to you" #: framing, TODO L3, phase 118). RE-CUT for phase 119 (task 04, LOCKED #: A5, owner directive 2026-09-16): the final sentence was replaced #: with the cite-discipline sentence (cite only the documents read — or #: the suggested document answered from without reading — never a #: document neither read nor used), closing the live confabulation in #: which the model cited a file it never read; the phase-118 "cite the #: document(s) you used, by path" sentence is retired. Only that #: sentence moved — the start-here framing, the ``read`` pointer, and #: the full-text clause survive byte-identical, so the prefix anchor is #: the same as pre-phase-119. The E2E mock's ``_document_block`` parser #: is regex-based over the block markup (which stays byte-stable around #: the intro), so this constant is a prompt-copy lock, pinned the way #: ``TOOLS_SECTION`` is: sha256 + prefix + total length. ``PERSONA``, #: ``TOOLS_SECTION``, and the LOW body anchors above stay byte-identical #: — this change touches no other constant. SUGGEST_INTRO_SHA256 = "c6ffbb19975cbf184910a9a8e8fdea101c16f5d3eecb872fb07afeabd2763302" SUGGEST_INTRO_LEN = 460 SUGGEST_INTRO_PREFIX = ( "The blocks below are the summaries of the top-ranked documents for " "your question — start here if one seems right to you: " ) def test_suggest_intro_byte_locked() -> None: """The start-here framing is LOCKED copy (phase 118; the final sentence re-cut by phase 119, LOCKED A5): sha256 + exact prefix + total length; the four contracts it must carry (summaries are the starting points; ``read`` adds the full text, which is NOT in the prompt until read; the phase-119 cite discipline — cite only what was read, or the suggested document answered from without reading, never a document neither read nor used) are pinned as substrings.""" assert len(SUGGEST_INTRO) == SUGGEST_INTRO_LEN assert _sha256(SUGGEST_INTRO) == SUGGEST_INTRO_SHA256 assert SUGGEST_INTRO.startswith(SUGGEST_INTRO_PREFIX) assert "call `read" in SUGGEST_INTRO assert "combined `source/path`" in SUGGEST_INTRO assert "its full text is not in the prompt until you read it" in SUGGEST_INTRO assert ( "Cite only the document(s) you read — or, if you answered from a " "suggested summary without reading it, cite that suggested " "document — never a document you neither read nor used." ) in SUGGEST_INTRO # The retired phase-118 final sentence is gone from the constant. assert "Cite the document(s) you used, by path." not in SUGGEST_INTRO