feat(410): the server orients with a client-neutral index; the live context carries live state only (#4030)
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / integration (push) Successful in 54s
CI & Build / Python tests (push) Successful in 1m28s
CI & Build / Build & push image (push) Successful in 27s
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / integration (push) Successful in 54s
CI & Build / Python tests (push) Successful in 1m28s
CI & Build / Build & push image (push) Successful in 27s
Step 3 of milestone 410 "One owner per piece of guidance".
_INSTRUCTIONS is rewritten as an index for every MCP client (1,597 of 2,000
chars): orient, rules, recall, record, plan, ids, reuse, UI, report. Each
line names its tool, and the block says every reflex is stated in full in
the using-scribe skill and in each tool description.
- names no client: CLAUDE.md, auto-memory and "the client injects ~2k
chars" are gone
- gains the two reflexes it lacked: records that cite each other go through
create_records with {{ref:N}}, and reports start from `placement`
The comment block above it now explains ownership (decision #4027) instead of
accumulating per-milestone trade history, and keeps the budget and its
reason (#2562).
build_session_context states only what the server knows about this session:
the active project and open work, its design system, an unbound-repo hint,
or that no project is bound. Removed: the "you are not holding the
operator's rules" section, the closing "Reflex: search Scribe" line, the
design-system usage sentence, and the plugin-specific header. using-scribe
owns all of that. The truncation note no longer restates the rules ask.
Tests: a pin that the live context carries no rules reflex; the cap test
drives truncation through the unbound-repo hint, since a bare session is now
one line; the budget test message describes the index.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -166,11 +166,11 @@ INSTRUCTIONS_BUDGET = 2000
|
||||
def test_instructions_fit_the_fold():
|
||||
text = _instructions_text()
|
||||
assert len(text) <= INSTRUCTIONS_BUDGET, (
|
||||
f"_INSTRUCTIONS is {len(text)} chars; the client injects only ~2,048 "
|
||||
f"and silently cuts the rest (#2562). This block is a MAP — move the "
|
||||
f"detail to the tool's docstring (delivered at reach-for time), the "
|
||||
f"plugin static context (always delivered), or a skill; see the "
|
||||
f"comment above _INSTRUCTIONS."
|
||||
f"_INSTRUCTIONS is {len(text)} chars; Claude Code injects only ~2,048 "
|
||||
f"and silently cuts the rest (#2562). This block is an INDEX — state "
|
||||
f"the topic in full on its owner (a skill or the tool's docstring, "
|
||||
f"decision #4027) and give it at most a line here; see the comment "
|
||||
f"above _INSTRUCTIONS."
|
||||
)
|
||||
|
||||
|
||||
@@ -289,8 +289,8 @@ def test_a_surface_claiming_rules_bind_also_names_what_does_not():
|
||||
# The reporting-back skill carries the shapes, but a skill only helps if it
|
||||
# fires. The reflex that sends a session to it lives on the two plugin
|
||||
# surfaces a session always reads; the in-band cue on update_task is the half
|
||||
# that reaches clients with no plugin at all. _INSTRUCTIONS took no line, on
|
||||
# purpose — server.py's comment block records why.
|
||||
# that reaches clients with no plugin at all. Since milestone 410 the server's
|
||||
# index carries a REPORT line too, pointing at `placement`.
|
||||
|
||||
REPORT_REFLEX = "report back in a shape the operator can read"
|
||||
REPORT_SURFACES = (
|
||||
|
||||
@@ -114,6 +114,10 @@ async def test_build_session_context_includes_project_when_scoped():
|
||||
# No design system on the project -> no design block at all. An install with
|
||||
# none is the ordinary case, not a degraded one.
|
||||
assert "## Design system" not in out["context"]
|
||||
# Live state only (decision #4027): how to work with Scribe is the
|
||||
# using-scribe skill's to say. A restated reflex here is a copy that drifts.
|
||||
assert 'content_type="rule"' not in out["context"]
|
||||
assert "Reflex:" not in out["context"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -246,14 +250,16 @@ async def test_build_session_context_caps_length():
|
||||
|
||||
Patching the cap rather than manufacturing 9,000 characters keeps the test
|
||||
about the TRUNCATION PATH — that it cuts, and that it says it cut — which
|
||||
is the part a reader depends on.
|
||||
is the part a reader depends on. The unbound-repo hint supplies the text:
|
||||
since milestone 410 the block carries live state only, and a bare session
|
||||
is a one-liner.
|
||||
"""
|
||||
from scribe.services import plugin_context as pc
|
||||
|
||||
with patch.object(pc, "_MAX_CHARS", 120):
|
||||
out = await pc.build_session_context(user_id=7)
|
||||
with patch.object(pc, "_MAX_CHARS", 60):
|
||||
out = await pc.build_session_context(user_id=7, unbound_repo="host/owner/repo")
|
||||
|
||||
assert len(out["context"]) <= 120 + 60 # cap + truncation note
|
||||
assert len(out["context"]) <= 60 + 20 # cap + truncation note
|
||||
assert "truncated" in out["context"], (
|
||||
"the block was cut without saying so — a reader cannot tell a "
|
||||
"truncated context from a short one"
|
||||
|
||||
Reference in New Issue
Block a user