Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion tests/engineering/test_dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -761,7 +761,7 @@ def test_engineering_database_details_are_read_only_and_report_the_schema(self)

self.assertRegex(details["size"], r"^\d+,\d{2} MB$")
self.assertNotEqual(details["size"], "0,00 MB")
self.assertEqual(details["schema_version"], "17")
self.assertEqual(details["schema_version"], "18")

@patch("tools.engineering.dashboard.subprocess.run")
def test_tracked_file_count_counts_recursive_git_index_entries(self, run: object) -> None:
Expand Down
29 changes: 29 additions & 0 deletions tests/engineering/test_execution_host.py
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,35 @@ def test_repository_mismatch_fails_closed_on_resume(self) -> None:
with self.assertRaisesRegex(RunnerError, "conflicts"):
runner.run(self.prompt, run_id="resume-run", resume=True)

def test_resume_rejects_a_dismissed_execution_without_invoking_the_agent(self) -> None:
from tools.engineering.prompt_history import record_prompt_execution
from tools.engineering.storage import record_execution_dismissal

run_id = "dismissed-resume-run"
self.store.save(TransactionState(run_id, "pcvantol/djconnect", str(self.prompt), "EXECUTE_AGENT"))
record_prompt_execution(
self.root,
run_id=run_id,
terminal_state="BLOCKED",
prompt_title="Dismissed blocked execution",
executed_at="2026-08-08T10:00:00+00:00",
)
record_execution_dismissal(
self.root,
run_id=run_id,
terminal_state="BLOCKED",
dismissed_at="2026-08-08T10:01:00+00:00",
dismissed_by="test_operator",
)
agent = FakeAgent(AgentResult("COMPLETE"))
runner = EngineeringRunner(self.root, self.store, FakeRepository(), FakeGitHub([]), agent, lambda _: None)

with self.assertRaisesRegex(RunnerError, "already been dismissed"):
runner.run(self.prompt, run_id=run_id, resume=True)

self.assertEqual(agent.prompts, [])
self.assertEqual(self.store.load(run_id).phase, "EXECUTE_AGENT")

def test_resume_recomputes_waiting_phase_from_pr_evidence(self) -> None:
self.store.save(TransactionState("resume-run", "pcvantol/djconnect", str(self.prompt), "EXECUTE_AGENT", pull_request=11, diagnostic="Prior waiting diagnostic."))
pending = PullRequestEvidence(11, "OPEN", False, False)
Expand Down
11 changes: 8 additions & 3 deletions tests/engineering/test_inbox_watcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -852,7 +852,7 @@ def test_execution_retry_supports_failed_and_refuses_non_retryable_or_duplicate_
with self.assertRaisesRegex(inbox_watcher.RetrySubmissionError, "staat al in de wachtrij"):
inbox_watcher.submit_execution_retry(self.repo, self.root, run_id)

def test_dismiss_terminal_execution_clears_operational_state_and_preserves_audit(self) -> None:
def test_dismiss_terminal_execution_persists_immutable_handling_and_blocks_retry(self) -> None:
run_id = "inbox-dismissed"
runs = self.repo / ".engineering" / "engineering-runs"
runs.mkdir(parents=True, exist_ok=True)
Expand All @@ -864,8 +864,13 @@ def test_dismiss_terminal_execution_clears_operational_state_and_preserves_audit
self.assertTrue(outcome["dismissed"])
self.assertEqual(json_status(self.repo)["watcher_state"], "WATCHER_IDLE")
self.assertIsNone(json_status(self.repo)["last_executed_run"])
audit = json.loads((status / "execution_dismissals.json").read_text(encoding="utf-8"))
self.assertEqual(audit[-1]["run_id"], run_id)
self.assertEqual(outcome["terminal_state"], "BLOCKED")
self.assertEqual(outcome["handling_state"], "DISMISSED")
with self.assertRaisesRegex(inbox_watcher.RetrySubmissionError, "al afgesloten"):
inbox_watcher.submit_execution_retry(self.repo, self.root, run_id)
history = __import__("tools.engineering.prompt_history", fromlist=["prompt_history"]).prompt_history(self.repo)
self.assertTrue(history[0]["dismissed"])
self.assertEqual(history[0]["status"], "BLOCKED")

def test_migration_moves_legacy_archives_and_removes_iCloud_status(self) -> None:
(self.root / "Completed").mkdir()
Expand Down
4 changes: 4 additions & 0 deletions tests/engineering/test_prompt_history.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ def test_records_terminal_run_and_serves_only_its_local_report(self) -> None:
"producer_submission_contract_version": None,
"execution_context_version": None,
"execution_context": None,
"dismissed": False,
"handling_state": "OPEN",
"dismissed_at": None,
"dismissed_by": None,
"retry_child_run_id": None,
"retry_status": None,
"queued_retry_child": False,
Expand Down
13 changes: 8 additions & 5 deletions tools/engineering/ENGINEERING_INBOX_PROTOCOL.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,10 +216,13 @@ and clears Active Execution so the watcher returns to idle without changing the
queue. The confirmation shows Run ID, prompt title and terminal state, and
explains that no work will restart.

Dismiss records `dismissed`, `dismissed_at` and `dismissed_by` in local audit
evidence. Engineering Reports, terminal evidence, telemetry, Prompt History
and retry relationships remain immutable. A dismissed `BLOCKED` execution may
still be retried later, while Queue Recovery remains the separate explicit
operation for dependent Inbox work. Dismiss never resumes that queue.
Dismiss records `dismissed`, `dismissed_at` and `dismissed_by` as immutable
operator-handling evidence in the canonical SQLite datastore. Engineering
Reports, terminal evidence, telemetry, Prompt History and retry relationships
remain immutable. A dismissed terminal execution is read-only: Retry, Resume,
Dismiss and every other lifecycle-mutating action are unavailable and rejected
server-side, including requests from a stale client. Queue Recovery remains the
separate explicit operation for dependent Inbox work. Dismiss never resumes
that queue.

Commands: `python3 -m tools.engineering.inbox_watcher once|run|status|install|uninstall|doctor|migrate-icloud-archives`.
4 changes: 3 additions & 1 deletion tools/engineering/assets/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -2758,7 +2758,7 @@ function renderPromptHistory() {
button.addEventListener("click", () => openPromptHistoryChat(entry));
chat.append(button);
} else chat.textContent = "—";
if (entry.can_retry === true && entry.run_id) {
if (entry.can_retry === true && !entry.dismissed && entry.run_id) {
const retry = document.createElement("button");
retry.type = "button";
retry.className = "predecessor-retry execution-history-action";
Expand Down Expand Up @@ -3523,6 +3523,8 @@ function promptDetailExecutionSection(history) {
] : [detailField(t("execution_context.snapshot"), t("execution_context.not_supplied"))];
return promptDetailCard(t("detail.execution"), [
promptDetailStatusField(history.status),
detailField(t("detail.operator_handling"), history.dismissed ? t("handling.dismissed") : t("handling.open")),
...(history.dismissed_at ? [detailField(t("detail.dismissed_at"), history.dismissed_at)] : []),
detailField(t("detail.prompt_title"), history.title),
detailField(t("detail.run_id"), history.run_id, true),
detailField(
Expand Down
25 changes: 25 additions & 0 deletions tools/engineering/assets/dashboard_locales.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ export const DASHBOARD_MESSAGES = {
"detail.not_recorded": "Not recorded.",
"detail.output_tokens": "Output tokens",
"detail.prompt_status": "Execution status",
"detail.operator_handling": "Operator handling",
"detail.dismissed_at": "Dismissed at",
"detail.prompt_title": "Execution title",
"detail.provider_usage": "AI provider usage",
"detail.plan_remaining": "Remaining in plan",
Expand All @@ -94,6 +96,9 @@ export const DASHBOARD_MESSAGES = {
"dismiss.details": "Run ID: {run_id}\nExecution title: {title}\nTerminal state: {state}\n\nExecution history, reports, telemetry and retry relationships are preserved. Only operational active state is cleared. No engineering work will restart.",
"dismiss.failed": "Dismiss Execution could not be completed.",
"dismiss.title": "Dismiss Execution",
"handling.dismissed": "Dismissed / Closed",
"handling.open": "Open",
"retry.dismissed": "This execution has already been dismissed; retry is unavailable.",
"enum.CAPABILITY": "Capability",
"enum.ENGINEERING": "Engineering",
"enum.FAIL": "Failed",
Expand Down Expand Up @@ -502,6 +507,8 @@ export const DASHBOARD_MESSAGES = {
"detail.not_recorded": "Niet vastgelegd.",
"detail.output_tokens": "Uitvoertokens",
"detail.prompt_status": "Uitvoeringsstatus",
"detail.operator_handling": "Operatorafhandeling",
"detail.dismissed_at": "Afgesloten op",
"detail.prompt_title": "Uitvoeringstitel",
"detail.provider_usage": "AI-providergebruik",
"detail.plan_remaining": "Resterend in plan",
Expand All @@ -522,6 +529,9 @@ export const DASHBOARD_MESSAGES = {
"dismiss.details": "Run-ID: {run_id}\nUitvoeringstitel: {title}\nEindstatus: {state}\n\nUitvoeringsgeschiedenis, rapporten, telemetrie en retry-relaties blijven bewaard. Alleen de actieve operationele status wordt gewist. Engineering wordt niet opnieuw gestart.",
"dismiss.failed": "De uitvoering kon niet worden afgesloten.",
"dismiss.title": "Uitvoering afsluiten",
"handling.dismissed": "Afgesloten",
"handling.open": "Open",
"retry.dismissed": "Deze uitvoering is al afgesloten; opnieuw proberen is niet beschikbaar.",
"enum.CAPABILITY": "Capability",
"enum.ENGINEERING": "Engineering",
"enum.FAIL": "Mislukt",
Expand Down Expand Up @@ -930,6 +940,8 @@ export const DASHBOARD_MESSAGES = {
"detail.not_recorded": "Nicht erfasst.",
"detail.output_tokens": "Ausgabetoken",
"detail.prompt_status": "Ausführungsstatus",
"detail.operator_handling": "Operatorbearbeitung",
"detail.dismissed_at": "Geschlossen am",
"detail.prompt_title": "Ausführungstitel",
"detail.provider_usage": "KI-Anbieternutzung",
"detail.plan_remaining": "Im Tarif verbleibend",
Expand All @@ -950,6 +962,9 @@ export const DASHBOARD_MESSAGES = {
"dismiss.details": "Run-ID: {run_id}\nAusführungstitel: {title}\nEndstatus: {state}\n\nAusführungshistorie, Berichte, Telemetrie und Wiederholungsbeziehungen bleiben erhalten. Nur der aktive Betriebsstatus wird gelöscht. Es wird keine Engineering-Arbeit neu gestartet.",
"dismiss.failed": "Die Ausführung konnte nicht geschlossen werden.",
"dismiss.title": "Ausführung schließen",
"handling.dismissed": "Geschlossen",
"handling.open": "Offen",
"retry.dismissed": "Diese Ausführung wurde bereits geschlossen; eine Wiederholung ist nicht verfügbar.",
"enum.CAPABILITY": "Capability",
"enum.ENGINEERING": "Engineering",
"enum.FAIL": "Fehlgeschlagen",
Expand Down Expand Up @@ -1305,6 +1320,8 @@ export const DASHBOARD_MESSAGES = {
"detail.not_recorded": "Non enregistré.",
"detail.output_tokens": "Jetons de sortie",
"detail.prompt_status": "État de l’exécution",
"detail.operator_handling": "Traitement opérateur",
"detail.dismissed_at": "Clôturée le",
"detail.prompt_title": "Titre de l’exécution",
"detail.provider_usage": "Utilisation du fournisseur IA",
"detail.plan_remaining": "Restant dans le forfait",
Expand All @@ -1325,6 +1342,9 @@ export const DASHBOARD_MESSAGES = {
"dismiss.details": "ID d’exécution : {run_id}\nTitre de l’exécution : {title}\nÉtat final : {state}\n\nL’historique, les rapports, la télémétrie et les relations de relance sont conservés. Seul l’état opérationnel actif est effacé. Aucun travail d’ingénierie ne redémarrera.",
"dismiss.failed": "L’exécution n’a pas pu être clôturée.",
"dismiss.title": "Clore l’exécution",
"handling.dismissed": "Clôturée",
"handling.open": "Ouvert",
"retry.dismissed": "Cette exécution a déjà été clôturée ; la relance est indisponible.",
"enum.CAPABILITY": "Capacité",
"enum.ENGINEERING": "Ingénierie",
"enum.FAIL": "Échec",
Expand Down Expand Up @@ -1680,6 +1700,8 @@ export const DASHBOARD_MESSAGES = {
"detail.not_recorded": "No registrado.",
"detail.output_tokens": "Tokens de salida",
"detail.prompt_status": "Estado de la ejecución",
"detail.operator_handling": "Gestión del operador",
"detail.dismissed_at": "Cerrada el",
"detail.prompt_title": "Título de la ejecución",
"detail.provider_usage": "Uso del proveedor de IA",
"detail.plan_remaining": "Restante en el plan",
Expand All @@ -1700,6 +1722,9 @@ export const DASHBOARD_MESSAGES = {
"dismiss.details": "ID de ejecución: {run_id}\nTítulo de la ejecución: {title}\nEstado final: {state}\n\nSe conservan el historial, los informes, la telemetría y las relaciones de reintento. Solo se borra el estado operativo activo. No se reiniciará ningún trabajo de ingeniería.",
"dismiss.failed": "No se pudo cerrar la ejecución.",
"dismiss.title": "Cerrar ejecución",
"handling.dismissed": "Cerrada",
"handling.open": "Abierta",
"retry.dismissed": "Esta ejecución ya se cerró; no se puede reintentar.",
"enum.CAPABILITY": "Capacidad",
"enum.ENGINEERING": "Ingeniería",
"enum.FAIL": "Fallido",
Expand Down
3 changes: 3 additions & 0 deletions tools/engineering/execution_host.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
from .execution_finalization import FinalizationCoordinator
from .execution_reporting import ReportingCoordinator
from .storage import load_readiness_evaluation, record_readiness_evaluation
from .storage import dismissal_for_run

# Compatibility exports remain at this façade while implementation resides in
# the dedicated context, repository and executor modules.
Expand Down Expand Up @@ -320,6 +321,8 @@ def run(
) -> TransactionState:
objective = prompt_path.read_text(encoding="utf-8")
state = self.store.load(run_id) if resume else None
if resume and state is not None and dismissal_for_run(self.root, state.run_id):
raise RunnerError("This execution has already been dismissed and cannot be resumed.")
try:
context = resolve_execution_context(objective, self.root)
except RunnerError as error:
Expand Down
34 changes: 23 additions & 11 deletions tools/engineering/inbox_watcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
from .capability_preflight import execute as execute_capability_preflight
from .producer import ProducerSubmissionError, parse_producer_metadata, parse_producer_submission
from .drift_diagnostics import summary as drift_summary
from .storage import EngineeringStorageError, load_projection, open_storage, record_artifact, record_submission
from .storage import EngineeringStorageError, dismissal_for_run, load_projection, open_storage, record_artifact, record_execution_dismissal, record_submission
from .execution_lease import liveness as lease_liveness, reconcile_stale

LABEL = "com.djconnect.engineering-inbox"
Expand Down Expand Up @@ -608,6 +608,8 @@ def retry_admission_preflight(repo: Path, run_id: str) -> None:
"""
if not re.fullmatch(r"inbox-[a-z0-9-]{6,64}", run_id):
raise RetrySubmissionError("De opgegeven run-ID is ongeldig.")
if dismissal_for_run(repo, run_id):
raise RetrySubmissionError("Deze uitvoering is al afgesloten; opnieuw proberen is niet beschikbaar.")
archived = _archived_prompt_for_run(repo, run_id)
if archived is None:
raise RetrySubmissionError("De oorspronkelijke terminale prompt is lokaal niet beschikbaar.")
Expand Down Expand Up @@ -655,19 +657,27 @@ def dismiss_execution(repo: Path, run_id: str, *, dismissed_by: str = "dashboard
phase = _terminal_phase_for_run(repo, run_id)
if phase not in TERMINAL_PHASES or current.get("last_executed_run") != run_id:
raise RetrySubmissionError("Alleen de huidige terminale uitvoering kan worden bevestigd.")
if dismissal_for_run(repo, run_id):
raise RetrySubmissionError("Deze uitvoering is al afgesloten.")
timestamp = datetime.now(timezone.utc).isoformat()
audit_path = status_path.with_name("execution_dismissals.json")
connection = open_storage(repo)
try:
records = json.loads(audit_path.read_text(encoding="utf-8")) if audit_path.exists() else []
except (OSError, json.JSONDecodeError) as error:
history_exists = connection.execute(
"SELECT 1 FROM prompt_execution_history WHERE run_id=?", (run_id,)
).fetchone() is not None
finally:
connection.close()
if not history_exists:
record_prompt_execution(
repo, run_id=run_id, terminal_state=phase,
prompt_title=current.get("last_executed_title") or run_id, executed_at=timestamp,
)
try:
record = record_execution_dismissal(
repo, run_id=run_id, terminal_state=phase, dismissed_at=timestamp, dismissed_by=dismissed_by,
)
except EngineeringStorageError as error:
raise RetrySubmissionError("De dismissal-audit is niet veilig beschikbaar.") from error
if not isinstance(records, list):
raise RetrySubmissionError("De dismissal-audit is ongeldig.")
record = {"run_id": run_id, "terminal_state": phase, "dismissed": True, "dismissed_at": timestamp, "dismissed_by": dismissed_by}
records.append(record)
temporary = audit_path.with_suffix(".tmp")
temporary.write_text(json.dumps(records, separators=(",", ":"), sort_keys=True) + "\n", encoding="utf-8")
os.replace(temporary, audit_path)
status(
repo,
"WATCHER_IDLE",
Expand All @@ -687,6 +697,8 @@ def submit_execution_retry(repo: Path, root: Path, run_id: str, *, queue_recover
if not re.fullmatch(r"inbox-[a-z0-9-]{6,64}", run_id):
raise RetrySubmissionError("De opgegeven run-ID is ongeldig.")
with _lock(repo):
if dismissal_for_run(repo, run_id):
raise RetrySubmissionError("Deze uitvoering is al afgesloten; opnieuw proberen is niet beschikbaar.")
terminal_phase = _terminal_phase_for_run(repo, run_id)
if terminal_phase not in BLOCKING_PREDECESSOR_PHASES:
raise RetrySubmissionError("Alleen een terminal geblokkeerde of mislukte uitvoering kan opnieuw worden uitgevoerd.")
Expand Down
10 changes: 8 additions & 2 deletions tools/engineering/prompt_history.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,11 +339,13 @@ def prompt_history(
COALESCE(submission.engineering_action_id, runs.engineering_action_id),
runs.execution_constraint_version, submission.submission_id,
submission.contract_version, submission.execution_context_version,
submission.execution_context_snapshot
submission.execution_context_snapshot, dismissal.terminal_state,
dismissal.handling_state, dismissal.dismissed_at, dismissal.dismissed_by
FROM prompt_execution_history AS history
LEFT JOIN execution_runs AS runs ON runs.run_id = history.run_id
LEFT JOIN execution_submission_links AS submission_link ON submission_link.run_id = history.run_id
LEFT JOIN execution_submissions AS submission ON submission.submission_id = submission_link.submission_id
LEFT JOIN execution_dismissals AS dismissal ON dismissal.run_id = history.run_id
ORDER BY history.executed_at DESC, history.run_id DESC
LIMIT ?
""",
Expand Down Expand Up @@ -379,6 +381,10 @@ def prompt_history(
"producer_submission_contract_version": row[23],
"execution_context_version": row[24],
"execution_context": json.loads(row[25]) if isinstance(row[25], str) else None,
"dismissed": row[26] is not None,
"handling_state": row[27] or "OPEN",
"dismissed_at": row[28],
"dismissed_by": row[29],
}
for row in rows
]
Expand All @@ -401,7 +407,7 @@ def prompt_history(
record["retry_timestamp"] = child.get("retry_timestamp") if child else record["retry_timestamp"]
record["queued_retry_child"] = bool(child and child.get("status") == "QUEUED")
record["active_retry_child"] = bool(child and child.get("status") == "ACTIVE")
record["can_retry"] = record.get("status") in {"BLOCKED", "FAILED"} and child is None
record["can_retry"] = record.get("status") in {"BLOCKED", "FAILED"} and child is None and not record["dismissed"]
chain = [record["run_id"]]
cursor = record
while cursor.get("retry_of") and cursor["retry_of"] not in chain:
Expand Down
Loading