docs(6206): settings, projects, api routes and three models drop citations; four capitalised services stragglers
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 15s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / integration (push) Successful in 1m7s
CI & Build / Python tests (push) Successful in 1m55s
CI & Build / Build & push image (push) Successful in 24s
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 15s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / integration (push) Successful in 1m7s
CI & Build / Python tests (push) Successful in 1m55s
CI & Build / Build & push image (push) Successful in 24s
- api.py's build-version docstring states why a channel name is not a build id, without the dated incident. - rule_version states why rules need a history, without the rule that was rescoped and the date. - Capitalised "Rule N" / "Milestone N" citations the earlier lowercase grep missed, in reply_shapes, supersession, services/family and models/family. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
"""Family canon (milestone 463): ideas that every project on a platform shares,
|
"""Family canon: ideas that every project on a platform shares,
|
||||||
and each project's recorded answer to them.
|
and each project's recorded answer to them.
|
||||||
|
|
||||||
A FAMILY IDEA is not a new kind of record. It is an existing `notes` row — a
|
A FAMILY IDEA is not a new kind of record. It is an existing `notes` row — a
|
||||||
@@ -45,7 +45,7 @@ from scribe.models import Base
|
|||||||
from scribe.models.base import CreatedAtMixin, SoftDeleteMixin, TimestampMixin, iso
|
from scribe.models.base import CreatedAtMixin, SoftDeleteMixin, TimestampMixin, iso
|
||||||
|
|
||||||
# Each tuple is the whitelist its CHECK constraint enforces (migration 0120).
|
# Each tuple is the whitelist its CHECK constraint enforces (migration 0120).
|
||||||
# Rule 36: a new value means DROP + ADD CONSTRAINT in the same migration.
|
# A new value means DROP + ADD CONSTRAINT in the same migration.
|
||||||
MEMBERSHIP_STATES = ("declared", "detected", "rejected")
|
MEMBERSHIP_STATES = ("declared", "detected", "rejected")
|
||||||
IDEA_STATUSES = ("candidate", "canon", "retired")
|
IDEA_STATUSES = ("candidate", "canon", "retired")
|
||||||
ADOPTION_STATUSES = ("unassessed", "adopted", "variant", "exempt", "owed")
|
ADOPTION_STATUSES = ("unassessed", "adopted", "variant", "exempt", "owed")
|
||||||
@@ -73,7 +73,7 @@ class Platform(Base, TimestampMixin, SoftDeleteMixin):
|
|||||||
form a backup carries, since ids are per-install.
|
form a backup carries, since ids are per-install.
|
||||||
|
|
||||||
`markers` are glob patterns over a bound repo's paths that suggest a
|
`markers` are glob patterns over a bound repo's paths that suggest a
|
||||||
project is this platform (step 2's detection). A pattern without a slash
|
project is this platform (platform detection). A pattern without a slash
|
||||||
matches a file's basename anywhere in the tree; one with a slash matches
|
matches a file's basename anywhere in the tree; one with a slash matches
|
||||||
the repo-relative path. Empty means declare-only: some platforms leave no
|
the repo-relative path. Empty means declare-only: some platforms leave no
|
||||||
reliable file behind.
|
reliable file behind.
|
||||||
@@ -166,7 +166,7 @@ class FamilyIdea(Base, TimestampMixin):
|
|||||||
comparing the two numbers, never stored as a flag that could go stale.
|
comparing the two numbers, never stored as a flag that could go stale.
|
||||||
|
|
||||||
`topic_id` is the rule topic holding the idea's binding norms, if it has
|
`topic_id` is the rule topic holding the idea's binding norms, if it has
|
||||||
any (the note↔topic link #3236 asked for), set by `set_topic`. The topic
|
any, set by `set_topic`. The topic
|
||||||
never carries platforms of its own; the idea's readouts list its rules,
|
never carries platforms of its own; the idea's readouts list its rules,
|
||||||
so an assessment judges a project against them.
|
so an assessment judges a project against them.
|
||||||
"""
|
"""
|
||||||
@@ -308,8 +308,7 @@ class FamilyDecision(Base, CreatedAtMixin):
|
|||||||
|
|
||||||
`before` and `after` are STATE snapshots — status, version, reason — and
|
`before` and `after` are STATE snapshots — status, version, reason — and
|
||||||
deliberately hold no foreign ids: an id inside JSON cannot be remapped by a
|
deliberately hold no foreign ids: an id inside JSON cannot be remapped by a
|
||||||
restore, and would come back pointing at whatever took that number (the
|
restore, and would come back pointing at whatever took that number. The ids this row needs are columns.
|
||||||
#3182 trap). The ids this row needs are columns.
|
|
||||||
|
|
||||||
`precedent_ids` are the earlier decisions this one followed. They are what
|
`precedent_ids` are the earlier decisions this one followed. They are what
|
||||||
keeps a call consistent with the last similar one when no person approves
|
keeps a call consistent with the last similar one when no person approves
|
||||||
@@ -367,7 +366,7 @@ class FamilyDecision(Base, CreatedAtMixin):
|
|||||||
stored again inside `after` (and the prior one inside `before`), and
|
stored again inside `after` (and the prior one inside `before`), and
|
||||||
a promotion's evidence carries the whole criteria reasoning. So a
|
a promotion's evidence carries the whole criteria reasoning. So a
|
||||||
state here is its status, version and platforms only, and evidence is
|
state here is its status, version and platforms only, and evidence is
|
||||||
the cited list alone (#5131). The full row is `to_dict`, which the
|
the cited list alone. The full row is `to_dict`, which the
|
||||||
decision log serves.
|
decision log serves.
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ from scribe.models.base import CreatedAtMixin, iso
|
|||||||
SUGGESTED = "suggested"
|
SUGGESTED = "suggested"
|
||||||
CONFIRMED = "confirmed"
|
CONFIRMED = "confirmed"
|
||||||
REJECTED = "rejected"
|
REJECTED = "rejected"
|
||||||
# CHECK ck_lesson_rule_links_state (migration 0111, rule 36).
|
# CHECK ck_lesson_rule_links_state (migration 0111).
|
||||||
LINK_STATES = (SUGGESTED, CONFIRMED, REJECTED)
|
LINK_STATES = (SUGGESTED, CONFIRMED, REJECTED)
|
||||||
|
|
||||||
|
|
||||||
class LessonRuleLink(Base, CreatedAtMixin):
|
class LessonRuleLink(Base, CreatedAtMixin):
|
||||||
"""A lesson says it is an instance of a rule (milestone 440, #4196).
|
"""A lesson says it is an instance of a rule.
|
||||||
|
|
||||||
A lesson records one concrete situation; a rule records the binding choice
|
A lesson records one concrete situation; a rule records the binding choice
|
||||||
for a class of them. The link lets the rule be reached through the
|
for a class of them. The link lets the rule be reached through the
|
||||||
@@ -53,7 +53,7 @@ class LessonRuleLink(Base, CreatedAtMixin):
|
|||||||
# Why it was confirmed or rejected — the reasoning a later reader needs to
|
# Why it was confirmed or rejected — the reasoning a later reader needs to
|
||||||
# decide whether it still holds, as a rule relation's `note` is.
|
# decide whether it still holds, as a rule relation's `note` is.
|
||||||
note: Mapped[str | None] = mapped_column(Text, nullable=True)
|
note: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||||
# What the suggestion rests on (filled by the co-surfacing recorder, #4637).
|
# What the suggestion rests on (filled by the co-surfacing recorder).
|
||||||
# Kept after a judgment so a confirmation can be read beside its evidence.
|
# Kept after a judgment so a confirmation can be read beside its evidence.
|
||||||
evidence: Mapped[dict | None] = mapped_column(JSONB, nullable=True)
|
evidence: Mapped[dict | None] = mapped_column(JSONB, nullable=True)
|
||||||
# When a judgment moved it out of `suggested`. Null while suggested.
|
# When a judgment moved it out of `suggested`. Null while suggested.
|
||||||
@@ -78,12 +78,12 @@ class LessonRuleLink(Base, CreatedAtMixin):
|
|||||||
|
|
||||||
|
|
||||||
class LessonNoRule(Base):
|
class LessonNoRule(Base):
|
||||||
"""A judgment that no rule governs a lesson's situation (#4631).
|
"""A judgment that no rule governs a lesson's situation.
|
||||||
|
|
||||||
The third answer to "which rule is this an instance of?", beside naming
|
The third answer to "which rule is this an instance of?", beside naming
|
||||||
one and leaving it open. It is what lets an UNJUDGED lesson be told apart
|
one and leaving it open. It is what lets an UNJUDGED lesson be told apart
|
||||||
from one that was looked at and found to stand alone — and a lesson with
|
from one that was looked at and found to stand alone — and a lesson with
|
||||||
no rule is the raw material #4634 reads for convergence, so the
|
no rule is the raw material convergence reads, so the
|
||||||
difference is the whole signal.
|
difference is the whole signal.
|
||||||
|
|
||||||
A row of its own rather than a key in the lesson's `data`: that column is
|
A row of its own rather than a key in the lesson's `data`: that column is
|
||||||
|
|||||||
@@ -10,18 +10,15 @@ from scribe.models.base import CreatedAtMixin, iso
|
|||||||
class RuleVersion(Base, CreatedAtMixin):
|
class RuleVersion(Base, CreatedAtMixin):
|
||||||
"""One snapshot of a rule's text, taken before an edit overwrote it.
|
"""One snapshot of a rule's text, taken before an edit overwrote it.
|
||||||
|
|
||||||
THE SIBLING NOTES ALREADY HAD. `note_versions` has existed for a long
|
THE SIBLING OF `note_versions`. Rules BIND BEHAVIOUR on every session that
|
||||||
time, and the design-system note calls its history "the changelog". Rules
|
loads them; without a history, an edit destroys what the rule used to say,
|
||||||
— which BIND BEHAVIOUR on every session that loads them — had nothing, so
|
and the more consequential record has the weaker protection.
|
||||||
an edit destroyed what the rule used to say. Rescoping rule 79 on
|
|
||||||
2026-08-29 meant hand-copying the superseded statement into a task log to
|
|
||||||
keep it (#3237). The more consequential record had the weaker protection.
|
|
||||||
|
|
||||||
`CreatedAtMixin`, not `TimestampMixin`: a version is an EVENT. It is
|
`CreatedAtMixin`, not `TimestampMixin`: a version is an EVENT. It is
|
||||||
written once and never updated, so an `updated_at` on it would be a column
|
written once and never updated, so an `updated_at` on it would be a column
|
||||||
that can only ever lie.
|
that can only ever lie.
|
||||||
|
|
||||||
WHAT IS DELIBERATELY DIFFERENT FROM NoteVersion (milestone 323):
|
WHAT IS DELIBERATELY DIFFERENT FROM NoteVersion:
|
||||||
|
|
||||||
- `user_id` is the ACTOR — who made the edit — where NoteVersion's is the
|
- `user_id` is the ACTOR — who made the edit — where NoteVersion's is the
|
||||||
owner, because `update_note` passes an owner-scoped id. For an audit
|
owner, because `update_note` passes an owner-scoped id. For an audit
|
||||||
@@ -34,7 +31,7 @@ class RuleVersion(Base, CreatedAtMixin):
|
|||||||
own lifecycle; folding them in would make one word, "version", mean two
|
own lifecycle; folding them in would make one word, "version", mean two
|
||||||
different things — the rule's wording, and the rule's place in the
|
different things — the rule's wording, and the rule's place in the
|
||||||
graph. `verified_at` is likewise absent: it is a stamp about a check,
|
graph. `verified_at` is likewise absent: it is a stamp about a check,
|
||||||
not a property of the text, and step 2's snapshot is taken before
|
not a property of the text, and the snapshot is taken before
|
||||||
update_rule clears it precisely so the history shows the check that was
|
update_rule clears it precisely so the history shows the check that was
|
||||||
in force when this wording was written.
|
in force when this wording was written.
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -12,14 +12,11 @@ async def health():
|
|||||||
|
|
||||||
def build_version_payload() -> dict:
|
def build_version_payload() -> dict:
|
||||||
"""What build is this, separated into the values that answer different
|
"""What build is this, separated into the values that answer different
|
||||||
questions (rule 149).
|
questions.
|
||||||
|
|
||||||
UNTIL 2026-08-31 THIS RETURNED THE CHANNEL. `BUILD_VERSION` in CI was
|
A channel name ("dev", "main") is not a build identifier: with a deploy
|
||||||
literally "dev" / "main" / the tag, so a running instance reported
|
misbehaving, the one endpoint whose job is to say which commit is serving
|
||||||
`{"version": "main"}` — a channel name sitting where a build identifier
|
must not answer with the name of a branch.
|
||||||
belongs. The cost was concrete: with a deploy misbehaving, nothing on the
|
|
||||||
instance could say which commit was serving it, and the one endpoint whose
|
|
||||||
job that is answered with the name of a branch.
|
|
||||||
|
|
||||||
The three values, and why they are three:
|
The three values, and why they are three:
|
||||||
|
|
||||||
@@ -33,7 +30,7 @@ def build_version_payload() -> dict:
|
|||||||
- `channel` — its own field, never folded into the name.
|
- `channel` — its own field, never folded into the name.
|
||||||
|
|
||||||
Plus `commit`, so the artifact's claim about itself can be checked against
|
Plus `commit`, so the artifact's claim about itself can be checked against
|
||||||
the `:<sha>` it was published under (rule 145).
|
the `:<sha>` it was published under.
|
||||||
|
|
||||||
ABSENT RATHER THAN EMPTY when unknown. A local build has no ordering key
|
ABSENT RATHER THAN EMPTY when unknown. A local build has no ordering key
|
||||||
and no channel, and saying so is honest; emitting `""` or a placeholder
|
and no channel, and saying so is honest; emitting `""` or a placeholder
|
||||||
@@ -43,7 +40,7 @@ def build_version_payload() -> dict:
|
|||||||
payload: dict = {"version": os.environ.get("APP_VERSION", "dev")}
|
payload: dict = {"version": os.environ.get("APP_VERSION", "dev")}
|
||||||
|
|
||||||
# Reported verbatim, never validated against an enum — a build claiming
|
# Reported verbatim, never validated against an enum — a build claiming
|
||||||
# something unexpected is better shown than dropped (rule 149).
|
# something unexpected is better shown than dropped.
|
||||||
for key, env in (("channel", "APP_CHANNEL"), ("commit", "APP_COMMIT")):
|
for key, env in (("channel", "APP_CHANNEL"), ("commit", "APP_COMMIT")):
|
||||||
value = (os.environ.get(env) or "").strip()
|
value = (os.environ.get(env) or "").strip()
|
||||||
if value:
|
if value:
|
||||||
|
|||||||
@@ -33,10 +33,10 @@ async def list_projects_route():
|
|||||||
projects = await list_projects_for_user(uid, status=status)
|
projects = await list_projects_for_user(uid, status=status)
|
||||||
if include_summary:
|
if include_summary:
|
||||||
# Batched: four queries plus two, in two sessions, for ALL projects.
|
# Batched: four queries plus two, in two sessions, for ALL projects.
|
||||||
# This replaced an asyncio.gather over a per-project summary that opened
|
# An asyncio.gather over a per-project summary would open a session per
|
||||||
# its own session and then one more per milestone — ~250 concurrent
|
# project and one more per milestone — far more concurrent checkouts
|
||||||
# checkouts against a pool of 15, all waiting out the 30s timeout and
|
# than the pool holds, all waiting out the checkout timeout and
|
||||||
# starving every other route on the instance (#2384).
|
# starving every other route on the instance.
|
||||||
#
|
#
|
||||||
# Grouped by OWNER because a shared project's counts belong to its
|
# Grouped by OWNER because a shared project's counts belong to its
|
||||||
# owner's records, matching what the per-project path passed.
|
# owner's records, matching what the per-project path passed.
|
||||||
@@ -67,7 +67,7 @@ async def create_project_route():
|
|||||||
status = data.get("status", "active")
|
status = data.get("status", "active")
|
||||||
if status not in ("active", "paused", "completed", "archived"):
|
if status not in ("active", "paused", "completed", "archived"):
|
||||||
return jsonify({"error": "status must be 'active', 'paused', 'completed', or 'archived'"}), 400
|
return jsonify({"error": "status must be 'active', 'paused', 'completed', or 'archived'"}), 400
|
||||||
# The inception decision rides the create (milestone 297): the UI's
|
# The inception decision rides the create: the UI's
|
||||||
# second step sends `inception: {choices}`; absent = undecided, and the
|
# second step sends `inception: {choices}`; absent = undecided, and the
|
||||||
# project page shows the card until it is. Validated before the create
|
# project page shows the card until it is. Validated before the create
|
||||||
# so a bad decision never leaves a half-made project behind.
|
# so a bad decision never leaves a half-made project behind.
|
||||||
@@ -98,7 +98,7 @@ async def create_project_route():
|
|||||||
@projects_bp.route("/<int:project_id>/inception", methods=["POST"])
|
@projects_bp.route("/<int:project_id>/inception", methods=["POST"])
|
||||||
@login_required
|
@login_required
|
||||||
async def decide_inception_route(project_id: int):
|
async def decide_inception_route(project_id: int):
|
||||||
"""Record (or re-record) what a project inherits — milestone 297.
|
"""Record (or re-record) what a project inherits.
|
||||||
Body: the choices object {design_system_id, seed_systems}; owner-only."""
|
Body: the choices object {design_system_id, seed_systems}; owner-only."""
|
||||||
uid = get_current_user_id()
|
uid = get_current_user_id()
|
||||||
data = await request.get_json() or {}
|
data = await request.get_json() or {}
|
||||||
@@ -185,7 +185,7 @@ async def get_coverage_route(project_id: int):
|
|||||||
project, _ = result
|
project, _ = result
|
||||||
owner_uid = project.user_id or uid
|
owner_uid = project.user_id or uid
|
||||||
return jsonify({
|
return jsonify({
|
||||||
# The OWNER's keyring (#2778) — whether refresh could do anything,
|
# The OWNER's keyring — whether refresh could do anything,
|
||||||
# regardless of who is looking.
|
# regardless of who is looking.
|
||||||
"configured": (await get_forges(owner_uid, project_id)).configured,
|
"configured": (await get_forges(owner_uid, project_id)).configured,
|
||||||
"coverage": await cached_coverage(owner_uid, project_id),
|
"coverage": await cached_coverage(owner_uid, project_id),
|
||||||
@@ -230,7 +230,7 @@ async def refresh_coverage_route(project_id: int):
|
|||||||
@projects_bp.route("/<int:project_id>/forge", methods=["PUT"])
|
@projects_bp.route("/<int:project_id>/forge", methods=["PUT"])
|
||||||
@login_required
|
@login_required
|
||||||
async def set_project_forge_route(project_id: int):
|
async def set_project_forge_route(project_id: int):
|
||||||
"""Pin the project to one forge connection, or clear the pin (#2778).
|
"""Pin the project to one forge connection, or clear the pin.
|
||||||
|
|
||||||
Body: {"connection_id": <id> | null}. Owner-or-admin may ask; either way
|
Body: {"connection_id": <id> | null}. Owner-or-admin may ask; either way
|
||||||
the pin can only reference a connection the project OWNER holds — the
|
the pin can only reference a connection the project OWNER holds — the
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ settings_bp = Blueprint("settings", __name__, url_prefix="/api/settings")
|
|||||||
# read and skip the mask on write; this generic KV surface has to apply the
|
# read and skip the mask on write; this generic KV surface has to apply the
|
||||||
# same treatment, or it silently un-masks what those endpoints masked — the
|
# same treatment, or it silently un-masks what those endpoints masked — the
|
||||||
# rows live on the admin's own user_id, so the plain GET returned them raw.
|
# rows live on the admin's own user_id, so the plain GET returned them raw.
|
||||||
# (forge_token left with 0078: forge credentials are keyring rows now, #2778.)
|
# (No forge_token here: forge credentials are keyring rows, since migration 0078.)
|
||||||
_SECRET_KEYS = frozenset({"smtp_password", "forge_webhook_secret"})
|
_SECRET_KEYS = frozenset({"smtp_password", "forge_webhook_secret"})
|
||||||
|
|
||||||
# What the tuning history records for a dial changed through this form. The MCP
|
# What the tuning history records for a dial changed through this form. The MCP
|
||||||
@@ -62,10 +62,10 @@ async def update_settings_route():
|
|||||||
for k, v in data.items():
|
for k, v in data.items():
|
||||||
str_v = str(v)
|
str_v = str(v)
|
||||||
# A retrieval dial is never written as a plain settings row, wherever
|
# A retrieval dial is never written as a plain settings row, wherever
|
||||||
# the request came from (#4102). The value would land correctly and the
|
# the request came from. The value would land correctly and the tuning
|
||||||
# tuning history would say nothing happened — and since milestone 416
|
# history would say nothing happened — and since those dials are moved
|
||||||
# those dials are moved by the model on the operator's behalf, a
|
# by the model on the operator's behalf, a history with holes in it is
|
||||||
# history with holes in it is worse than none: it reads as complete.
|
# worse than none: it reads as complete.
|
||||||
#
|
#
|
||||||
# Routed rather than refused on purpose. Refusing would work only for
|
# Routed rather than refused on purpose. Refusing would work only for
|
||||||
# callers that had been updated; this way every caller that ever writes
|
# callers that had been updated; this way every caller that ever writes
|
||||||
@@ -113,7 +113,7 @@ async def test_search():
|
|||||||
return jsonify({"configured": True, "results": [], "searxng_url": Config.SEARXNG_URL})
|
return jsonify({"configured": True, "results": [], "searxng_url": Config.SEARXNG_URL})
|
||||||
|
|
||||||
|
|
||||||
# --- forge connections (#2778) ------------------------------------------------
|
# --- forge connections ---------------------------------------------------------
|
||||||
# The user's keyring: read-only forge credentials, one per host, resolved by
|
# The user's keyring: read-only forge credentials, one per host, resolved by
|
||||||
# repo host for every server-side forge read on the user's projects. Strictly
|
# repo host for every server-side forge read on the user's projects. Strictly
|
||||||
# own-rows — a connection is a credential, and there is no admin view of
|
# own-rows — a connection is a credential, and there is no admin view of
|
||||||
@@ -201,7 +201,7 @@ async def delete_forge_connection_route(connection_id: int):
|
|||||||
async def test_forge_connection_route(connection_id: int):
|
async def test_forge_connection_route(connection_id: int):
|
||||||
"""Probe the SAVED connection: reachability and token acceptance in one
|
"""Probe the SAVED connection: reachability and token acceptance in one
|
||||||
press, so a misconfiguration is visible now rather than as silent
|
press, so a misconfiguration is visible now rather than as silent
|
||||||
fallbacks later (#2663's lesson, applied per keyring row)."""
|
fallbacks later, per keyring row."""
|
||||||
from scribe.services.forge import ForgeError, build_adapter
|
from scribe.services.forge import ForgeError, build_adapter
|
||||||
from scribe.services.forge_connections import connection_token, get_connection
|
from scribe.services.forge_connections import connection_token, get_connection
|
||||||
|
|
||||||
|
|||||||
@@ -449,7 +449,7 @@ async def _open_ledger(session, user_id: int, note_id: int) -> int:
|
|||||||
)).scalars().all())
|
)).scalars().all())
|
||||||
opened = 0
|
opened = 0
|
||||||
for pid in sorted(project_ids - answered):
|
for pid in sorted(project_ids - answered):
|
||||||
# Rule 78: a promotion reaches only the projects its promoter could
|
# A promotion reaches only the projects its promoter could
|
||||||
# have written an answer into themselves.
|
# have written an answer into themselves.
|
||||||
if await access.can_write_project(user_id, pid):
|
if await access.can_write_project(user_id, pid):
|
||||||
session.add(FamilyAdoption(project_id=pid, idea_id=note_id, status="unassessed"))
|
session.add(FamilyAdoption(project_id=pid, idea_id=note_id, status="unassessed"))
|
||||||
|
|||||||
@@ -3,11 +3,11 @@
|
|||||||
WHY THIS EXISTS
|
WHY THIS EXISTS
|
||||||
|
|
||||||
A reply is where the person the work is for finds out what happened, and they
|
A reply is where the person the work is for finds out what happened, and they
|
||||||
were not there while it was done. Milestone 409 wrote the shapes that make a
|
were not there while it was done. The shapes make a reply readable to them —
|
||||||
reply readable to them — conclusion first, the shortest reply that carries the
|
conclusion first, the shortest reply that carries the answer, where the work
|
||||||
answer, where the work stands — and put them in one bundled skill. A skill
|
stands. A skill arrives only when the agent decides to load it, so in a long
|
||||||
arrives only when the agent decides to load it, so in a long session the shape
|
session a shape held in a skill fades out of context exactly when replies get
|
||||||
faded out of context exactly when replies were getting longer.
|
longer.
|
||||||
|
|
||||||
So the shapes are product content held here, on the server, and delivered by
|
So the shapes are product content held here, on the server, and delivered by
|
||||||
the moments they belong to rather than by the agent remembering to ask:
|
the moments they belong to rather than by the agent remembering to ask:
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ async def set_supersedes(
|
|||||||
silent drop, because it is the one case where the caller might reasonably
|
silent drop, because it is the one case where the caller might reasonably
|
||||||
believe they succeeded and be wrong in a way that matters — demoting someone
|
believe they succeeded and be wrong in a way that matters — demoting someone
|
||||||
else's record out of their retrieval is damage you cannot see from the
|
else's record out of their retrieval is damage you cannot see from the
|
||||||
outside. Rule #47.
|
outside.
|
||||||
"""
|
"""
|
||||||
if not await access.can_write_note(user_id, note_id):
|
if not await access.can_write_note(user_id, note_id):
|
||||||
return None
|
return None
|
||||||
|
|||||||
Reference in New Issue
Block a user