docs(6209): task document, query scrubbing, note pipeline, lesson door, live body, ledger clear, rule usage
Seven more test files: docstrings and comments state the property and its reason, the SQL-twin note states why `\m` and not `\b` without the install it broke, and fixture provenance says "real near-miss queries" rather than naming the spike that collected them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
"""The REST door for lessons — the half the web UI can actually reach (#3734).
|
||||
"""The REST door for lessons — the half the web UI can actually reach.
|
||||
|
||||
WHY THIS EXISTS AT ALL
|
||||
|
||||
Milestone 385 built the lesson kind through the MCP tools, which is the surface
|
||||
an agent uses. The Vue app speaks REST, so until this blueprint existed a lesson
|
||||
was a record a person could not create, read, edit or retire from the UI — rule
|
||||
27's "no UI, no ship" failing at the door rather than in the view.
|
||||
The MCP tools are the surface an agent uses; the Vue app speaks REST. Without
|
||||
this blueprint a lesson is a record a person cannot create, read, edit or
|
||||
retire from the UI — a feature with no UI, failing at the door rather than in
|
||||
the view.
|
||||
|
||||
WHAT THESE PIN
|
||||
|
||||
@@ -17,7 +17,7 @@ kind:
|
||||
own title would produce lessons that rank differently from the agent's, and
|
||||
the document IS what ranks.
|
||||
|
||||
- ACL (rule 78). Share-aware resolve, write as the owner — the pattern
|
||||
- ACL. Share-aware resolve, write as the owner — the pattern
|
||||
routes/snippets.py sets — so a shared editor isn't rejected by the
|
||||
owner-scoped service.
|
||||
|
||||
@@ -50,7 +50,7 @@ def test_both_doors_share_one_serializer():
|
||||
|
||||
|
||||
def test_the_rest_door_composes_nothing_itself():
|
||||
"""Asserted on structure (rule 167). The document is what ranks, so a door
|
||||
"""Asserted on structure. The document is what ranks, so a door
|
||||
that built its own title would produce lessons that rank differently from
|
||||
the ones the agent writes."""
|
||||
from scribe.routes import lessons as routes
|
||||
@@ -124,7 +124,7 @@ def test_the_subject_is_required_too():
|
||||
assert "what is required" in src
|
||||
|
||||
|
||||
# ── ACL: rule 78's pattern, not a bare owner filter ──────────────────────────
|
||||
# ── ACL: the shared-access pattern, not a bare owner filter ──────────────────
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -139,12 +139,12 @@ def test_writes_check_permission_and_act_as_the_owner(handler):
|
||||
assert "can_write_note" in src, f"{handler} does not check write permission"
|
||||
assert "note.user_id" in src, (
|
||||
f"{handler} writes as the caller rather than as the owner, which "
|
||||
f"rejects a legitimately shared editor (rule 78)"
|
||||
f"rejects a legitimately shared editor"
|
||||
)
|
||||
|
||||
|
||||
def test_no_handler_builds_its_own_owner_filter():
|
||||
"""Rule 78's actual failure mode: a route assembling its own
|
||||
"""The access layer's actual failure mode: a route assembling its own
|
||||
`Note.user_id == uid` clause instead of going through the service and the
|
||||
access helpers. Passing `user_id=uid` INTO a service is the correct call
|
||||
and is not what this looks for."""
|
||||
@@ -238,7 +238,7 @@ def test_the_payload_reads_back_the_composed_fields():
|
||||
|
||||
|
||||
def test_the_rest_guards_can_fail():
|
||||
"""Rule 167: shown turning red once."""
|
||||
"""Shown turning red once."""
|
||||
from scribe.routes import lessons as routes
|
||||
|
||||
src = inspect.getsource(routes)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
"""The notes corpus on the one retrieval pipeline (milestone 456 step 4).
|
||||
"""The notes corpus on the one retrieval pipeline.
|
||||
|
||||
`run_note_arm` is driven directly here, with the search and both recorders
|
||||
stubbed through `NoteIO`: the stage order, the invariants the rule arms
|
||||
already pin (#3497's call row before any return, #3752's fresh-only cut,
|
||||
#4101's ledger-renders-not-removes), the write path's withheld menu (#3739),
|
||||
already pin (the call row before any return, the fresh-only cut, the ledger
|
||||
renders rather than removes), the write path's withheld menu,
|
||||
and the two reserved slots in their load-bearing order. The builders that
|
||||
compose these arms keep their own tests; these pin the stages they share.
|
||||
"""
|
||||
@@ -53,7 +53,7 @@ async def _run(arm, route, *, budget=3, **moment):
|
||||
return result, io, calls
|
||||
|
||||
|
||||
# ── the call row (#3497, #3752) ───────────────────────────────────────────
|
||||
# ── the call row ──────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -75,7 +75,7 @@ async def test_repeats_and_named_records_are_counted_not_reported():
|
||||
(row,) = _rows(io.record_retrieval, "auto_inject")
|
||||
assert [int(n.id) for _s, n in row["results"]] == [22]
|
||||
assert row["suppressed"] == 2
|
||||
# The repeat stays on the menu (#4101); the named record does not — it is
|
||||
# The repeat stays on the menu; the named record does not — it is
|
||||
# shown by its own block.
|
||||
assert [int(n.id) for _s, n in result.menu] == [11, 22]
|
||||
(surfaced,) = _rows(io.record_surfaced, "auto_inject")
|
||||
@@ -105,7 +105,7 @@ def test_every_notes_stage_logs_before_it_can_return():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_the_band_narrows_the_menu_after_the_row_is_written():
|
||||
"""Notes log BEFORE the band (#2085) — the row is the candidate set a
|
||||
"""Notes log BEFORE the band — the row is the candidate set a
|
||||
floor is tuned against, the surfacing rows are what the reader saw."""
|
||||
hits = [_note(1, 0.90), _note(2, 0.70)]
|
||||
result, io, _ = await _run(rp.WRITE_PATH, lambda kw: hits)
|
||||
@@ -141,7 +141,7 @@ async def test_a_recorder_that_raises_costs_only_its_row():
|
||||
assert [int(n.id) for _s, n in result.menu] == [1]
|
||||
|
||||
|
||||
# ── the write path's withheld menu (#3739) ────────────────────────────────
|
||||
# ── the write path's withheld menu ────────────────────────────────────────
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -223,7 +223,7 @@ async def test_a_slot_stands_down_when_its_kind_won_on_score():
|
||||
@pytest.mark.asyncio
|
||||
async def test_a_slot_spends_itself_on_a_repeat_without_booking_it_again():
|
||||
"""A record shown in an EARLIER call is exactly what a slot may spend
|
||||
itself on (#4101) — it is rendered, but it is not a new surfacing."""
|
||||
itself on — it is rendered, but it is not a new surfacing."""
|
||||
main = [_note(1, 0.70)]
|
||||
lesson = [_note(42, 0.58, note_type=LESSON_NOTE_TYPE)]
|
||||
result, io, _ = await _run(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""A logged query never carries a credential (#3925).
|
||||
"""A logged query never carries a credential.
|
||||
|
||||
WHY THIS EXISTS
|
||||
|
||||
@@ -9,8 +9,7 @@ that exported a token therefore stored the token.
|
||||
|
||||
And storing it was not the worst of it. `near_miss_samples` is the readout the
|
||||
threshold documentation tells you to open before moving a bar, so the value
|
||||
came back OUT into an agent's context on the next tuning pass — which is
|
||||
exactly how this was found, during #3853's threshold spike.
|
||||
would come back OUT into an agent's context on the next tuning pass.
|
||||
|
||||
WHAT THIS PINS, IN BOTH DIRECTIONS, AND WHY THE SECOND HALF IS THE HARD ONE
|
||||
|
||||
@@ -21,12 +20,11 @@ A scrubber has two ways to fail and only one of them is obvious.
|
||||
because it is silent: the whole worth of a near-miss sample is reading the
|
||||
query that was actually refused, and a scrubber that chewed up ordinary
|
||||
commands would turn the one instrument for tuning a bar into unreadable
|
||||
stubs while still looking like it worked. That is the #2663 shape — a
|
||||
surface that reads fine and has quietly stopped saying anything.
|
||||
stubs while still looking like it worked — a surface that reads fine and
|
||||
has quietly stopped saying anything.
|
||||
|
||||
So the second block is not padding. Its cases are REAL queries taken from this
|
||||
install's `near_miss_samples` during #3853, and they must survive byte for
|
||||
byte. If a future pattern is added and one of them changes, the pattern is too
|
||||
So the second block is not padding. Its cases are REAL near-miss queries, and
|
||||
they must survive byte for byte. If a future pattern is added and one of them changes, the pattern is too
|
||||
greedy — tighten it rather than editing the expectation.
|
||||
|
||||
The secret cases use FABRICATED values in the real formats. Nothing here is or
|
||||
@@ -59,7 +57,7 @@ _SECRETS = [
|
||||
"MIIEowIBAAKC"),
|
||||
]
|
||||
|
||||
# Real queries, from this install's near-miss samples during #3853.
|
||||
# Real queries, from near-miss samples.
|
||||
_EVIDENCE = [
|
||||
"git push origin dev",
|
||||
'git pull --rebase origin dev 2>&1 | tail -3; echo "=== HEAD ==="; git log --oneline -2',
|
||||
@@ -114,7 +112,7 @@ def test_empty_and_missing_queries_pass_through():
|
||||
|
||||
|
||||
def test_the_write_path_scrubs_rather_than_the_read_path():
|
||||
"""The payload built for storage carries the redacted text (#3925).
|
||||
"""The payload built for storage carries the redacted text.
|
||||
|
||||
Pinned on `_build_payload` because that is the single seam every source
|
||||
reaches the column through. A per-caller scrub would be three places for
|
||||
@@ -135,21 +133,20 @@ def test_the_write_path_scrubs_rather_than_the_read_path():
|
||||
assert "git push" in payload["query"]
|
||||
|
||||
|
||||
# ── the SQL twin has its own word-boundary spelling (#3925) ─────────────
|
||||
# ── the SQL twin has its own word-boundary spelling ─────────────────────
|
||||
#
|
||||
# Migration 0099 carries an inlined copy of these patterns, deliberately: a
|
||||
# migration is a frozen record of what already ran, and importing the live
|
||||
# ones would mean it quietly did something different next year.
|
||||
#
|
||||
# Frozen is not the same as correct, and the first cut was neither. The
|
||||
# boundary was dropped in the port, so `sk-` matched inside any word
|
||||
# containing it — `<task-notification>` became `<ta[redacted:token]>` across
|
||||
# thousands of rows on the one install that ran it. And writing `\b` would not
|
||||
# have saved it: in Postgres ARE `\b` is a BACKSPACE, not a word boundary.
|
||||
# Frozen is not the same as correct. Without the boundary, `sk-` matches
|
||||
# inside any word containing it — `<task-notification>` becomes
|
||||
# `<ta[redacted:token]>`. And writing `\b` does not help: in Postgres ARE `\b`
|
||||
# is a BACKSPACE, not a word boundary.
|
||||
# `\m` (start of word) is the spelling that means what Python's `\b` means.
|
||||
#
|
||||
# So this pins the property no reader can eyeball, and it is a PRESENCE check
|
||||
# on a token that must appear rather than an absence check on prose (#3352).
|
||||
# on a token that must appear rather than an absence check on prose.
|
||||
|
||||
def test_the_migrations_patterns_anchor_to_a_word_start_the_postgres_way():
|
||||
"""`\\m`, never `\\b` — the two are unrelated in Postgres."""
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Rule usage telemetry — the parts that need no database (milestone 333 step 1).
|
||||
"""Rule usage telemetry — the parts that need no database.
|
||||
|
||||
The round trip lives in `test_integration_backup_rule_usage_roundtrip.py`.
|
||||
What is here is the payload building and the zero shape: cheap, and the half
|
||||
@@ -143,10 +143,10 @@ def test_the_model_serialises_the_fields_the_ratio_needs():
|
||||
assert row["created_at"] is None
|
||||
|
||||
|
||||
# ─── the readout (milestone 333 step 5) ──────────────────────────────────────
|
||||
# Integration: a real GROUP BY over a real table. Step 1 unit-tested the WRITE
|
||||
# path and the zero shape and left the aggregate uncovered, which only became
|
||||
# load-bearing when the rule list started rendering it.
|
||||
# ─── the readout ─────────────────────────────────────────────────────────────
|
||||
# Integration: a real GROUP BY over a real table. The unit tests above cover
|
||||
# the WRITE path and the zero shape; the aggregate the rule list renders needs
|
||||
# a real database.
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
@@ -212,7 +212,7 @@ async def test_usage_for_rules_on_an_empty_id_list_asks_the_database_nothing(
|
||||
@pytest.mark.integration
|
||||
@pytest.mark.asyncio
|
||||
async def test_a_preloaded_rule_does_not_read_as_a_ranked_surfacing(_dispose_engine):
|
||||
"""The split that makes the always-on set judgeable (#3473).
|
||||
"""The split that makes the always-on set judgeable.
|
||||
|
||||
A resident rule is delivered every session by a surface that chose
|
||||
nothing. Counting those as `surfaced_count` would rank the always-on set
|
||||
@@ -262,12 +262,11 @@ async def test_a_preloaded_rule_does_not_read_as_a_ranked_surfacing(_dispose_eng
|
||||
await s.commit()
|
||||
|
||||
|
||||
# ── the outcome stream (#4212, milestone 419) ─────────────────────────────
|
||||
# ── the outcome stream ────────────────────────────────────────────────────
|
||||
#
|
||||
# What these guard is a distinction, not a payload. Before this existed, a
|
||||
# rule read and obeyed and a rule read and ignored left byte-identical
|
||||
# telemetry, so the readout could not name the failure the whole milestone
|
||||
# was opened on. The tests that matter most below are the ones asserting
|
||||
# What these guard is a distinction, not a payload. Without outcomes, a rule
|
||||
# read and obeyed and a rule read and ignored leave byte-identical telemetry,
|
||||
# so the readout cannot name the failure. The tests that matter most below are the ones asserting
|
||||
# that a REASONLESS DEPARTURE IS NEVER WRITTEN, and that an unacted rule is
|
||||
# a state in its own right rather than the absence of one.
|
||||
|
||||
@@ -301,7 +300,7 @@ def test_a_departure_with_no_reason_is_never_written(captured, reason):
|
||||
miss, so writing one would collapse the two states this table exists to
|
||||
separate — silently, in the readout, where nobody would see it happen.
|
||||
Dropped and reported, never stored: telemetry that lies is worse than
|
||||
telemetry that is absent (#2663)."""
|
||||
telemetry that is absent."""
|
||||
rule_usage.record_rule_outcome(
|
||||
user_id=7, rule_id=156, outcome=DEPARTED,
|
||||
source="mcp_rule_outcome", detail=reason or "",
|
||||
@@ -357,10 +356,9 @@ def test_a_rule_opened_and_departed_from_is_departed():
|
||||
|
||||
|
||||
def test_a_rule_opened_and_never_acted_on_is_unacted() -> None:
|
||||
"""THE STATE THAT DID NOT EXIST, and the reason for the milestone. Not
|
||||
"no data": the rule was surfaced, deliberately opened, and then left no
|
||||
trace of having mattered. Until now that was arithmetically identical to
|
||||
compliance, which is why nothing could report it."""
|
||||
"""THE UNACTED STATE. Not "no data": the rule was surfaced, deliberately
|
||||
opened, and then left no trace of having mattered. Without this state it
|
||||
is arithmetically identical to compliance, and nothing can report it."""
|
||||
assert rule_usage.outcome_state(
|
||||
_usage(surfaced_count=4, pull_count=2)
|
||||
) == rule_usage.UNACTED
|
||||
@@ -389,5 +387,5 @@ def test_a_departure_outranks_an_application():
|
||||
def test_the_state_reads_the_aggregate_the_readout_already_returns():
|
||||
"""`outcome_state` takes `usage_for_rules`' own shape, so the badge, the
|
||||
readout and any later session summary cannot disagree about what
|
||||
"followed" means — the drift #3246 found across the rules system."""
|
||||
"followed" means."""
|
||||
assert rule_usage.outcome_state(rule_usage.empty_rule_usage()) == rule_usage.UNREAD
|
||||
|
||||
@@ -1,22 +1,18 @@
|
||||
"""A compaction clears every session ledger, by convention not by list (#4101).
|
||||
"""A compaction clears every session ledger, by convention not by list.
|
||||
|
||||
WHY THIS EXISTS
|
||||
|
||||
Milestone 386 established the claim: a ledger describes what a session HOLDS,
|
||||
so the events that destroy context must destroy it too, or the records it names
|
||||
become permanently unreachable mid-session. `scribe_session_context.sh`
|
||||
implemented that — for the rules ledger, by name.
|
||||
|
||||
Five ledgers live in that directory and two were on the list. The note arms'
|
||||
three (`.ids`, `.sync.ids`, `.derive.ids`) were left, under a comment asserting
|
||||
this was "a decision rather than an oversight". It was not a decision, and the
|
||||
arms left out are the ones where it costs most:
|
||||
A ledger describes what a session HOLDS, so the events that destroy context
|
||||
must destroy it too, or the records it names become permanently unreachable
|
||||
mid-session. A clear that names ledgers one by one misses the next one, and the
|
||||
note arms' three (`.ids`, `.sync.ids`, `.derive.ids`) are where a miss costs
|
||||
most:
|
||||
|
||||
- their exclusions are HARD — `exclude_ids` is passed into
|
||||
`semantic_search_notes` itself, so a surfaced note leaves the result set
|
||||
entirely, with no weaker rendering to fall back to the way #3750 gave a
|
||||
repeated rule one;
|
||||
- and they never AGE — #3751's TTL was added to the rules ledger only.
|
||||
entirely, with no weaker rendering to fall back to the way a repeated
|
||||
rule has one;
|
||||
- and they never AGE — the TTL is on the rules ledger only.
|
||||
|
||||
Hard, permanent and never cleared: a note surfaced in a session's first minute
|
||||
is unreachable for the rest of it, through any number of compactions.
|
||||
@@ -38,7 +34,7 @@ test. Both sides are asserted:
|
||||
|
||||
And the negative: `<sid>.unreached` is not a ledger of held context but a
|
||||
record that the instance could not be reached, and a glob that swept it away
|
||||
would make a hook forget an outage it is meant to report (#2932).
|
||||
would make a hook forget an outage it is meant to report.
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
@@ -137,7 +133,7 @@ def test_a_source_that_kept_the_context_keeps_the_ledgers(source, tmp_path):
|
||||
def test_the_outage_marker_is_not_swept_with_them(tmp_path):
|
||||
"""`.unreached` records that the instance was down, not what was surfaced.
|
||||
|
||||
Different lifetime, different question. #2932's whole point is that "we
|
||||
Different lifetime, different question. The marker's whole point is that "we
|
||||
checked and found nothing" and "we never managed to check" must stay
|
||||
distinguishable, and a clear that took this file out would quietly answer
|
||||
the second with the first.
|
||||
@@ -235,7 +231,7 @@ def test_the_clear_is_derived_and_not_a_list_of_names():
|
||||
|
||||
|
||||
def test_the_evidence_twin_is_not_swept_with_them(tmp_path):
|
||||
"""The second thing that survives, and for the `.unreached` reason (#4217).
|
||||
"""The second thing that survives, and for the `.unreached` reason.
|
||||
|
||||
`scribe_rules_append` writes each ledger twice: `<sid>.<kind>.ids`, which
|
||||
says what this context HOLDS and must be forgotten here, and
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
"""Pull-time freshness (#2690) — attach_live_body against a mocked forge.
|
||||
"""Pull-time freshness — attach_live_body against a mocked forge.
|
||||
|
||||
The properties that must hold, each with its own way of rotting:
|
||||
|
||||
- A no-forge instance's pull response is BYTE-IDENTICAL to today's (rule
|
||||
#115 — the baseline, not a degraded mode).
|
||||
- A no-forge instance's pull response is BYTE-IDENTICAL to a plain read
|
||||
(the baseline, not a degraded mode).
|
||||
- The probe never rewrites the body: "current" refreshes provenance,
|
||||
"diverged" reports, and neither clobbers the record mid-read.
|
||||
- A 404 stamps the mechanically-true 'missing' verdict — once, not on
|
||||
@@ -57,8 +57,8 @@ def _file_response(content: str, commit_sha: str = SHA) -> httpx.Response:
|
||||
|
||||
|
||||
def _patched(forge):
|
||||
"""Stub the owner-keyring lookup (#2778): None → an empty selector, i.e.
|
||||
the owner has no connections — the old 'no forge configured' state."""
|
||||
"""Stub the owner-keyring lookup: None → an empty selector, i.e. the
|
||||
owner has no connections — no forge configured."""
|
||||
from scribe.services.forge import ForgeSelector
|
||||
|
||||
selector = ForgeSelector(() if forge is None else (forge,))
|
||||
@@ -112,7 +112,7 @@ async def test_current_with_same_stored_sha_skips_the_write():
|
||||
|
||||
|
||||
async def test_stored_sha_short_circuit_skips_the_content_fetch():
|
||||
"""#2693: when provenance already names a commit and the forge reports no
|
||||
"""When provenance already names a commit and the forge reports no
|
||||
newer commit touching the path, the pull is confirmed current WITHOUT a
|
||||
content transfer — the economy that fits pull-time freshness inside
|
||||
GitHub's rate limits."""
|
||||
@@ -274,7 +274,7 @@ async def test_forge_failure_inside_lookup_never_breaks_the_pull():
|
||||
assert "body_source" not in data
|
||||
|
||||
|
||||
# --- #2782: an annotated record is not a diverged one ------------------------
|
||||
# --- an annotated record is not a diverged one ------------------------------
|
||||
# Containment is right for a verbatim record and wrong for a deliberately
|
||||
# annotated one: the commentary that makes the record worth reading is exactly
|
||||
# what makes `cached in fetched` false, forever. These pin the escape hatch —
|
||||
@@ -326,7 +326,7 @@ async def test_an_expired_verdict_does_not_vouch():
|
||||
|
||||
|
||||
async def test_a_push_invalidated_verdict_does_not_vouch():
|
||||
"""A push touched the recorded location since the check (#2691) — the repo
|
||||
"""A push touched the recorded location since the check — the repo
|
||||
moved under the verdict even though the record didn't."""
|
||||
data = _data(code=ANNOTATED, verification=_ok_verdict(invalidated_by="c" * 40))
|
||||
assert await _freshness(data) == ("cache", "diverged")
|
||||
@@ -349,7 +349,7 @@ async def test_a_verbatim_record_still_takes_the_containment_path():
|
||||
|
||||
|
||||
async def test_a_verdict_predating_commit_stamping_does_not_vouch():
|
||||
"""Verdicts recorded before `commit_sha` existed (#2688) carry no commit to
|
||||
"""Verdicts recorded before `commit_sha` existed carry no commit to
|
||||
compare, so they cannot tie the body to a known state of the source. They
|
||||
fall through to containment rather than vouching on age alone."""
|
||||
verdict = svc.compose_verification(
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
"""task_document — the document a TASK is embedded as, work logs included (#4251).
|
||||
"""task_document — the document a TASK is embedded as, work logs included.
|
||||
|
||||
A work log is the richest record Scribe holds of *why* something is the way it
|
||||
is: prose written during the work, saying what was tried and ruled out. #4241
|
||||
made it readable. It was still not findable, so "has anyone tried this
|
||||
approach?" — the question a log answers — could not reach one, and #4208 was
|
||||
rebuilt in this very session because its logs were unreachable.
|
||||
is: prose written during the work, saying what was tried and ruled out. A log
|
||||
that is readable but not embedded is not findable, so "has anyone tried this
|
||||
approach?" — the question a log answers — cannot reach it.
|
||||
|
||||
These tests pin the shape and the two properties the decision rested on: a task
|
||||
without logs embeds EXACTLY as it always did, and a task with them stays as
|
||||
@@ -30,7 +29,7 @@ D2 = datetime.datetime(2026, 9, 21, 11, 0)
|
||||
def test_a_task_with_no_logs_embeds_exactly_as_it_did_before():
|
||||
"""Most notes are not tasks and most tasks carry no log. Their vectors are
|
||||
the corpus this instance's thresholds were measured against, and changing
|
||||
them for nothing would move every tuned number underneath itself (#4225)."""
|
||||
them for nothing would move every tuned number underneath itself."""
|
||||
assert task_document("A title", "A body") == ("A title", "A body")
|
||||
assert task_document("A title", "A body", []) == ("A title", "A body")
|
||||
assert task_document("T", None) == ("T", None)
|
||||
@@ -81,10 +80,9 @@ def test_an_entry_with_no_timestamp_still_gets_its_own_section():
|
||||
|
||||
def test_each_log_becomes_its_own_title_anchored_chunk():
|
||||
"""THE decision this build turns on. The objection to putting logs in the
|
||||
task's document is that a long log drowns a short title — true before #280,
|
||||
when one vector per record meant a 2,000-word log averaged the task's
|
||||
subject away and everything past ~400 words was truncated unread. Chunking
|
||||
answers both: separate vectors, each carrying the title as its anchor."""
|
||||
task's document is that a long log drowns a short title — true of one
|
||||
vector per record, where a 2,000-word log averages the task's subject away
|
||||
and everything past ~400 words is truncated unread. Chunking answers both: separate vectors, each carrying the title as its anchor."""
|
||||
def _entry(subject: str) -> str:
|
||||
para = " ".join([f"This log entry discusses the {subject} in detail."] * 8)
|
||||
return "\n\n".join(f"{para} (p{i})" for i in range(6))
|
||||
@@ -102,7 +100,7 @@ def test_each_log_becomes_its_own_title_anchored_chunk():
|
||||
# a log section and scored as part of it.
|
||||
assert any("Short body." in c and "alternative" not in c for c in chunks)
|
||||
|
||||
# And nothing is lost: this is what #280 exists for. Paragraph-shaped,
|
||||
# And nothing is lost: this is what chunking exists for. Paragraph-shaped,
|
||||
# because that is what a log is and because a single unbroken 3,000-char
|
||||
# line is hard-split mid-line by design — `test_chunking` owns that case.
|
||||
joined = "\n".join(chunks)
|
||||
@@ -113,7 +111,7 @@ def test_each_log_becomes_its_own_title_anchored_chunk():
|
||||
|
||||
def test_a_short_task_with_a_short_log_is_still_one_sharp_chunk():
|
||||
"""Over-splitting is not the goal either. A task and one short log stay a
|
||||
single document, the shape note #2485 measured as the sharpest."""
|
||||
single document, the shape that measures sharpest."""
|
||||
title, body = task_document("T", "body", [(D1, "a short note about it")])
|
||||
assert chunk_document(title, body) == [embedding_text(title, body)]
|
||||
|
||||
@@ -122,8 +120,8 @@ def test_a_short_task_with_a_short_log_is_still_one_sharp_chunk():
|
||||
#
|
||||
# The shaper above is pure. These pin that the writers actually call it — a
|
||||
# task whose logs are in the document but never re-indexed after one is written
|
||||
# is #4241's half-surface one layer down: the entry is readable, and the search
|
||||
# still answers as though it were never written.
|
||||
# is a half-surface one layer down: the entry is readable, and the search still
|
||||
# answers as though it were never written.
|
||||
|
||||
from unittest.mock import AsyncMock, MagicMock, patch # noqa: E402
|
||||
|
||||
|
||||
Reference in New Issue
Block a user