fix(agent): persist no-write learning receipts
All checks were successful
CD Pipeline / workflow-shape (push) Successful in 1s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 1m19s
CD Pipeline / build-and-deploy (push) Successful in 9m4s
CD Pipeline / post-deploy-checks (push) Successful in 2m0s
All checks were successful
CD Pipeline / workflow-shape (push) Successful in 1s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 1m19s
CD Pipeline / build-and-deploy (push) Successful in 9m4s
CD Pipeline / post-deploy-checks (push) Successful in 2m0s
This commit is contained in:
@@ -3264,7 +3264,7 @@ jobs:
|
|||||||
}
|
}
|
||||||
echo "executor_boundary_stage=live_socket_boundary_verified"
|
echo "executor_boundary_stage=live_socket_boundary_verified"
|
||||||
|
|
||||||
read_workload_db_identity() {
|
read_workload_db_identity_once() {
|
||||||
workload="$1"
|
workload="$1"
|
||||||
container="$2"
|
container="$2"
|
||||||
representative_probe_count="$3"
|
representative_probe_count="$3"
|
||||||
@@ -3412,6 +3412,23 @@ jobs:
|
|||||||
asyncio.run(main())
|
asyncio.run(main())
|
||||||
PY
|
PY
|
||||||
}
|
}
|
||||||
|
read_workload_db_identity() {
|
||||||
|
workload="$1"
|
||||||
|
attempt=1
|
||||||
|
while [ "$attempt" -le 3 ]; do
|
||||||
|
if identity_output=$(read_workload_db_identity_once "$@"); then
|
||||||
|
printf '%s\n' "$identity_output"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
echo "workload_db_identity_exec_retry=$attempt/3;workload=$workload" >&2
|
||||||
|
if [ "$attempt" -lt 3 ]; then
|
||||||
|
sleep $((attempt * 3))
|
||||||
|
fi
|
||||||
|
attempt=$((attempt + 1))
|
||||||
|
done
|
||||||
|
echo "workload_db_identity_exec_exhausted=3;workload=$workload" >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
json_field() {
|
json_field() {
|
||||||
field="$1"
|
field="$1"
|
||||||
python3 -c \
|
python3 -c \
|
||||||
|
|||||||
@@ -153,6 +153,16 @@ _ENUM_FALLBACKS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _knowledge_enum_db_label(value):
|
||||||
|
"""Match the mixed-case labels in the deployed PostgreSQL enums."""
|
||||||
|
|
||||||
|
if isinstance(value, EntryStatus) and value is EntryStatus.PUBLISHED:
|
||||||
|
return value.value
|
||||||
|
if isinstance(value, EntryType | EntrySource | EntryStatus):
|
||||||
|
return value.name
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
def _enum_member(value, enum_cls):
|
def _enum_member(value, enum_cls):
|
||||||
if value is None:
|
if value is None:
|
||||||
return _ENUM_FALLBACKS.get(enum_cls)
|
return _ENUM_FALLBACKS.get(enum_cls)
|
||||||
@@ -287,11 +297,11 @@ class KnowledgeDBRepository:
|
|||||||
values = {
|
values = {
|
||||||
"title": data.title,
|
"title": data.title,
|
||||||
"content": data.content,
|
"content": data.content,
|
||||||
"entry_type": data.entry_type.value if hasattr(data.entry_type, "value") else data.entry_type,
|
"entry_type": _knowledge_enum_db_label(data.entry_type),
|
||||||
"category": data.category,
|
"category": data.category,
|
||||||
"tags": data.tags,
|
"tags": data.tags,
|
||||||
"source": data.source.value if hasattr(data.source, "value") else data.source,
|
"source": _knowledge_enum_db_label(data.source),
|
||||||
"status": data.status.value if hasattr(data.status, "value") else data.status,
|
"status": _knowledge_enum_db_label(data.status),
|
||||||
"related_incident_id": data.related_incident_id,
|
"related_incident_id": data.related_incident_id,
|
||||||
"related_playbook_id": data.related_playbook_id,
|
"related_playbook_id": data.related_playbook_id,
|
||||||
"related_approval_id": data.related_approval_id,
|
"related_approval_id": data.related_approval_id,
|
||||||
@@ -313,7 +323,7 @@ class KnowledgeDBRepository:
|
|||||||
"title": data.title,
|
"title": data.title,
|
||||||
"content": data.content,
|
"content": data.content,
|
||||||
"tags": data.tags,
|
"tags": data.tags,
|
||||||
"status": data.status.value if hasattr(data.status, "value") else data.status,
|
"status": _knowledge_enum_db_label(data.status),
|
||||||
"related_approval_id": data.related_approval_id,
|
"related_approval_id": data.related_approval_id,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -339,12 +349,12 @@ class KnowledgeDBRepository:
|
|||||||
record = KnowledgeEntryRecord(
|
record = KnowledgeEntryRecord(
|
||||||
title=data.title,
|
title=data.title,
|
||||||
content=data.content,
|
content=data.content,
|
||||||
entry_type=data.entry_type,
|
entry_type=_knowledge_enum_db_label(data.entry_type),
|
||||||
category=data.category,
|
category=data.category,
|
||||||
tags=data.tags,
|
tags=data.tags,
|
||||||
source=data.source,
|
source=_knowledge_enum_db_label(data.source),
|
||||||
# 2026-04-04 ogt: Phase 25 P1 — 支援指定 status(ANTI_PATTERN 直接 PUBLISHED)
|
# 2026-04-04 ogt: Phase 25 P1 — 支援指定 status(ANTI_PATTERN 直接 PUBLISHED)
|
||||||
status=data.status,
|
status=_knowledge_enum_db_label(data.status),
|
||||||
related_incident_id=data.related_incident_id,
|
related_incident_id=data.related_incident_id,
|
||||||
related_playbook_id=data.related_playbook_id,
|
related_playbook_id=data.related_playbook_id,
|
||||||
related_approval_id=data.related_approval_id,
|
related_approval_id=data.related_approval_id,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ from src.repositories.knowledge_repository import (
|
|||||||
_ASSET_TAXONOMY_KEYS,
|
_ASSET_TAXONOMY_KEYS,
|
||||||
KnowledgeDBRepository,
|
KnowledgeDBRepository,
|
||||||
_enum_text,
|
_enum_text,
|
||||||
|
_knowledge_enum_db_label,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -263,3 +264,12 @@ def test_enum_text_helper_casts_status_to_lowercase_text() -> None:
|
|||||||
|
|
||||||
assert "lower(cast(knowledge_entries.status as varchar))" in compiled
|
assert "lower(cast(knowledge_entries.status as varchar))" in compiled
|
||||||
assert "archived" in compiled
|
assert "archived" in compiled
|
||||||
|
|
||||||
|
|
||||||
|
def test_knowledge_enum_db_labels_match_deployed_postgresql_contract() -> None:
|
||||||
|
assert _knowledge_enum_db_label(EntryType.INCIDENT_CASE) == "INCIDENT_CASE"
|
||||||
|
assert _knowledge_enum_db_label(EntryType.ANTI_PATTERN) == "ANTI_PATTERN"
|
||||||
|
assert _knowledge_enum_db_label(EntrySource.AI_EXTRACTED) == "AI_EXTRACTED"
|
||||||
|
assert _knowledge_enum_db_label(EntrySource.HUMAN) == "HUMAN"
|
||||||
|
assert _knowledge_enum_db_label(EntryStatus.DRAFT) == "DRAFT"
|
||||||
|
assert _knowledge_enum_db_label(EntryStatus.PUBLISHED) == "published"
|
||||||
|
|||||||
@@ -264,6 +264,10 @@ def test_cd_prunes_and_verifies_api_executor_boundary_in_production() -> None:
|
|||||||
assert "read_workload_db_identity awoooi-api api 1 8" in workflow
|
assert "read_workload_db_identity awoooi-api api 1 8" in workflow
|
||||||
assert "read_workload_db_identity awoooi-worker worker 1 5" in workflow
|
assert "read_workload_db_identity awoooi-worker worker 1 5" in workflow
|
||||||
assert "awoooi-ansible-executor-broker broker 1 2" in workflow
|
assert "awoooi-ansible-executor-broker broker 1 2" in workflow
|
||||||
|
assert "read_workload_db_identity_once" in workflow
|
||||||
|
assert 'while [ "$attempt" -le 3 ]' in workflow
|
||||||
|
assert "workload_db_identity_exec_retry=$attempt/3" in workflow
|
||||||
|
assert "workload_db_identity_exec_exhausted=3" in workflow
|
||||||
assert "AWOOOI_DB_REPRESENTATIVE_PROBE_COUNT" in workflow
|
assert "AWOOOI_DB_REPRESENTATIVE_PROBE_COUNT" in workflow
|
||||||
assert "AWOOOI_DB_REQUIRED_CONNECTION_BUDGET" in workflow
|
assert "AWOOOI_DB_REQUIRED_CONNECTION_BUDGET" in workflow
|
||||||
assert "api_http_concurrency_probe_passed" in workflow
|
assert "api_http_concurrency_probe_passed" in workflow
|
||||||
|
|||||||
Reference in New Issue
Block a user