feat: update feishu intake

This commit is contained in:
2026-08-02 14:08:11 +08:00
parent e9b34747cc
commit 6855ac7078
13 changed files with 535 additions and 23 deletions
+29 -11
View File
@@ -26,6 +26,9 @@ from typing import Any
from yaml_subset import DuplicateKeyError, YamlSubsetError, load_json_unique, load_yaml_subset, make_unique_pyyaml_loader
REQUIRED_FIELDS = ("title", "actual", "expected", "stepsToReproduce", "acceptance", "priority", "attachments", "updatedAt")
SOURCE_FACT_FIELDS = ("title", "actual", "expected", "updatedAt")
COORDINATOR_FIELDS = ("steps", "acceptance", "priority")
BUG_CONTENT_FIELDS = ("title", "actual", "expected", *COORDINATOR_FIELDS)
MAX_PAGES = 100
MAX_RECORDS = 10_000
PAGE_SIZE = 100
@@ -444,6 +447,7 @@ def source_ref(config: dict[str, Any], record_id: str) -> str:
def fetch(config: dict[str, Any], output_dir: Path | None) -> dict[str, Any]:
profile_check(config)
prepared: list[tuple[dict[str, Any], list[tuple[dict[str, Any], str]]]] = []
batch_warnings: list[dict[str, str]] = []
total_attachments = 0
total_attachment_bytes = 0
for record_id, row in fetch_pages(config):
@@ -456,9 +460,15 @@ def fetch(config: dict[str, Any], output_dir: Path | None) -> dict[str, Any]:
if total_attachment_bytes > MAX_TOTAL_ATTACHMENT_BYTES:
raise IntakeError("batch exceeded the attachment byte limit")
record = {"sourceRef": source_ref(config, record_id), "recordId": record_id, "updatedAt": text(cells["updatedAt"]), "title": text(cells["title"]), "actual": text(cells["actual"]), "expected": text(cells["expected"]), "steps": text(cells["stepsToReproduce"]), "acceptance": text(cells["acceptance"]), "priority": text(cells["priority"]), "attachments": [metadata for metadata, _ in attachment_data], "warnings": []}
for field in ("title", "actual", "expected", "steps", "acceptance", "priority", "updatedAt"):
if not attachment_data and not any(record[field] for field in BUG_CONTENT_FIELDS):
batch_warnings.append({"recordId": record_id, "code": "blank_record_skipped"})
continue
for field in SOURCE_FACT_FIELDS:
if not record[field]:
raise IntakeError(f"record {field} must not be empty")
record["enrichmentRequired"] = [
field for field in COORDINATOR_FIELDS if not record[field]
]
prepared.append((record, attachment_data))
download_root: Path | None = None
if output_dir is not None:
@@ -483,10 +493,10 @@ def fetch(config: dict[str, Any], output_dir: Path | None) -> dict[str, Any]:
attachment["size"], min(60, remaining),
)
records.append(record)
return {"provider": "feishu-base", "profile": config["profile"], "tableId": config["tableId"], "viewId": config["viewId"], "records": records}
return {"provider": "feishu-base", "profile": config["profile"], "tableId": config["tableId"], "viewId": config["viewId"], "records": records, "warnings": batch_warnings}
def plan_actions(board: dict[str, Any], records: list[dict[str, Any]]) -> list[dict[str, str]]:
def plan_actions(board: dict[str, Any], records: list[dict[str, Any]]) -> list[dict[str, Any]]:
"""Plan idempotent Coordinator actions without mutating the task board."""
tasks = board.get("tasks")
if not isinstance(tasks, list):
@@ -513,7 +523,7 @@ def plan_actions(board: dict[str, Any], records: list[dict[str, Any]]) -> list[d
raise IntakeError("task board contains duplicate Feishu source references")
existing[ref] = task
actions: list[dict[str, str]] = []
actions: list[dict[str, Any]] = []
seen_records: set[str] = set()
for record in records:
ref = record.get("sourceRef")
@@ -530,22 +540,30 @@ def plan_actions(board: dict[str, Any], records: list[dict[str, Any]]) -> list[d
seen_records.add(ref)
task = existing.get(ref)
if task is None:
actions.append({"sourceRef": ref, "recordId": record_id, "action": "create"})
planned_action: dict[str, Any] = {"sourceRef": ref, "recordId": record_id, "action": "create"}
enrichment_required = record.get("enrichmentRequired")
if enrichment_required:
planned_action["enrichmentRequired"] = enrichment_required
actions.append(planned_action)
continue
source = task["source"]
if source["updatedAt"] == updated_at:
action = "unchanged"
action_name = "unchanged"
elif task["status"] == "open":
action = "refresh"
action_name = "refresh"
else:
action = "drift"
actions.append({
action_name = "drift"
planned_action = {
"sourceRef": ref,
"recordId": record_id,
"taskId": task["id"],
"status": task["status"],
"action": action,
})
"action": action_name,
}
enrichment_required = record.get("enrichmentRequired")
if enrichment_required and action_name == "refresh":
planned_action["enrichmentRequired"] = enrichment_required
actions.append(planned_action)
return actions