discord_response: embed schema delta - timestamp, typed MeshIntentResult, IntentType enum color map, 6000-char total enforcement #271

Closed
opened 2026-08-12 09:53:21 +00:00 by Mark · 1 comment
Owner

Follow-up to #234 (Response Delivery) - delta for the embed-schema acceptance that did not land in commit 5a1d111 (feat(#234): add Discord response delivery formatter).

Source: kanban card t_b56a0fae (decomposed from #234 Phase 4, "Design rich embed schema for mesh intent responses").

Acceptance not met by landed code (runtime/discord_response.py):

  1. Schema has no timestamp. Card requires title/description/fields/color/timestamp/footer; _build_embed_dict emits title/description/color/fields/footer only.
  2. No typed MeshIntentResult input. Card requires an EmbedBuilder taking a typed MeshIntentResult; landed API is format_mesh_result(intent_type: str, result: Any). No MeshIntentResult type exists in the repo.
  3. Color map not keyed by IntentType enum. Card requires a color mapping table keyed by an IntentType enum (info=blue, warn=yellow, error=red, success=green); landed COLORS is dict[str, int] keyed by string literals (research/write/chat/status/error). No IntentType enum exists.
  4. 6000-char total embed limit not enforced. Card requires the embed stays within Discord's 6000-char total / 25-field / 1024-char-per-field limits. Landed code enforces the 25-field cap, 1024 field-value, 256 field-name, and 4096 description, but never computes the 6000-char total across title+description+field names+values+footer.

Verification evidence (commit 5a1d111, local-only unpushed; origin/master still e8c24a0; #234 still open):

  • pytest tests/unit/test_discord_response.py -> 13 passed
  • ruff check runtime/discord_response.py runtime/discord_ingress.py runtime/init.py tests/unit/test_discord_response.py -> clean

Acceptance criteria for this issue:

  • Embed dict includes ISO-8601 timestamp (default: result completion time or now()).
  • Public builder accepts a typed MeshIntentResult (define the type; keep framework-agnostic dict output).
  • IntentType enum defined; COLORS keyed by IntentType; add warn=yellow mapping.
  • Enforce 6000-char total embed budget (sum check with clipping) and add a test asserting the total with a maxed-out embed.
  • Document the schema (module docstring or docs/ entry).
Follow-up to #234 (Response Delivery) - delta for the embed-schema acceptance that did not land in commit 5a1d111 (feat(#234): add Discord response delivery formatter). Source: kanban card t_b56a0fae (decomposed from #234 Phase 4, "Design rich embed schema for mesh intent responses"). Acceptance not met by landed code (runtime/discord_response.py): 1. Schema has no timestamp. Card requires title/description/fields/color/timestamp/footer; _build_embed_dict emits title/description/color/fields/footer only. 2. No typed MeshIntentResult input. Card requires an EmbedBuilder taking a typed MeshIntentResult; landed API is format_mesh_result(intent_type: str, result: Any). No MeshIntentResult type exists in the repo. 3. Color map not keyed by IntentType enum. Card requires a color mapping table keyed by an IntentType enum (info=blue, warn=yellow, error=red, success=green); landed COLORS is dict[str, int] keyed by string literals (research/write/chat/status/error). No IntentType enum exists. 4. 6000-char total embed limit not enforced. Card requires the embed stays within Discord's 6000-char total / 25-field / 1024-char-per-field limits. Landed code enforces the 25-field cap, 1024 field-value, 256 field-name, and 4096 description, but never computes the 6000-char total across title+description+field names+values+footer. Verification evidence (commit 5a1d111, local-only unpushed; origin/master still e8c24a0; #234 still open): - pytest tests/unit/test_discord_response.py -> 13 passed - ruff check runtime/discord_response.py runtime/discord_ingress.py runtime/__init__.py tests/unit/test_discord_response.py -> clean Acceptance criteria for this issue: - Embed dict includes ISO-8601 timestamp (default: result completion time or now()). - Public builder accepts a typed MeshIntentResult (define the type; keep framework-agnostic dict output). - IntentType enum defined; COLORS keyed by IntentType; add warn=yellow mapping. - Enforce 6000-char total embed budget (sum check with clipping) and add a test asserting the total with a maxed-out embed. - Document the schema (module docstring or docs/ entry).
Author
Owner

Authoritative spec (kanban card t_842f0b3f) for this delta — implement exactly:

Data model:

  • IntentType enum: INFO="info", WARN="warn", ERROR="error", SUCCESS="success", UNKNOWN="unknown".
  • MeshIntentResult frozen dataclass: intent_type: IntentType (required, non-optional), title: str, description: str, fields: list[tuple[str,str]]=[], timestamp: str|None=None (ISO8601/RFC3339 UTC), footer: str|None=None, author: str|None=None.

Color table (module-level dict keyed by enum members, never string literals):

  • INFO=0x3498DB (#3498DB blue), WARN=0xF1C40F (#F1C40F yellow), ERROR=0xE74C3C (#E74C3C red), SUCCESS=0x2ECC71 (#2ECC71 green), UNKNOWN=0x95A5A6 (#95A5A6 neutral gray default).
  • Resolution never raises: COLORS.get(intent_type, COLORS[IntentType.UNKNOWN]).

Discord limits (clamp with trailing ellipsis '…', i.e. s[:limit-1]+'…'; field-count overflow raises):

  • title 256, description 4096, field name 256, field value 1024, footer text 2048, author name 256, field count 25 (ValueError 'too many embed fields: N (max 25)' — never clamp), total budget 6000.
  • Total budget = len(title)+len(description)+sum(len(field.name)+len(field.value))+(len(footer) if footer)+(len(author) if author). timestamp and color NOT counted.
  • Total-budget enforcement order: drop trailing fields until <=6000 (warn per pop), then clamp description, then footer, then title.

Output (canonical dict, always framework-agnostic):

  • build_embed(result: MeshIntentResult) -> dict with keys title, description, color (int), fields [{"name","value","inline":bool default False}]. Include timestamp iff set (never null), footer {"text":...} iff set, author {"name":...} iff set.
  • to_discord_embed(data) thin lazy adapter: import discord inside function (ImportError when absent), discord.Embed(title, description, color=discord.Color(data["color"])), add_field per entry, embed.timestamp = datetime.fromisoformat(ts), set_footer, set_author. Python 3.12+ so fromisoformat handles trailing Z.
  • Keep format_mesh_result(intent_type: str, result: Any) and format* helpers working unchanged; may refactor internals to reuse build_embed. COLORS re-keying str->IntentType is the one breaking change; do NOT keep both key types in the same table.

Tests (new file tests/unit/test_embed_builder.py preferred): one test per IntentType member for COLORS + build_embed color int (5), unknown default gray, truncation for title/desc/field-value/footer/author each clamps with '…', 28 fields -> ValueError and 25 fields ok, total-budget overshoot drops trailing fields, timestamp set/None, footer/author set/None, existing 13 tests in tests/unit/test_discord_response.py keep passing.

Full spec: workspace file MeshIntentResult-embed-schema.md (kanban card t_842f0b3f attachments).

Authoritative spec (kanban card t_842f0b3f) for this delta — implement exactly: Data model: - IntentType enum: INFO="info", WARN="warn", ERROR="error", SUCCESS="success", UNKNOWN="unknown". - MeshIntentResult frozen dataclass: intent_type: IntentType (required, non-optional), title: str, description: str, fields: list[tuple[str,str]]=[], timestamp: str|None=None (ISO8601/RFC3339 UTC), footer: str|None=None, author: str|None=None. Color table (module-level dict keyed by enum members, never string literals): - INFO=0x3498DB (#3498DB blue), WARN=0xF1C40F (#F1C40F yellow), ERROR=0xE74C3C (#E74C3C red), SUCCESS=0x2ECC71 (#2ECC71 green), UNKNOWN=0x95A5A6 (#95A5A6 neutral gray default). - Resolution never raises: COLORS.get(intent_type, COLORS[IntentType.UNKNOWN]). Discord limits (clamp with trailing ellipsis '…', i.e. s[:limit-1]+'…'; field-count overflow raises): - title 256, description 4096, field name 256, field value 1024, footer text 2048, author name 256, field count 25 (ValueError 'too many embed fields: N (max 25)' — never clamp), total budget 6000. - Total budget = len(title)+len(description)+sum(len(field.name)+len(field.value))+(len(footer) if footer)+(len(author) if author). timestamp and color NOT counted. - Total-budget enforcement order: drop trailing fields until <=6000 (warn per pop), then clamp description, then footer, then title. Output (canonical dict, always framework-agnostic): - build_embed(result: MeshIntentResult) -> dict with keys title, description, color (int), fields [{"name","value","inline":bool default False}]. Include timestamp iff set (never null), footer {"text":...} iff set, author {"name":...} iff set. - to_discord_embed(data) thin lazy adapter: import discord inside function (ImportError when absent), discord.Embed(title, description, color=discord.Color(data["color"])), add_field per entry, embed.timestamp = datetime.fromisoformat(ts), set_footer, set_author. Python 3.12+ so fromisoformat handles trailing Z. - Keep format_mesh_result(intent_type: str, result: Any) and _format_* helpers working unchanged; may refactor internals to reuse build_embed. COLORS re-keying str->IntentType is the one breaking change; do NOT keep both key types in the same table. Tests (new file tests/unit/test_embed_builder.py preferred): one test per IntentType member for COLORS + build_embed color int (5), unknown default gray, truncation for title/desc/field-value/footer/author each clamps with '…', 28 fields -> ValueError and 25 fields ok, total-budget overshoot drops trailing fields, timestamp set/None, footer/author set/None, existing 13 tests in tests/unit/test_discord_response.py keep passing. Full spec: workspace file MeshIntentResult-embed-schema.md (kanban card t_842f0b3f attachments).
Mark 2026-08-12 10:48:35 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Mark/mesh-seed#271
No description provided.