Merge be3e65ac8c into c896c09c42
This commit is contained in:
commit
e9fdd13cf0
|
|
@ -38,7 +38,12 @@ def _fmt_pending_list(subsystem: str) -> str:
|
|||
for r in records:
|
||||
origin = r.get("origin", "foreground")
|
||||
tag = " [auto]" if origin == "background_review" else ""
|
||||
lines.append(f" {r['id']}{tag} {r.get('summary', '')}")
|
||||
badge = ""
|
||||
v = r.get("validation")
|
||||
if v and v != "ok":
|
||||
reason = v[len("blocked: "):] if v.startswith("blocked: ") else v
|
||||
badge = " \u26a0\ufe0f BLOCKED: %s" % reason[:70]
|
||||
lines.append(f" {r['id']}{tag}{badge} {r.get('summary', '')}")
|
||||
where = "/{s} approve <id>".format(s=subsystem)
|
||||
lines.append("")
|
||||
lines.append(f"Apply: {where} Reject: /{subsystem} reject <id>")
|
||||
|
|
|
|||
|
|
@ -1459,10 +1459,29 @@ def _apply_skill_write_gate(action, name, **payload_kwargs):
|
|||
old_string=payload_kwargs.get("old_string") or "",
|
||||
new_string=payload_kwargs.get("new_string") or "",
|
||||
)
|
||||
record = wa.stage_write(wa.SKILLS, payload, summary=gist, origin=wa.current_origin())
|
||||
# Pre-validate creates at staging time so a record that can never be
|
||||
# applied (frontmatter description over SKILL_PROMPT_DESC_LIMIT, missing
|
||||
# name, missing frontmatter, etc.) is flagged immediately instead of
|
||||
# failing later at /skills approve — the exact trap that left 26 blocked
|
||||
# creates in the backlog. The record is STILL staged (nothing is lost);
|
||||
# the blocker is recorded, shown in /skills pending, and echoed in the
|
||||
# response so the agent can fix the description before approving.
|
||||
validation = "ok"
|
||||
if action == "create":
|
||||
try:
|
||||
err = _validate_frontmatter(payload.get("content") or "", new_skill=True)
|
||||
if err:
|
||||
validation = "blocked: " + err.splitlines()[0]
|
||||
except Exception:
|
||||
validation = "ok" # fail open: never block staging on validator bugs
|
||||
record = wa.stage_write(
|
||||
wa.SKILLS, payload, summary=gist, origin=wa.current_origin(),
|
||||
validation=validation,
|
||||
)
|
||||
return json.dumps(
|
||||
{"success": True, "staged": True, "pending_id": record["id"],
|
||||
"gist": gist, "message": decision.message},
|
||||
"gist": gist, "message": decision.message,
|
||||
"validation": validation},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ def _pending_dir(subsystem: str) -> Path:
|
|||
|
||||
|
||||
def stage_write(subsystem: str, payload: Dict[str, Any],
|
||||
*, summary: str, origin: str) -> Dict[str, Any]:
|
||||
*, summary: str, origin: str, validation: str = "ok") -> Dict[str, Any]:
|
||||
"""Persist a pending write and return a short record describing it.
|
||||
|
||||
Args:
|
||||
|
|
@ -124,6 +124,11 @@ def stage_write(subsystem: str, payload: Dict[str, Any],
|
|||
For skills this is the LLM/heuristic gist; for memory it can be the
|
||||
entry text itself.
|
||||
origin: ``foreground`` or ``background_review`` — recorded for audit.
|
||||
validation: pre-computed apply-time check result for the staged write.
|
||||
``"ok"`` (default) means it will apply; anything else is a short
|
||||
``"blocked: <reason>"`` flag surfaced in pending lists so a record
|
||||
that can never be applied is visible before approval. Recorded for
|
||||
audit; never used to refuse staging (a staged write is never lost).
|
||||
|
||||
Returns a dict with ``id`` and metadata. Best-effort: on disk failure it
|
||||
logs and still returns a record (the write is simply lost, which is the
|
||||
|
|
@ -136,6 +141,7 @@ def stage_write(subsystem: str, payload: Dict[str, Any],
|
|||
"action": payload.get("action", ""),
|
||||
"summary": (summary or "").strip(),
|
||||
"origin": origin or "foreground",
|
||||
"validation": validation,
|
||||
"created_at": time.time(),
|
||||
"payload": payload,
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue