docs(6209): forty test files — design cascade and stylesheet, embeddings, family canon, forge, backup round trips, inception, placement, platforms, moments, rule move and verification, search scope, facets
Module and test docstrings state what is pinned without the record number or step that introduced it. Incident accounts become the failure shape in the present tense: the pipefail head, the code_shapes import, the export order, the facet dialects, the cross-kind repeat, the write-once kind. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
"""The auto-inject query carries the conversation beside a thin prompt (#4364).
|
||||
"""The auto-inject query carries the conversation beside a thin prompt.
|
||||
|
||||
The notes arm used to retrieve against the operator's typed words alone, and a
|
||||
mid-session follow-up — "yes do that", "now fix the filter" — names nothing a
|
||||
record can match. The hook now reads the tail of the last assistant reply out
|
||||
The operator's typed words alone are a poor query: a mid-session follow-up —
|
||||
"yes do that", "now fix the filter" — names nothing a record can match. The
|
||||
hook reads the tail of the last assistant reply out
|
||||
of the transcript and sends it as `ctx`; the server appends it to a SHORT
|
||||
prompt only. Two halves, pinned separately: what the server builds, and what
|
||||
the hook extracts.
|
||||
@@ -103,10 +103,10 @@ def test_no_transcript_is_silence_not_failure(tmp_path):
|
||||
assert recent(tmp_path, []) == ""
|
||||
|
||||
|
||||
# --- what a menu line carries (#4364) ----------------------------------------
|
||||
# --- what a menu line carries -----------------------------------------------
|
||||
#
|
||||
# The name, the kind and System, and the WHOLE matched passage — once. A repeat
|
||||
# is a pointer. These pin the shape against the three ways it had gone wrong:
|
||||
# is a pointer. These pin the shape against the three ways it goes wrong:
|
||||
# a trigger-composed title rendered as the line (1,500+ chars), the passage cut
|
||||
# to its head (which was the title again), and a `seen` repeat re-rendered whole.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""The CI-side token check (#2277).
|
||||
"""The CI-side token check.
|
||||
|
||||
The checker is stdlib-only and lives in scripts/ so CI can run it without an
|
||||
install, so these tests import it by path rather than as a package.
|
||||
@@ -45,7 +45,7 @@ def test_declarations_after_a_comment_are_not_lost():
|
||||
|
||||
|
||||
def test_the_supersedes_block_is_read_from_the_sheet_not_hardcoded():
|
||||
"""Rule #115: the checker must know nothing about any install's palette.
|
||||
"""The checker knows nothing about any install's palette.
|
||||
Everything it enforces comes out of the stylesheet it is pointed at."""
|
||||
assert check.superseded_literals(SHEET) == {
|
||||
"#fff": "--fs-text-primary",
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
"""Every create_* tool says what it is NOT for (#3123).
|
||||
"""Every create_* tool says what it is NOT for.
|
||||
|
||||
WHY THIS EXISTS
|
||||
|
||||
Scribe's record kinds are reached for interchangeably — a note written where
|
||||
a task was owed, a rule written where a snippet belonged — and the moment of
|
||||
choice is the only moment a correction is cheap. The tool docstring IS the
|
||||
agent-facing contract (rule 119 puts product guidance there and nowhere
|
||||
else), so a docstring that only documents parameters answers "how do I call
|
||||
agent-facing contract (product guidance lives there and nowhere else), so a docstring that only documents parameters answers "how do I call
|
||||
this" while leaving "should I be calling this at all" unasked.
|
||||
|
||||
The gap was lopsided before this: `create_rule` and `start_planning` both
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""The parent chain: walking it, and refusing to close it (milestone #254 step 1).
|
||||
"""The parent chain: walking it, and refusing to close it.
|
||||
|
||||
Pure functions over a `{id: parent_id}` literal, so a whole hierarchy is one line
|
||||
of setup and no database is involved. That is the reason the cascade lives in its
|
||||
@@ -99,7 +99,7 @@ def test_the_guard_survives_a_hierarchy_that_is_already_corrupt():
|
||||
|
||||
# --- resolution -------------------------------------------------------------
|
||||
#
|
||||
# The cascade proper (milestone #254 step 2). Hierarchies are stated as literals
|
||||
# The cascade proper. Hierarchies are stated as literals
|
||||
# because resolve_tokens is pure and duck-typed — which is the whole reason it
|
||||
# lives here rather than inside the service.
|
||||
|
||||
@@ -384,7 +384,7 @@ def test_rows_without_a_supersedes_attribute_at_all_still_resolve():
|
||||
def test_rationale_cascades_like_purpose_and_is_a_different_question():
|
||||
"""`purpose` is what the token is FOR; `rationale` is why it is this value.
|
||||
Rules carry the second routinely ("Success = Moss, aligned by design") and a
|
||||
token row had nowhere to put it until now."""
|
||||
token row needs a place to put it."""
|
||||
resolved = _by_name(resolve_tokens(
|
||||
APP, PARENTS,
|
||||
{
|
||||
|
||||
@@ -120,8 +120,8 @@ def test_the_header_says_what_the_sheet_is_for():
|
||||
# --- modes ------------------------------------------------------------------
|
||||
|
||||
def test_base_goes_on_the_root_selector_and_other_modes_layer_over_it():
|
||||
"""Matches the convention already in the codebase, and the one-way scoping
|
||||
#251 recorded: light on `:root`, dark layered on an attribute selector."""
|
||||
"""Matches the convention already in the codebase, and its one-way
|
||||
scoping: light on `:root`, dark layered on an attribute selector."""
|
||||
css = render_stylesheet([
|
||||
design_token_stub(name="--fs-bg", value_by_mode={"base": "#f5f1e8", "dark": "#14171a"}),
|
||||
])
|
||||
@@ -188,7 +188,7 @@ def test_a_declared_token_with_no_value_appears_as_a_comment_not_a_silence():
|
||||
|
||||
|
||||
def test_an_empty_system_renders_a_sheet_with_no_blocks_rather_than_failing():
|
||||
"""A system with no tokens is an ordinary state (rule #115), including one
|
||||
"""A system with no tokens is an ordinary state, including one
|
||||
that was just created."""
|
||||
css = render_stylesheet([])
|
||||
assert "{" not in css
|
||||
|
||||
@@ -9,7 +9,7 @@ the dangerous one: a recurring task embedded to a different shape than the rest
|
||||
of the corpus is ranked against documents it doesn't match, and nothing reports
|
||||
it. A wrong vector returns results; it just returns the wrong ones.
|
||||
|
||||
It is also the precondition for #2486. A dev-log's vector separates from five
|
||||
It is also the precondition for comparing document shapes. A dev-log's vector separates from five
|
||||
unrelated dev-logs by 0.023 where a snippet separates by 0.153, and the leading
|
||||
explanation is shape — a snippet states its purpose twice in a short document.
|
||||
Testing an alternative against three copies would mean testing a shape that
|
||||
@@ -77,5 +77,5 @@ def test_nothing_else_builds_the_embedding_document_itself():
|
||||
f"these build the embedding document inline instead of calling "
|
||||
f"embedding_text(): {offenders}. One definition — an inlined copy is "
|
||||
f"ranked against a corpus it no longer matches the moment the shape "
|
||||
f"changes, and nothing reports it (#2486)."
|
||||
f"changes, and nothing reports it."
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""The embedding refresh must LOSE to a delete, not race it (#3262).
|
||||
"""The embedding refresh must LOSE to a delete, not race it.
|
||||
|
||||
Both upserts replace a record's vectors as delete-then-insert. That takes two
|
||||
row locks — the chunk rows, then the parent row via the insert's foreign key —
|
||||
@@ -32,7 +32,7 @@ def _mock_session(lock_result: object = 7, execute_side_effect=None):
|
||||
session = MagicMock()
|
||||
claimed = MagicMock()
|
||||
claimed.scalar_one_or_none.return_value = lock_result
|
||||
# A task's document carries its work logs (#4251), so the refresh reads
|
||||
# A task's document carries its work logs, so the refresh reads
|
||||
# task_logs before it builds chunks. Answered explicitly — left to
|
||||
# autovivify, `list(result.all())` would raise and be swallowed, and these
|
||||
# tests would be exercising the failure path without saying so.
|
||||
@@ -72,7 +72,7 @@ async def test_a_note_refresh_claims_the_row_before_rewriting_its_vectors():
|
||||
|
||||
sqls = [compiled_sql(c.args[0], dialect=PG) for c in session.execute.call_args_list]
|
||||
# Located by what they ARE rather than by position: the work-log read a
|
||||
# task's document needs (#4251) runs before any of this, and an index is
|
||||
# task's document needs runs before any of this, and an index is
|
||||
# not what the claim is about.
|
||||
claim = next(i for i, sql in enumerate(sqls) if "FOR KEY SHARE NOWAIT" in sql)
|
||||
replace = next(
|
||||
|
||||
@@ -74,7 +74,7 @@ async def test_get_embedding_propagates_model_load_failures():
|
||||
await get_embedding("x")
|
||||
|
||||
|
||||
# ─── query_embedding_memo (milestone 456 step 1) ─────────────────────────────
|
||||
# ─── query_embedding_memo ────────────────────────────────────────────────────
|
||||
|
||||
|
||||
def _counting_embeddings():
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""The promotion engine without a database (milestone 463 step 3).
|
||||
"""The promotion engine without a database.
|
||||
|
||||
The parts that decide — which citations claim lineage, which criteria veto —
|
||||
are pure and pinned here, beside the doors' wiring: the triggers ride the
|
||||
@@ -89,7 +89,7 @@ def test_proven_needs_named_evidence():
|
||||
|
||||
|
||||
def test_the_criteria_the_agent_is_told_are_the_ones_enforced():
|
||||
"""Rule 119: the criteria are product text. The promote tool's docstring
|
||||
"""The criteria are product text. The promote tool's docstring
|
||||
must name every criterion the service checks, by its parameter name."""
|
||||
doc = family_tools.promote_family_idea.__doc__
|
||||
for key in CRITERIA_KEYS:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""The adoption ledger without a database (milestone 463 step 4).
|
||||
"""The adoption ledger without a database.
|
||||
|
||||
The parts that decide are pure and pinned here: what an assessment needs
|
||||
before it can be recorded, what each ground of the conflict order needs —
|
||||
@@ -166,7 +166,7 @@ def test_no_reference_at_all_points_at_the_idea():
|
||||
# --- the product text and the doors ---------------------------------------------------
|
||||
|
||||
def test_the_outcomes_the_agent_is_told_are_the_ones_enforced():
|
||||
"""Rule 119: the outcomes and the order are product text. The tool
|
||||
"""The outcomes and the order are product text. The tool
|
||||
docstrings must name every outcome and every ground the service checks,
|
||||
in the service's order."""
|
||||
assess_doc = tool_doc("scribe.mcp.tools.family", "assess_family_adoption")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""How family canon reaches a session (milestone 463 step 6), without a
|
||||
"""How family canon reaches a session, without a
|
||||
database: the line enter_project carries, the skill and its triggers, and the
|
||||
pointers every other surface gives to it. Retrieval reach, the readout's
|
||||
counts and the owed answers against Postgres are in
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Forge-connection tokens are stored sealed (milestone 523, #5877).
|
||||
"""Forge-connection tokens are stored sealed.
|
||||
|
||||
Migration 0122 seals the rows that existed before, with its OWN frozen copy of
|
||||
the v1 key derivation (so a later edit to services/secrets.py can never change
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Forge push webhook (#2691) — signature gate, payload parsing, and the
|
||||
"""Forge push webhook — signature gate, payload parsing, and the
|
||||
end-to-end drift flag on real Postgres.
|
||||
|
||||
The webhook is the seam that makes verification scale: a push names exactly
|
||||
@@ -43,7 +43,7 @@ def test_signature_gate():
|
||||
|
||||
|
||||
def test_delivered_signature_reads_both_forges_headers():
|
||||
"""#2693: GitHub signs the same HMAC but ships it as
|
||||
"""GitHub signs the same HMAC but ships it as
|
||||
X-Hub-Signature-256: sha256=<hex> — the whole webhook payload mapping is
|
||||
this header, so pin it."""
|
||||
hexsig = _sign(b"{}")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""The create gate's similarity bars are settings, clamped and fail-open (#4385)."""
|
||||
"""The create gate's similarity bars are settings, clamped and fail-open."""
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
"""Under `pipefail`, an early-exiting `head` must not void the output it kept (#4042).
|
||||
"""Under `pipefail`, an early-exiting `head` must not void the output it kept.
|
||||
|
||||
The hooks run with `set -uo pipefail`. `hits=$(git grep -l … | head -4) ||
|
||||
hits=""` lost its four hits whenever git grep was still writing when head
|
||||
exited: SIGPIPE, a failed substitution, and the fallback wiped the result. It
|
||||
only showed on big outputs, so the by-name duplicate arm went silent for
|
||||
hits=""` loses its four hits whenever git grep is still writing when head
|
||||
exits: SIGPIPE, a failed substitution, and the fallback wipes the result. It
|
||||
only shows on big outputs, so the by-name duplicate arm goes silent for
|
||||
exactly the most-duplicated names.
|
||||
|
||||
Two halves: the real function on a repo big enough to overflow the pipe, and
|
||||
the check_plugin pattern that keeps the shape out of every hook (shown able to
|
||||
fail, rule #167).
|
||||
fail).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
"""Real-Postgres round trip for code_shapes (#4197).
|
||||
"""Real-Postgres round trip for code_shapes.
|
||||
|
||||
**What this guards is a column that was simply not there.** `code_shapes`
|
||||
exported `reason_code`, `recheck_at` and `diverges_from` and imported none of
|
||||
them — a restore reported success and came back with every judgment's verdict
|
||||
**What this guards is a column the import leaves out.** If `code_shapes`
|
||||
exports `reason_code`, `recheck_at` and `diverges_from` and imports none of
|
||||
them, a restore reports success and comes back with every judgment's verdict
|
||||
and no code for why, every recheck flag cleared, and every divergence pointer
|
||||
gone. The unit-level column guard in `test_services_backup.py` is what found
|
||||
it and is what stops it recurring; this file is the behavioural half, because
|
||||
gone. The unit-level column guard in `test_services_backup.py` catches a
|
||||
column missing from either side; this file is the behavioural half, because
|
||||
"the builder passes the kwarg" and "the value survives a real restore" are
|
||||
different claims.
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
"""Real-Postgres check that the full export is ORDERED, so the backup file
|
||||
deduplicates between runs (milestone 523).
|
||||
deduplicates between runs.
|
||||
|
||||
Only Postgres shows this. An unordered select returns rows in heap order, and
|
||||
an UPDATE writes the row's new version at the end of the heap — so before
|
||||
export_full_backup ordered its queries, editing one old note moved it to the
|
||||
bottom of `notes`. Every byte after its old place shifted, and a restic run
|
||||
over the next backup stored most of the table again. A mocked session returns
|
||||
an UPDATE writes the row's new version at the end of the heap — so without an
|
||||
ORDER BY in export_full_backup, editing one old note moves it to the bottom of
|
||||
`notes`. Every byte after its old place shifts, and a restic run over the next
|
||||
backup stores most of the table again. A mocked session returns
|
||||
whatever order it was handed and could never catch it.
|
||||
"""
|
||||
import io
|
||||
|
||||
@@ -101,7 +101,7 @@ async def test_the_tar_restores_with_every_id_remapped(written):
|
||||
assert (note.project_id, note.milestone_id) == (project.id, milestone.id)
|
||||
assert note.body == "From the tar, not the JSON."
|
||||
assert note.status == "todo"
|
||||
# The Profile page travels with its user (#5879); a field left blank stays
|
||||
# The Profile page travels with its user; a field left blank stays
|
||||
# blank rather than restoring as the page's default.
|
||||
assert (profile.display_name, profile.tone) == ("Drill Owner", "technical")
|
||||
assert profile.interests == ["backups"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Real-Postgres round trip for rule_versions (milestone 323 step 1).
|
||||
"""Real-Postgres round trip for rule_versions.
|
||||
|
||||
Two things here cannot be shown with mocks, and both are the kind that fail
|
||||
QUIETLY — a restore reports success and hands back history that is wrong.
|
||||
@@ -7,7 +7,7 @@ QUIETLY — a restore reports success and hands back history that is wrong.
|
||||
A restore that writes it straight through succeeds and attaches every
|
||||
snapshot to whatever rule happens to hold that number here — an edit
|
||||
history filed against the wrong binding instruction, which is worse than
|
||||
no history at all. This is #3182's `arose_from_id` trap on a new table.
|
||||
no history at all. It is the same trap as a note's `arose_from_id`.
|
||||
|
||||
2. **A null actor does not drop the row.** `user_id` is SET NULL precisely so
|
||||
history outlives the account that wrote it, so the restore deliberately
|
||||
@@ -217,7 +217,7 @@ async def test_both_snapshots_come_back(restored):
|
||||
|
||||
|
||||
async def test_the_history_attaches_to_the_RESTORED_rule(restored):
|
||||
"""#3182's trap. The source rule still exists and holds a different id, so
|
||||
"""The remap trap. The source rule still exists and holds a different id, so
|
||||
a straight-through copy would file this history against it — or against
|
||||
whatever unrelated rule owns that number."""
|
||||
new_rule_id = restored["rule"].id
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""The adoption ledger against real Postgres (milestone 463 step 4).
|
||||
"""The adoption ledger against real Postgres.
|
||||
|
||||
What the unit lane can't show: an answer moves the row and logs exactly one
|
||||
decision; an owed answer files its task in the OWING project, tagged to the
|
||||
@@ -236,7 +236,7 @@ async def test_another_projects_answer_is_recorded_as_precedent(family):
|
||||
assert first["decision"]["id"] in second["decision"]["precedent_ids"]
|
||||
assert second["precedents"][0]["relation"] == "same idea, another project"
|
||||
assert second["precedents"][0]["project_title"] == "android one"
|
||||
# A precedent says its reason once: before/after are state only (#5131).
|
||||
# A precedent says its reason once: before/after are state only.
|
||||
assert second["precedents"][0]["reason"] == "the source app"
|
||||
assert "reason" not in second["precedents"][0]["after"]
|
||||
|
||||
@@ -392,7 +392,7 @@ async def test_the_matrix_hides_what_the_caller_cannot_read(family):
|
||||
assert all(i["note_id"] != family["note"] for i in matrix["ideas"])
|
||||
|
||||
|
||||
# --- the shape ledger as evidence (step 5) -------------------------------------------
|
||||
# --- the shape ledger as evidence ----------------------------------------------------
|
||||
|
||||
REPO = "git.example/android-two"
|
||||
KOTLIN_BODY = (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Real-Postgres checks for family canon's schema (milestone 463 step 1).
|
||||
"""Real-Postgres checks for family canon's schema.
|
||||
|
||||
Two kinds of claim live here, and both need a database:
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""The promotion engine against real Postgres (milestone 463 step 3).
|
||||
"""The promotion engine against real Postgres.
|
||||
|
||||
What the unit lane can't show: a promotion opens the right ledger rows and
|
||||
no others, a veto changes nothing but the log, an undo puts back exactly the
|
||||
@@ -279,9 +279,9 @@ async def test_a_repeat_with_no_shared_platform_is_silent(family):
|
||||
|
||||
|
||||
async def test_a_repeat_across_kinds_is_silent(family):
|
||||
"""A snippet whose only match is a NOTE is not a repeat (#5130): a dated
|
||||
release log scored 0.83 against a signed-APK CI snippet on shared
|
||||
vocabulary and was opened as a candidate. The stub hands back the
|
||||
"""A snippet whose only match is a NOTE is not a repeat: a dated
|
||||
release log can score above the bar against a signed-APK CI snippet on
|
||||
shared vocabulary alone, and would open as a candidate. The stub hands back the
|
||||
cross-kind hit directly, so this pins the trigger's own check, not the
|
||||
search filter in front of it."""
|
||||
async with async_session() as s:
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""A family idea reaches every project on its platform, and no other
|
||||
(milestone 463 step 6).
|
||||
"""A family idea reaches every project on its platform, and no other.
|
||||
|
||||
WHY THIS IS AN INTEGRATION TEST — the lesson-reach reasoning (#3730) holds
|
||||
WHY THIS IS AN INTEGRATION TEST — the lesson-reach reasoning holds
|
||||
here too: the reach is one `OR` inside the search's project filter, and only
|
||||
the ROWS that come back prove it. Every note embeds identically to the query,
|
||||
so scoping is the only thing that can separate them. The embedder is stubbed;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Real-Postgres integration tests for the forge keyring (#2778).
|
||||
"""Real-Postgres integration tests for the forge keyring.
|
||||
|
||||
Runs only in the CI integration lane (real Postgres, schema built by
|
||||
`alembic upgrade head`, which includes migration 0078's forge_connections
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Real-Postgres tests for "recently touched" in the enter_project handshake (#4045).
|
||||
"""Real-Postgres tests for "recently touched" in the enter_project handshake.
|
||||
|
||||
What a mock cannot show: that a work-log moves its task up the list even
|
||||
though logging never bumps the task's updated_at, and that a milestone whose
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
"""Real-Postgres integration tests for project inception (milestone 297).
|
||||
"""Real-Postgres integration tests for project inception.
|
||||
|
||||
What mocks can't prove: a decision's effects land through the real services
|
||||
(the design system points, the standard Systems seed once), the record is
|
||||
written last, a bad target applies nothing.
|
||||
|
||||
Rules are not part of inception since milestone 414: a rule in a rulebook is
|
||||
Rules are not part of inception: a rule in a rulebook is
|
||||
global and applies to every project, so there is nothing to subscribe to.
|
||||
"""
|
||||
import pytest
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""A lesson is reachable from a project it was not written on (step 3).
|
||||
"""A lesson is reachable from a project it was not written on.
|
||||
|
||||
WHY THIS IS AN INTEGRATION TEST
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
"""Real-Postgres tests for finding a plan by meaning (milestone 415, steps 3 and 4).
|
||||
"""Real-Postgres tests for finding a plan by meaning.
|
||||
|
||||
A project's roadmap written as milestones was invisible to recall: `search`
|
||||
covered notes, tasks and rules, so "is there already a plan for this?" had no
|
||||
tool. What a mock cannot show is the join scoping the vectors to a project and
|
||||
A project's roadmap is written as milestones, and `search` reaches them, so
|
||||
"is there already a plan for this?" has a tool. What a mock cannot show is the join scoping the vectors to a project and
|
||||
to what the caller may read, so these seed real milestones with hand-made
|
||||
vectors and stub only the embedder.
|
||||
"""
|
||||
@@ -84,7 +83,7 @@ async def test_a_project_the_caller_cannot_read_returns_nothing(roadmap):
|
||||
assert await _found(roadmap["stranger"]) == []
|
||||
|
||||
|
||||
# ── the plan gate (step 4): start_planning finds the plan before making another ──
|
||||
# ── the plan gate: start_planning finds the plan before making another ──
|
||||
|
||||
LONG = "Resolve works and editions against the metadata providers. " * 5
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Real-Postgres tests for an install's moment mappings (milestone 458 step 2).
|
||||
"""Real-Postgres tests for an install's moment mappings.
|
||||
|
||||
What these pin is what the in-session correction promises the operator: a
|
||||
mapping made is in force on the next call, a default switched off stays off,
|
||||
|
||||
@@ -32,7 +32,7 @@ def _vec(*nonzero_first):
|
||||
|
||||
|
||||
def _emb(note_id, user_id, chunk_index, vec):
|
||||
"""A chunk row at the current chunker version (#280, migration 0077)."""
|
||||
"""A chunk row at the current chunker version."""
|
||||
from scribe.services.embeddings import CHUNKER_VERSION, EMBEDDING_MODEL
|
||||
|
||||
return NoteEmbedding(
|
||||
@@ -63,7 +63,7 @@ async def seeded():
|
||||
# query vector will be [1,0,0,...]; near ~ identical (sim≈1.0),
|
||||
# far is orthogonal (sim≈0.0 -> filtered by the default threshold).
|
||||
# near gets a SECOND, weaker chunk (sim≈0.6) — the collapse to
|
||||
# best-chunk-per-note (#280) is under test: near must come back once,
|
||||
# best-chunk-per-note is under test: near must come back once,
|
||||
# at its best chunk's score, not twice.
|
||||
s.add(_emb(near.id, user.id, 0, _vec(1.0)))
|
||||
s.add(_emb(near.id, user.id, 1, _vec(0.6, 0.8)))
|
||||
@@ -94,7 +94,7 @@ async def test_semantic_search_ranks_and_thresholds_via_pgvector(seeded):
|
||||
assert near_id in ids
|
||||
assert far_id not in ids
|
||||
assert ids[0] == near_id
|
||||
# Chunk collapse (#280): near has TWO chunk rows above the floor (sim≈1.0
|
||||
# Chunk collapse: near has TWO chunk rows above the floor (sim≈1.0
|
||||
# and ≈0.6) and must appear exactly once, at its best chunk's score.
|
||||
assert ids.count(near_id) == 1
|
||||
top_score = results[0][0]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Real-Postgres tests for task placement (milestone 409 step 1).
|
||||
"""Real-Postgres tests for task placement.
|
||||
|
||||
What a mock cannot show: that step order is creation order rather than update
|
||||
order, that position and progress are computed over the steps the CALLER may
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Real-Postgres checks for platform membership (milestone 463 step 2).
|
||||
"""Real-Postgres checks for platform membership.
|
||||
|
||||
The one invariant: detection only ever ADDS, and only where nobody has
|
||||
answered. A refresh that overwrote a "no" would put a project back into a
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Real-Postgres proof that a batch create cannot be interfered with (#4016).
|
||||
"""Real-Postgres proof that a batch create cannot be interfered with.
|
||||
|
||||
What mocks cannot show: that the ids a placeholder is rewritten to are the ids
|
||||
the rows actually got, that two batches running at the same time each cite
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""Real-Postgres tests for moment proposals and judgments (milestone 458 step 7).
|
||||
"""Real-Postgres tests for moment proposals and judgments.
|
||||
|
||||
What the step promises, against the real tables:
|
||||
What the feature promises, against the real tables:
|
||||
- the pass reads only rules nobody has answered for, and any answer — a
|
||||
proposal, a mount, "no moment fits" — takes a rule off that list;
|
||||
- a proposal mounts nothing; a confirm mounts, a reject is kept, and a judged
|
||||
@@ -8,7 +8,7 @@ What the step promises, against the real tables:
|
||||
- an edit that takes a moment off a rule is a rejection the signal respects;
|
||||
- the signal counts SESSIONS, not opens, and asks once the bar is crossed;
|
||||
- only the owner can propose, judge, or feed the signal;
|
||||
- the misfire (step 7b): only a mount can misfire, reports count DAYS, the
|
||||
- the misfire: only a mount can misfire, reports count DAYS, the
|
||||
bar makes an unmount proposal, reject takes it off, confirm keeps it and
|
||||
stops the asking, and a re-mount starts the count again.
|
||||
"""
|
||||
@@ -196,7 +196,7 @@ async def test_the_open_resolves_acts_through_the_installs_mappings(world):
|
||||
assert (await _row(done.id, "work.deliver")).source == "signal"
|
||||
|
||||
|
||||
# ── The misfire (step 7b) ────────────────────────────────────────────────────
|
||||
# ── The misfire ──────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Real-Postgres tests for moving a rule between homes (milestone 414, step 3).
|
||||
"""Real-Postgres tests for moving a rule between homes.
|
||||
|
||||
A rule's home is its reach: a rulebook topic makes it global, a project makes
|
||||
it that project's. The alternative to a move — recreate the rule in the other
|
||||
@@ -84,7 +84,7 @@ async def test_a_project_rule_becomes_global_and_keeps_everything(homes):
|
||||
|
||||
|
||||
async def test_a_move_writes_no_version(homes):
|
||||
"""A version records what a rule SAID (milestone 323, decision 4). A move
|
||||
"""A version records what a rule SAID. A move
|
||||
changes where it binds, not a word of it."""
|
||||
before = len(await rv_svc.list_versions(homes["rule"]))
|
||||
await rulebooks_svc.move_rule(homes["rule"], homes["owner"], topic_id=homes["topic"])
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Real-Postgres tests for a rule's CHECK — the write half (milestone 312).
|
||||
"""Real-Postgres tests for a rule's CHECK — the write half.
|
||||
|
||||
What mocks cannot prove, and what the staleness sweep depends on:
|
||||
|
||||
@@ -132,7 +132,7 @@ async def test_editing_anything_else_leaves_the_stamp_alone(constraint):
|
||||
assert row.why.startswith("act_runner picks the shell")
|
||||
|
||||
|
||||
# ── the sweep itself (step 3) ──────────────────────────────────────────
|
||||
# ── the sweep itself ───────────────────────────────────────────────────
|
||||
|
||||
@pytest_asyncio.fixture
|
||||
async def rulebook_of_three():
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
"""Real-Postgres crowd tests: an in-scope record is found however many nearer
|
||||
records sit outside the scope (#4961; the rule search's is #4958's, in
|
||||
records sit outside the scope (the rule search's crowd test is in
|
||||
test_integration_rule_scope).
|
||||
|
||||
Ordered straight off a `*_embeddings` table, the planner can walk the HNSW
|
||||
index, which takes ~`hnsw.ef_search` (40) nearest chunks from every owner and
|
||||
project and only then applies the scope. Each test here puts 80 out-of-scope
|
||||
records nearer the query than the reader's one in-scope record, so the old
|
||||
shape could not reach it when the index served the order. What a test cannot
|
||||
force is the plan — the shape guard in test_search_scope_shape is what fails
|
||||
on the old query whatever Postgres picks.
|
||||
records nearer the query than the reader's one in-scope record, so a query
|
||||
that scopes after the index walk cannot reach it when the index serves the
|
||||
order. What a test cannot force is the plan — the shape guard in
|
||||
test_search_scope_shape is what fails on that query whatever Postgres picks.
|
||||
|
||||
Rows are inserted directly with hand-made vectors and the embedder is stubbed,
|
||||
so the scope alone decides what comes back.
|
||||
@@ -57,7 +57,7 @@ def _chunk(model, key: str, record_id: int, vec: list[float], **extra):
|
||||
async def _found(search, user_id: int, **scope) -> set[int]:
|
||||
"""The ids a search finds. Every search fails open, so a query that raised
|
||||
reads as an empty result — the swallowed traceback is captured and named
|
||||
in the failure instead (#4958)."""
|
||||
in the failure instead."""
|
||||
raised: list[str] = []
|
||||
with patch("scribe.services.embeddings.get_embedding",
|
||||
AsyncMock(return_value=QUERY_VEC)), \
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Real-Postgres integration test for the snippet location reverse lookup (#2083).
|
||||
"""Real-Postgres integration test for the snippet location reverse lookup.
|
||||
|
||||
Runs only in the CI integration lane (real Postgres, schema built by
|
||||
`alembic upgrade head`, which includes migration 0070's `notes.data` + GIN index).
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""Real-Postgres test that the CHECK actually accepts 'spike' (0091).
|
||||
|
||||
Rule 36 exists because the value and the constraint can drift apart: the
|
||||
The value and the constraint can drift apart: the
|
||||
code starts writing a new kind while the database still refuses it, and
|
||||
nothing catches it until a write fails in front of someone. A mock cannot
|
||||
show that — it has no CHECK — so the constraint gets its own real-DB test,
|
||||
@@ -68,19 +68,18 @@ async def test_an_unknown_kind_is_still_refused(owner_id):
|
||||
|
||||
Without this, every assertion above would pass just as happily against a
|
||||
table whose CHECK had been dropped and never re-added — which is exactly
|
||||
the failure rule 36 is written against.
|
||||
the drift this file is written against.
|
||||
"""
|
||||
with pytest.raises(IntegrityError):
|
||||
await _write(owner_id, "investigation")
|
||||
|
||||
|
||||
async def test_a_kind_can_be_corrected_after_the_fact(owner_id):
|
||||
"""The write-once bug, asserted against a real column (#3129).
|
||||
"""A kind is not write-once, asserted against a real column.
|
||||
|
||||
The read-back is the whole test. A version that only asserted the update
|
||||
call succeeded would have passed against the broken code — the route
|
||||
returned 200 while dropping the field, which is exactly how this survived
|
||||
long enough to be found by hand.
|
||||
call succeeded would pass against a route that returns 200 while dropping
|
||||
the field, which is a failure nothing else reports.
|
||||
"""
|
||||
from scribe.services import notes as notes_svc
|
||||
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
The facet predicate is written twice by necessity — as SQL for rows the
|
||||
database hands back, and as Python for candidates the vector search has
|
||||
already fetched — plus a third time as the `is_task` pre-filter that narrows
|
||||
the candidate set before it exists. Those three used to be hand-written and
|
||||
agreed only by luck: adding `issue` to the SQL arm alone would have set the
|
||||
pre-filter to is_task=False, handed the Python arm a candidate set with no
|
||||
tasks in it, and returned an empty semantic half for the Issues facet forever
|
||||
with nothing red anywhere (#3128).
|
||||
the candidate set before it exists. Hand-written, those three
|
||||
agree only by luck: adding `issue` to the SQL arm alone would set the
|
||||
pre-filter to is_task=False, hand the Python arm a candidate set with no
|
||||
tasks in it, and return an empty semantic half for the Issues facet forever
|
||||
with nothing red anywhere.
|
||||
|
||||
They are now generated from one table. These tests pin the property that made
|
||||
the trap possible, so it cannot come back by a different route.
|
||||
So they are generated from one table, and these tests pin the property that
|
||||
makes the trap possible, so it cannot come back by a different route.
|
||||
"""
|
||||
import pytest
|
||||
|
||||
@@ -104,8 +104,7 @@ def test_the_live_task_kinds_are_all_facets():
|
||||
|
||||
def test_non_task_facets_are_the_note_types_and_only_those():
|
||||
"""Spelled out rather than derived, so adding a kind to `_FACETS` has to
|
||||
be a deliberate edit in two places. `lesson` joined in milestone 385 step
|
||||
2 (#3729) and is non-task on purpose: `is_task` IS `status is not None`,
|
||||
be a deliberate edit in two places. `lesson` is non-task on purpose: `is_task` IS `status is not None`,
|
||||
so a lesson that acquired a status would stop being a lesson."""
|
||||
assert set(NON_TASK_FACETS) == {"note", "process", "snippet", "lesson"}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user