Skip to content

Commit 5d812b2

Browse files
feat: add Phase 5 source-first editorial queue
1 parent f8e1d97 commit 5d812b2

6 files changed

Lines changed: 1032 additions & 0 deletions

app/sentry_runtime.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from .observability import capture_technical_exception, init_optional_sentry
1212
from . import final_edit_capture_runtime as _final_edit_capture_runtime
1313
from . import production_outcome_runtime as _outcome_runtime
14+
from . import source_first_runtime as _source_first_runtime
1415

1516
# Final Edit Capture is deliberately installed only on the normal Daily/private-review
1617
# entrypoint. app.fic_digest imports neither this module nor the capture runtime.
@@ -19,6 +20,11 @@
1920

2021
from .webhook_aware_assistant import WebhookAwarePersonalAssistant
2122

23+
# Product Roadmap Phase 5 changes only the private editorial navigation layer. Install
24+
# it on the final normal-Daily application class so Fanfic/AO3 and lower-level reusable
25+
# classes keep their established behavior.
26+
_source_first_runtime.install(WebhookAwarePersonalAssistant)
27+
2228

2329
async def async_main() -> int:
2430
init_optional_sentry()

app/source_first_inbox_ui.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
from __future__ import annotations
2+
3+
from .source_first_queue import SourceQueueSnapshot
4+
from .telegram import inline_keyboard
5+
6+
_STATE_ICON = {
7+
"active": "▶️",
8+
"pending": "⏳",
9+
"deferred": "⏸",
10+
"complete": "✅",
11+
}
12+
_PROOF_ICON = {
13+
"complete": "✓",
14+
"partial": "~",
15+
"unproven": "?",
16+
"unknown": "·",
17+
}
18+
19+
20+
def source_first_text(snapshot: SourceQueueSnapshot) -> str:
21+
if not snapshot.session_id:
22+
return (
23+
"📥 صندوق بررسی منبع‌به‌منبع\n\n"
24+
"فعلاً پیش‌نویسِ در انتظار بررسی نداریم."
25+
)
26+
27+
lines = ["📥 صندوق بررسی منبع‌به‌منبع", ""]
28+
if snapshot.active_source:
29+
lines.extend(
30+
[
31+
f"منبع {snapshot.active_position}/{snapshot.total_sources}: @{snapshot.active_source}",
32+
f"پست {snapshot.current_item_number}/{snapshot.current_item_total}",
33+
"این منبع تا تمام‌شدن پست‌هایش فعال می‌ماند؛ برای رفتن به منبع بعدی باید آن را صریحاً عقب بیندازی.",
34+
"",
35+
]
36+
)
37+
elif snapshot.deferred_sources:
38+
lines.extend(["همهٔ موارد باقی‌مانده فعلاً عقب انداخته شده‌اند.", ""])
39+
else:
40+
lines.extend(["این دور بررسی تمام شده است.", ""])
41+
42+
proof_complete = sum(item.completeness_status == "complete" for item in snapshot.sources)
43+
lines.append(f"اثبات پوشش Phase 4 (shadow): {proof_complete}/{snapshot.total_sources} منبع COMPLETE")
44+
lines.append("وضعیت منابع:")
45+
for item in snapshot.sources:
46+
state = _STATE_ICON.get(item.state, "•")
47+
proof = _PROOF_ICON.get(item.completeness_status, "·")
48+
progress = f"{item.done_items}/{item.total_items}" if item.total_items else "0/0"
49+
retry = " · retry failed" if item.last_retry_status == "failed" else ""
50+
lines.append(f"{state} @{item.source} · {progress} · proof {proof}{retry}")
51+
return "\n".join(lines)
52+
53+
54+
def source_first_keyboard(snapshot: SourceQueueSnapshot):
55+
rows: list[list[tuple[str, str]]] = []
56+
if snapshot.active_source and snapshot.current_draft_id:
57+
rows.append([("📝 باز کردن پست فعلی", "sq:open")])
58+
rows.append(
59+
[
60+
("⏸ عقب انداختن این منبع", f"sq:defer:{snapshot.active_source}"),
61+
("🔁 retry همین منبع", f"sq:retry:{snapshot.active_source}"),
62+
]
63+
)
64+
for source in snapshot.deferred_sources[:8]:
65+
rows.append([(f"▶️ ادامه @{source}", f"sq:resume:{source}")])
66+
rows.append([("🕘 نمای قدیمیِ زمانی", "sq:legacy:pending:0")])
67+
return inline_keyboard(rows)
68+
69+
70+
def source_first_draft_keyboard(draft_id: str, source: str):
71+
return inline_keyboard(
72+
[
73+
[("😂 بامزه‌تر", f"draft:fun:{draft_id}"), ("🪽 نرم‌تر", f"draft:soft:{draft_id}")],
74+
[("📰 دقیق‌تر", f"draft:precise:{draft_id}"), ("📋 متن تمیز", f"draft:copy:{draft_id}")],
75+
[("🗑 رد", f"draft:reject:{draft_id}")],
76+
[("⏸ عقب انداختن منبع", f"sq:defer:{source}"), ("🔁 retry منبع", f"sq:retry:{source}")],
77+
[("◀️ برگشت به صف منبعی", "sq:home")],
78+
]
79+
)

0 commit comments

Comments
 (0)