rename(547): the server is grimoire — package, image, DB defaults, backups
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / TypeScript typecheck (push) Successful in 56s
CI & Build / integration (push) Successful in 1m4s
CI & Build / Python tests (push) Successful in 1m55s
CI & Build / Build & push image (push) Successful in 44s
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / TypeScript typecheck (push) Successful in 56s
CI & Build / integration (push) Successful in 1m4s
CI & Build / Python tests (push) Successful in 1m55s
CI & Build / Build & push image (push) Successful in 44s
Step 2 of the Scribe -> Grimoire rename. - src/scribe -> src/grimoire, and every import, patch target, module path, hypercorn entry point and `python -m grimoire.restore` with it; pyproject, uv.lock and the frontend package are named grimoire. - Image git.fabledsword.com/bvandeusen/fabledgrimoire; CI's Postgres service runs as grimoire / grimoire_test. - Compose files default the DB user, database and (prod) volume to grimoire, each overridable from .env, so an install created as Scribe keeps its data by setting POSTGRES_USER, POSTGRES_DB and PGDATA_VOLUME. - Backups are written as grimoire-<ts>.tar with format grimoire-backup-tar. Archives named scribe-* with the scribe-backup-tar manifest still restore and are still counted at the destination (folder and S3), with tests. - Exports, the MCP auth realm, the ASGI scope key and the persistent logger carry the new name. Kept on purpose: the secret-sealing key label stays "scribe.secrets.v1", because every stored secret was derived under it. Plugin identity (plugin name, hooks, env vars, .scribe marker, skills) is step 3. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,11 +9,11 @@ import pytest
|
||||
import pytest_asyncio
|
||||
from sqlalchemy import select
|
||||
|
||||
from scribe.models import async_session
|
||||
from scribe.models.code_shape import CodeShape
|
||||
from scribe.models.project import Project
|
||||
from scribe.models.user import User
|
||||
from scribe.services.shape_ledger import (
|
||||
from grimoire.models import async_session
|
||||
from grimoire.models.code_shape import CodeShape
|
||||
from grimoire.models.project import Project
|
||||
from grimoire.models.user import User
|
||||
from grimoire.services.shape_ledger import (
|
||||
classify_shapes,
|
||||
classify_shapes_where,
|
||||
list_project_shapes,
|
||||
@@ -36,7 +36,7 @@ SHAPES = [
|
||||
@pytest_asyncio.fixture
|
||||
async def seeded():
|
||||
"""Owner + outsider, a project with a synced 4-shape ledger, one snippet."""
|
||||
from scribe.services import snippets as snippets_svc
|
||||
from grimoire.services import snippets as snippets_svc
|
||||
|
||||
async with async_session() as s:
|
||||
owner = await ensure_user(s, "classify_owner")
|
||||
@@ -174,7 +174,7 @@ async def test_sync_stamps_scoped_rows_and_unstamps_when_they_become_reachable(s
|
||||
"""By-construction one-offs arrive `scoped` (mechanical), count as
|
||||
accounted, are reached by the sweep's default, and go back to the todo
|
||||
if a later tree makes them ordinary. A judgment overrides the stamp."""
|
||||
from scribe.services.coverage import ArchiveShape
|
||||
from grimoire.services.coverage import ArchiveShape
|
||||
owner, pid, sid = seeded["owner"], seeded["pid"], seeded["snippet"]
|
||||
scoped_shapes = [
|
||||
ArchiveShape("web/Card.vue", "css", "card", ".card {", "s1", ".card { x: 1 }", True),
|
||||
@@ -206,7 +206,7 @@ async def test_uses_edges_are_the_consumer_map(seeded):
|
||||
"""A shape keeps ONE snippet_id (what it is) and any number of
|
||||
uses edges (what it calls); the snippet's consumer map lists them,
|
||||
list_shapes(uses=N) finds them, and a sweep can write them."""
|
||||
from scribe.services import snippets as snippets_svc
|
||||
from grimoire.services import snippets as snippets_svc
|
||||
owner, pid, sid = seeded["owner"], seeded["pid"], seeded["snippet"]
|
||||
helper = await snippets_svc.create_snippet(
|
||||
owner, name="cls_hash_helper", code="def hash_token(raw):\n return raw\n",
|
||||
@@ -232,7 +232,7 @@ async def test_uses_edges_are_the_consumer_map(seeded):
|
||||
assert (await list_project_shapes(owner, pid, uses=hid))[1] == 2
|
||||
# The proposer writes uses edges for JUDGED rows too: Config (exempt)
|
||||
# names hash_token in its body → an edge, no proposal.
|
||||
from scribe.services.shape_ledger import propose_for_repo
|
||||
from grimoire.services.shape_ledger import propose_for_repo
|
||||
await classify_shapes(owner, pid, [
|
||||
{"path": "src/app.py", "symbol": "Config", "status": "exempt", "reason": "settings"},
|
||||
])
|
||||
@@ -270,8 +270,8 @@ async def test_list_filters_compose(seeded):
|
||||
|
||||
@pytest.mark.integration
|
||||
async def test_get_snippet_carries_the_structured_consumer_map(seeded):
|
||||
from scribe.mcp._context import _user_id_ctx
|
||||
from scribe.mcp.tools.snippets import get_snippet
|
||||
from grimoire.mcp._context import _user_id_ctx
|
||||
from grimoire.mcp.tools.snippets import get_snippet
|
||||
|
||||
owner, pid, sid = seeded["owner"], seeded["pid"], seeded["snippet"]
|
||||
await classify_shapes(owner, pid, [
|
||||
@@ -303,7 +303,7 @@ async def test_sync_refiles_rows_whose_snippet_was_purged(seeded):
|
||||
{"path": "src/app.py", "symbol": "make_app", "status": "instance",
|
||||
"snippet_id": sid},
|
||||
])
|
||||
from scribe.models.note import Note
|
||||
from grimoire.models.note import Note
|
||||
|
||||
async with async_session() as s:
|
||||
note = await s.get(Note, sid)
|
||||
@@ -331,7 +331,7 @@ async def test_write_path_evidence_is_a_proposal_never_a_verdict(seeded):
|
||||
edge — a fact about the code — is still recorded."""
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from scribe.services.shape_ledger import suggest_write_path_instances
|
||||
from grimoire.services.shape_ledger import suggest_write_path_instances
|
||||
|
||||
owner, other, pid, sid = (
|
||||
seeded["owner"], seeded["other"], seeded["pid"], seeded["snippet"]
|
||||
@@ -396,7 +396,7 @@ async def test_a_brand_new_shape_gets_a_provisional_row_carrying_the_suggestion(
|
||||
carry a suggestion."""
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from scribe.services.shape_ledger import suggest_write_path_instances, unjudged_shapes
|
||||
from grimoire.services.shape_ledger import suggest_write_path_instances, unjudged_shapes
|
||||
|
||||
owner, pid, sid = seeded["owner"], seeded["pid"], seeded["snippet"]
|
||||
pulled = {sid: datetime.now(timezone.utc)}
|
||||
@@ -446,8 +446,8 @@ async def test_recent_pulls_reads_the_usage_stream(seeded):
|
||||
window; a surfacing alone is not a pull."""
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
from scribe.models.note_usage import PULLED, SURFACED, NoteUsageEvent
|
||||
from scribe.services.shape_ledger import recent_pulls
|
||||
from grimoire.models.note_usage import PULLED, SURFACED, NoteUsageEvent
|
||||
from grimoire.services.shape_ledger import recent_pulls
|
||||
|
||||
owner, sid = seeded["owner"], seeded["snippet"]
|
||||
now = datetime.now(timezone.utc)
|
||||
@@ -473,7 +473,7 @@ def _quiet_semantic():
|
||||
bases and the bookkeeping, so it answers "nothing" here."""
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from scribe.services import shape_ledger
|
||||
from grimoire.services import shape_ledger
|
||||
return patch.object(shape_ledger, "_semantic_canon", AsyncMock(return_value=None))
|
||||
|
||||
|
||||
@@ -494,7 +494,7 @@ async def test_proposer_proposes_and_confirm_classifies(seeded):
|
||||
nothing for the unrelated — skips rows whose content it already judged,
|
||||
and a scoped confirm turns proposals into agent instances while a
|
||||
classify on another retires its proposal."""
|
||||
from scribe.services.shape_ledger import (
|
||||
from grimoire.services.shape_ledger import (
|
||||
confirm_proposals, propose_for_repo,
|
||||
)
|
||||
|
||||
@@ -564,7 +564,7 @@ async def test_derive_groups_land_on_rows_and_in_the_summary(seeded):
|
||||
"""Shapes with no canon hit that repeat — identical bodies in two files,
|
||||
the same name in three — carry a derive proposal, and the readout ranks
|
||||
the families. A canon proposal keeps a row out of any derive group."""
|
||||
from scribe.services.shape_ledger import (
|
||||
from grimoire.services.shape_ledger import (
|
||||
apply_derive_groups, live_rows, propose_for_repo, proposal_summary,
|
||||
)
|
||||
|
||||
@@ -627,7 +627,7 @@ async def test_write_time_derive_names_the_family_or_the_canon_for_a_name(seeded
|
||||
count; for CSS a NAME family, never a body one); a
|
||||
name whose canonical row lives elsewhere → that canon; a judged row at
|
||||
the path, the canon's own file, or an unknown name → silence."""
|
||||
from scribe.services.shape_ledger import apply_derive_groups, write_time_derive
|
||||
from grimoire.services.shape_ledger import apply_derive_groups, write_time_derive
|
||||
|
||||
owner, pid, sid = seeded["owner"], seeded["pid"], seeded["snippet"]
|
||||
defs = _defs(
|
||||
@@ -672,7 +672,7 @@ async def test_derive_new_names_the_copy_that_joined_a_family_since_the_stamp(se
|
||||
newcomer — the drift since the last refresh, not the whole family."""
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from scribe.services.shape_ledger import (
|
||||
from grimoire.services.shape_ledger import (
|
||||
apply_derive_groups, derive_new_summary, live_rows,
|
||||
)
|
||||
|
||||
@@ -704,8 +704,8 @@ async def test_transition_and_prefix_references_clear_the_unused_css_flag(seeded
|
||||
a transition `name=` and a concatenated name — travel from the real
|
||||
extractor through resolution into the flag, so rules they reach stop
|
||||
being reported as unused. Only a rule nothing can reach stays listed."""
|
||||
from scribe.services.coverage import class_references
|
||||
from scribe.services.shape_ledger import sync_repo_consumers, used_by_map, live_rows
|
||||
from grimoire.services.coverage import class_references
|
||||
from grimoire.services.shape_ledger import sync_repo_consumers, used_by_map, live_rows
|
||||
|
||||
pid, owner = seeded["pid"], seeded["owner"]
|
||||
defs = _defs(
|
||||
@@ -756,7 +756,7 @@ async def test_consumer_map_syncs_edges_from_template_references(seeded):
|
||||
resolution for a scoped class, fan-out to the shared sheet for a class a
|
||||
template does not define, counts refreshed and stale edges removed on
|
||||
the next sync, and a vanished row's edges gone with it."""
|
||||
from scribe.services.shape_ledger import consumers_of, live_rows, sync_repo_consumers
|
||||
from grimoire.services.shape_ledger import consumers_of, live_rows, sync_repo_consumers
|
||||
|
||||
pid = seeded["pid"]
|
||||
defs = _defs(
|
||||
@@ -791,7 +791,7 @@ async def test_consumer_map_syncs_edges_from_template_references(seeded):
|
||||
|
||||
# The readout side: used_by per css row, the unused-css flag, and the
|
||||
# family's consumers on the write-path check.
|
||||
from scribe.services.shape_ledger import (
|
||||
from grimoire.services.shape_ledger import (
|
||||
apply_derive_groups, used_by_map, write_time_derive,
|
||||
)
|
||||
owner = seeded["owner"]
|
||||
@@ -825,12 +825,12 @@ async def test_a_second_confirm_dialog_is_detected_and_named(seeded):
|
||||
judgment clears the flag; a shape proposed AS the canon is not flagged."""
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
from scribe.services.shape_ledger import (
|
||||
from grimoire.services.shape_ledger import (
|
||||
divergence_summary, flag_divergence, live_rows, propose_for_repo,
|
||||
write_time_divergence,
|
||||
)
|
||||
|
||||
from scribe.services import snippets as snippets_svc
|
||||
from grimoire.services import snippets as snippets_svc
|
||||
|
||||
owner, pid = seeded["owner"], seeded["pid"]
|
||||
# The confirm helper is TS canon: a sym basis only proposes
|
||||
@@ -917,8 +917,8 @@ async def test_weak_stamps_elect_no_canon_and_their_flags_are_withdrawn(seeded):
|
||||
|
||||
from sqlalchemy import update
|
||||
|
||||
from scribe.services import snippets as snippets_svc
|
||||
from scribe.services.shape_ledger import (
|
||||
from grimoire.services import snippets as snippets_svc
|
||||
from grimoire.services.shape_ledger import (
|
||||
_RESEMBLE_REASON, flag_divergence, propose_for_repo, write_time_divergence,
|
||||
)
|
||||
|
||||
@@ -999,9 +999,9 @@ async def test_a_semantic_miss_does_not_silence_the_prompt(seeded):
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from scribe.services import shape_ledger
|
||||
from scribe.services import snippets as snippets_svc
|
||||
from scribe.services.shape_ledger import flag_divergence, live_rows, propose_for_repo
|
||||
from grimoire.services import shape_ledger
|
||||
from grimoire.services import snippets as snippets_svc
|
||||
from grimoire.services.shape_ledger import flag_divergence, live_rows, propose_for_repo
|
||||
|
||||
owner, pid = seeded["owner"], seeded["pid"]
|
||||
canon = await snippets_svc.create_snippet(
|
||||
@@ -1051,7 +1051,7 @@ async def _two_generations(seeded, tag: str):
|
||||
"""
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from scribe.services import snippets as snippets_svc
|
||||
from grimoire.services import snippets as snippets_svc
|
||||
|
||||
owner, pid = seeded["owner"], seeded["pid"]
|
||||
canon = await snippets_svc.create_snippet(
|
||||
@@ -1092,8 +1092,8 @@ async def test_the_capped_semantic_pass_reaches_the_new_shape_first(seeded):
|
||||
ONE check, the new shape must be the one that gets it."""
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from scribe.services import shape_ledger
|
||||
from scribe.services.shape_ledger import live_rows, propose_for_repo
|
||||
from grimoire.services import shape_ledger
|
||||
from grimoire.services.shape_ledger import live_rows, propose_for_repo
|
||||
|
||||
owner, pid, later, _previous = await _two_generations(seeded, "cap")
|
||||
with patch.object(shape_ledger, "_semantic_canon", AsyncMock(return_value=None)):
|
||||
@@ -1108,7 +1108,7 @@ async def test_the_capped_semantic_pass_reaches_the_new_shape_first(seeded):
|
||||
|
||||
@pytest.mark.integration
|
||||
async def test_history_records_what_was_used_when_and_drift_asks_for_a_recheck(seeded):
|
||||
from scribe.services.shape_ledger import shape_history
|
||||
from grimoire.services.shape_ledger import shape_history
|
||||
|
||||
owner, other, pid, sid = (
|
||||
seeded["owner"], seeded["other"], seeded["pid"], seeded["snippet"]
|
||||
@@ -1163,7 +1163,7 @@ async def test_a_shape_written_this_turn_is_judged_before_the_sync_sees_it(seede
|
||||
then reads the shape keeps the judgment, and a sync that does NOT have it
|
||||
yet (the code has not reached the bound ref) keeps it through the vanish
|
||||
and the reappearance. Without `repo` the old contract holds."""
|
||||
from scribe.services import repo_bindings as repo_bindings_svc
|
||||
from grimoire.services import repo_bindings as repo_bindings_svc
|
||||
|
||||
owner, pid = seeded["owner"], seeded["pid"]
|
||||
await repo_bindings_svc.set_binding(owner, REPO, pid)
|
||||
@@ -1200,7 +1200,7 @@ async def test_unjudged_is_what_nobody_read(seeded):
|
||||
audit's verdict is not. Evidence travels; a verdict is never inferred."""
|
||||
from sqlalchemy import update
|
||||
|
||||
from scribe.services.shape_ledger import _RESEMBLE_REASON, unjudged_shapes
|
||||
from grimoire.services.shape_ledger import _RESEMBLE_REASON, unjudged_shapes
|
||||
|
||||
owner, pid, sid = seeded["owner"], seeded["pid"], seeded["snippet"]
|
||||
await classify_shapes(owner, pid, [
|
||||
@@ -1238,9 +1238,9 @@ async def test_a_whole_file_snippet_makes_its_file_row_canonical(seeded):
|
||||
symbol, is the canon for that file row — the claim a whole-file record
|
||||
makes and a definition row never could. It still covers no definition
|
||||
inside the file."""
|
||||
from scribe.services import snippets as snippets_svc
|
||||
from scribe.services.coverage import _recorded_locations
|
||||
from scribe.services.shape_ledger import mark_canonicals
|
||||
from grimoire.services import snippets as snippets_svc
|
||||
from grimoire.services.coverage import _recorded_locations
|
||||
from grimoire.services.shape_ledger import mark_canonicals
|
||||
|
||||
owner, pid = seeded["owner"], seeded["pid"]
|
||||
await sync_repo_shapes(pid, REPO, SHAPES + [
|
||||
|
||||
Reference in New Issue
Block a user