fix(ops): format list fields as JSON arrays, filter out placeholder strings, and update prompt template rules
This commit is contained in:
parent
1fbe2a746d
commit
0ac85f8b92
|
|
@ -23,3 +23,8 @@ TEST_ESEGUITI:
|
|||
BLOCCO_DATI: si | no
|
||||
NOTE:
|
||||
- <nota>
|
||||
|
||||
REGOLE RIGIDE PER LE LISTE (ABSORBED_LEGACY_FRAGMENTS, OPEN_LEGACY_FRAGMENTS, DATES_USED, TEST_ESEGUITI, NOTE):
|
||||
- Ogni elemento della lista deve iniziare con '- '.
|
||||
- Quando una lista non ha elementi: lasciare soltanto l'intestazione (es. OPEN_LEGACY_FRAGMENTS:) e non inserire alcuna riga con trattino.
|
||||
- E VIETATO tassativamente scrivere 'none', 'nessuno', 'nessuna', 'n/a' o 'non applicabile'.
|
||||
|
|
|
|||
|
|
@ -4,6 +4,39 @@ import json
|
|||
import re
|
||||
import argparse
|
||||
|
||||
PLACEHOLDERS = {"none", "nessuno", "nessuna", "n/a", "non applicabile", "null"}
|
||||
|
||||
def clean_list_item(item: str) -> str:
|
||||
item = item.strip()
|
||||
if item.startswith("- "):
|
||||
item = item[2:].strip()
|
||||
elif item.startswith("-"):
|
||||
item = item[1:].strip()
|
||||
return item
|
||||
|
||||
def is_placeholder(item: str) -> bool:
|
||||
clean = clean_list_item(item).lower()
|
||||
return clean in PLACEHOLDERS or not clean
|
||||
|
||||
def parse_list_field(val) -> list:
|
||||
if val is None:
|
||||
return []
|
||||
items = []
|
||||
if isinstance(val, list):
|
||||
for el in val:
|
||||
s = str(el).strip()
|
||||
if not is_placeholder(s):
|
||||
items.append(clean_list_item(s))
|
||||
elif isinstance(val, str):
|
||||
lines = val.strip().splitlines()
|
||||
for line in lines:
|
||||
s = line.strip()
|
||||
if not s:
|
||||
continue
|
||||
if not is_placeholder(s):
|
||||
items.append(clean_list_item(s))
|
||||
return items
|
||||
|
||||
def parse_output(text: str) -> dict:
|
||||
fields = {
|
||||
"task_id": None,
|
||||
|
|
@ -13,11 +46,11 @@ def parse_output(text: str) -> dict:
|
|||
"commit": None,
|
||||
"consolidated_unit_id": None,
|
||||
"blocco_dati": None,
|
||||
"dates_used": None,
|
||||
"test_eseguiti": None,
|
||||
"note": None,
|
||||
"absorbed_legacy_fragments": None,
|
||||
"open_legacy_fragments": None,
|
||||
"dates_used": [],
|
||||
"test_eseguiti": [],
|
||||
"note": [],
|
||||
"absorbed_legacy_fragments": [],
|
||||
"open_legacy_fragments": [],
|
||||
"raw_text": text
|
||||
}
|
||||
|
||||
|
|
@ -27,33 +60,71 @@ def parse_output(text: str) -> dict:
|
|||
data = json.loads(json_match.group(0))
|
||||
if isinstance(data, dict):
|
||||
source_dict = data.get("parsed", data)
|
||||
for k in fields:
|
||||
if k in source_dict and source_dict[k] is not None:
|
||||
fields[k] = source_dict[k]
|
||||
if isinstance(source_dict, dict):
|
||||
for k in fields:
|
||||
if k in ["raw_text"]:
|
||||
continue
|
||||
if k in ["dates_used", "test_eseguiti", "note", "absorbed_legacy_fragments", "open_legacy_fragments"]:
|
||||
if k in source_dict and source_dict[k] is not None:
|
||||
fields[k] = parse_list_field(source_dict[k])
|
||||
else:
|
||||
if k in source_dict and source_dict[k] is not None:
|
||||
fields[k] = str(source_dict[k]).strip()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
patterns = {
|
||||
"task_id": r"(?:TASK_ID|task_id):\s*(.+)",
|
||||
"esito_205": r"(?:ESITO_205|esito_205):\s*(.+)",
|
||||
"repository": r"(?:REPOSITORY|repository):\s*(.+)",
|
||||
"branch": r"(?:BRANCH|branch):\s*(.+)",
|
||||
"commit": r"(?:COMMIT|commit):\s*(.+)",
|
||||
"consolidated_unit_id": r"(?:CONSOLIDATED_UNIT_ID|UNITA_ID|consolidated_unit_id):\s*(.+)",
|
||||
"blocco_dati": r"(?:BLOCCO_DATI|blocco_dati):\s*(.+)",
|
||||
"dates_used": r"(?:DATES_USED|dates_used):\s*(.+)",
|
||||
"test_eseguiti": r"(?:TEST_ESEGUITI|test_eseguiti):\s*(.+)",
|
||||
"note": r"(?:NOTE|note):\s*(.+)",
|
||||
"absorbed_legacy_fragments": r"(?:ABSORBED_LEGACY_FRAGMENTS|absorbed_legacy_fragments):\s*(.+)",
|
||||
"open_legacy_fragments": r"(?:OPEN_LEGACY_FRAGMENTS|open_legacy_fragments):\s*(.+)"
|
||||
HEADER_MAP = {
|
||||
"TASK_ID": "task_id",
|
||||
"ESITO_205": "esito_205",
|
||||
"REPOSITORY": "repository",
|
||||
"BRANCH": "branch",
|
||||
"COMMIT": "commit",
|
||||
"CONSOLIDATED_UNIT_ID": "consolidated_unit_id",
|
||||
"UNITA_ID": "consolidated_unit_id",
|
||||
"BLOCCO_DATI": "blocco_dati",
|
||||
"ABSORBED_LEGACY_FRAGMENTS": "absorbed_legacy_fragments",
|
||||
"OPEN_LEGACY_FRAGMENTS": "open_legacy_fragments",
|
||||
"DATES_USED": "dates_used",
|
||||
"TEST_ESEGUITI": "test_eseguiti",
|
||||
"NOTE": "note",
|
||||
}
|
||||
|
||||
for key, pat in patterns.items():
|
||||
if fields[key] is None:
|
||||
m = re.search(pat, text, re.IGNORECASE)
|
||||
lines = text.splitlines()
|
||||
current_key = None
|
||||
|
||||
for line in lines:
|
||||
stripped = line.strip()
|
||||
if not stripped:
|
||||
continue
|
||||
|
||||
header_match = None
|
||||
for h_name, field_key in HEADER_MAP.items():
|
||||
pattern = rf"^(?:{h_name}|{field_key}):\s*(.*)$"
|
||||
m = re.match(pattern, stripped, re.IGNORECASE)
|
||||
if m:
|
||||
val = m.group(1).strip()
|
||||
fields[key] = val
|
||||
header_match = (field_key, m.group(1).strip())
|
||||
break
|
||||
|
||||
if header_match:
|
||||
field_key, inline_val = header_match
|
||||
current_key = field_key
|
||||
if field_key in ["dates_used", "test_eseguiti", "note", "absorbed_legacy_fragments", "open_legacy_fragments"]:
|
||||
if inline_val and not is_placeholder(inline_val):
|
||||
fields[field_key].append(clean_list_item(inline_val))
|
||||
else:
|
||||
if not fields[field_key] and inline_val:
|
||||
fields[field_key] = inline_val
|
||||
elif current_key and current_key in ["dates_used", "test_eseguiti", "note", "absorbed_legacy_fragments", "open_legacy_fragments"]:
|
||||
if not is_placeholder(stripped):
|
||||
fields[current_key].append(clean_list_item(stripped))
|
||||
|
||||
for k in ["dates_used", "test_eseguiti", "note", "absorbed_legacy_fragments", "open_legacy_fragments"]:
|
||||
cleaned = []
|
||||
for el in fields[k]:
|
||||
c = clean_list_item(str(el))
|
||||
if c and not is_placeholder(c) and c not in cleaned:
|
||||
cleaned.append(c)
|
||||
fields[k] = cleaned
|
||||
|
||||
return fields
|
||||
|
||||
|
|
@ -81,9 +152,6 @@ def validate_fields(fields: dict, expected_repo: str = None, expected_branch: st
|
|||
"esito_205",
|
||||
"consolidated_unit_id",
|
||||
"blocco_dati",
|
||||
"dates_used",
|
||||
"test_eseguiti",
|
||||
"note",
|
||||
]
|
||||
|
||||
for key in mandatory_single_fields:
|
||||
|
|
@ -91,12 +159,21 @@ def validate_fields(fields: dict, expected_repo: str = None, expected_branch: st
|
|||
if val is None or (isinstance(val, str) and not val.strip()):
|
||||
missing.append(key)
|
||||
|
||||
abs_frag = fields.get("absorbed_legacy_fragments")
|
||||
open_frag = fields.get("open_legacy_fragments")
|
||||
has_abs = abs_frag is not None and (not isinstance(abs_frag, str) or bool(str(abs_frag).strip()))
|
||||
has_open = open_frag is not None and (not isinstance(open_frag, str) or bool(str(open_frag).strip()))
|
||||
mandatory_list_fields = [
|
||||
"dates_used",
|
||||
"test_eseguiti",
|
||||
"note",
|
||||
]
|
||||
|
||||
if not (has_abs or has_open):
|
||||
for key in mandatory_list_fields:
|
||||
val = fields.get(key)
|
||||
if not isinstance(val, list) or len(val) == 0:
|
||||
missing.append(key)
|
||||
|
||||
abs_frag = fields.get("absorbed_legacy_fragments") or []
|
||||
open_frag = fields.get("open_legacy_fragments") or []
|
||||
|
||||
if len(abs_frag) == 0 and len(open_frag) == 0:
|
||||
missing.append("absorbed_legacy_fragments|open_legacy_fragments")
|
||||
|
||||
dedup_missing = []
|
||||
|
|
|
|||
|
|
@ -12,9 +12,7 @@ REAL_COMMIT="$(git -C "$REPO_DIR" rev-parse HEAD)"
|
|||
|
||||
echo "=== ESECUZIONE TEST AUTOMATICI WRAPPER E PARSER AGY 1.1.11 ==="
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# Test 1: Output Jetski negato -> wrapper fallisce
|
||||
# -------------------------------------------------------------
|
||||
echo -n "Test 1: Output Jetski negato -> "
|
||||
TEST_BIN_DIR="$(mktemp -d)"
|
||||
cat << 'EOF' > "$TEST_BIN_DIR/agy-ultra"
|
||||
|
|
@ -37,9 +35,7 @@ else
|
|||
exit 1
|
||||
fi
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# Test 2: Output vuoto -> wrapper fallisce
|
||||
# -------------------------------------------------------------
|
||||
echo -n "Test 2: Output vuoto -> "
|
||||
TEST_BIN_DIR="$(mktemp -d)"
|
||||
cat << 'EOF' > "$TEST_BIN_DIR/agy-ultra"
|
||||
|
|
@ -62,20 +58,22 @@ else
|
|||
exit 1
|
||||
fi
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# Test 3: task_id null -> parser fallisce
|
||||
# -------------------------------------------------------------
|
||||
echo -n "Test 3: task_id null -> "
|
||||
INCOMPLETE_REPORT="ESITO_205: riuscito
|
||||
REPOSITORY: ${REAL_REPO}
|
||||
BRANCH: ${REAL_BRANCH}
|
||||
COMMIT: ${REAL_COMMIT}
|
||||
CONSOLIDATED_UNIT_ID: 1545
|
||||
DATES_USED: 2026-08-10
|
||||
TEST_ESEGUITI: ./vendor/bin/pest
|
||||
DATES_USED:
|
||||
- 2026-08-10
|
||||
TEST_ESEGUITI:
|
||||
- pest
|
||||
BLOCCO_DATI: no
|
||||
NOTE: Incompleto
|
||||
ABSORBED_LEGACY_FRAGMENTS: id_cond=12"
|
||||
NOTE:
|
||||
- Incompleto
|
||||
ABSORBED_LEGACY_FRAGMENTS:
|
||||
- id_cond=12"
|
||||
|
||||
set +e
|
||||
TEST3_OUT="$(python3 "$PARSER" --expected-repo "$REAL_REPO" --expected-branch "$REAL_BRANCH" --expected-commit "$REAL_COMMIT" <<< "$INCOMPLETE_REPORT" 2>&1)"
|
||||
|
|
@ -90,61 +88,99 @@ else
|
|||
exit 1
|
||||
fi
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# Test 4: Report completo -> passa
|
||||
# -------------------------------------------------------------
|
||||
echo -n "Test 4: Report completo -> "
|
||||
COMPLETE_REPORT="TASK_ID: CT-2026-08-10-TEST-001
|
||||
# Test 4: '- nessuno' viene scartato e restituisce lista vuota []
|
||||
echo -n "Test 4: '- nessuno' viene scartato -> "
|
||||
NONE_REPORT="TASK_ID: CT-2026-08-10-TEST-NONE
|
||||
ESITO_205: riuscito
|
||||
REPOSITORY: ${REAL_REPO}
|
||||
BRANCH: ${REAL_BRANCH}
|
||||
COMMIT: ${REAL_COMMIT}
|
||||
CONSOLIDATED_UNIT_ID: 1545
|
||||
DATES_USED: 2026-08-10
|
||||
TEST_ESEGUITI: ./vendor/bin/pest
|
||||
ABSORBED_LEGACY_FRAGMENTS:
|
||||
- artisan-ultra-real-24825cbb
|
||||
OPEN_LEGACY_FRAGMENTS:
|
||||
- nessuno
|
||||
DATES_USED:
|
||||
- 2026-08-09
|
||||
TEST_ESEGUITI:
|
||||
- test
|
||||
BLOCCO_DATI: no
|
||||
NOTE: Task completato correttamente
|
||||
ABSORBED_LEGACY_FRAGMENTS: id_cond=12"
|
||||
NOTE:
|
||||
- ARTISAN_ULTRA_OK"
|
||||
|
||||
set +e
|
||||
TEST4_OUT="$(python3 "$PARSER" --expected-repo "$REAL_REPO" --expected-branch "$REAL_BRANCH" --expected-commit "$REAL_COMMIT" <<< "$COMPLETE_REPORT" 2>&1)"
|
||||
TEST4_OUT="$(python3 "$PARSER" --expected-repo "$REAL_REPO" --expected-branch "$REAL_BRANCH" --expected-commit "$REAL_COMMIT" <<< "$NONE_REPORT" 2>&1)"
|
||||
TEST4_EXIT=$?
|
||||
set -e
|
||||
|
||||
if [ $TEST4_EXIT -eq 0 ] && [[ "$TEST4_OUT" == *'"ok": true'* ]]; then
|
||||
if [ $TEST4_EXIT -eq 0 ] && [[ "$TEST4_OUT" == *'"open_legacy_fragments": []'* ]]; then
|
||||
echo "PASS (Exit Code: $TEST4_EXIT)"
|
||||
else
|
||||
echo "FAIL (Expected exit code 0 with ok: true)"
|
||||
echo "FAIL (Expected open_legacy_fragments to be empty array [])"
|
||||
echo "$TEST4_OUT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# Test 5: Git diverso dal reale -> fallisce
|
||||
# -------------------------------------------------------------
|
||||
echo -n "Test 5: Git diverso dal reale -> "
|
||||
# Test 5: Liste restituite come array e smoke completo produce ok=true
|
||||
echo -n "Test 5: Smoke completo con liste array -> "
|
||||
COMPLETE_REPORT="TASK_ID: task-348c024293
|
||||
ESITO_205: riuscito
|
||||
REPOSITORY: ${REAL_REPO}
|
||||
BRANCH: ${REAL_BRANCH}
|
||||
COMMIT: ${REAL_COMMIT}
|
||||
CONSOLIDATED_UNIT_ID: SMOKE-24825CBB
|
||||
ABSORBED_LEGACY_FRAGMENTS:
|
||||
- artisan-ultra-real-24825cbb
|
||||
OPEN_LEGACY_FRAGMENTS:
|
||||
DATES_USED:
|
||||
- 2026-08-09
|
||||
TEST_ESEGUITI:
|
||||
- lettura AGENTS.md e parser rigoroso
|
||||
BLOCCO_DATI: no
|
||||
NOTE:
|
||||
- ARTISAN_ULTRA_24825CBB_REAL_OK"
|
||||
|
||||
set +e
|
||||
TEST5_OUT="$(python3 "$PARSER" --expected-repo "$REAL_REPO" --expected-branch "$REAL_BRANCH" --expected-commit "$REAL_COMMIT" <<< "$COMPLETE_REPORT" 2>&1)"
|
||||
TEST5_EXIT=$?
|
||||
set -e
|
||||
|
||||
if [ $TEST5_EXIT -eq 0 ] && [[ "$TEST5_OUT" == *'"ok": true'* ]] && [[ "$TEST5_OUT" == *'"absorbed_legacy_fragments": ['* ]]; then
|
||||
echo "PASS (Exit Code: $TEST5_EXIT)"
|
||||
else
|
||||
echo "FAIL (Expected ok: true with array fields)"
|
||||
echo "$TEST5_OUT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Test 6: Git diverso dal reale -> fallisce
|
||||
echo -n "Test 6: Git diverso dal reale -> "
|
||||
MISMATCH_REPORT="TASK_ID: CT-2026-08-10-TEST-001
|
||||
ESITO_205: riuscito
|
||||
REPOSITORY: ssh://git@wrong-repo.git
|
||||
BRANCH: wrong-branch
|
||||
COMMIT: deadbeef1234
|
||||
CONSOLIDATED_UNIT_ID: 1545
|
||||
DATES_USED: 2026-08-10
|
||||
TEST_ESEGUITI: ./vendor/bin/pest
|
||||
DATES_USED:
|
||||
- 2026-08-10
|
||||
TEST_ESEGUITI:
|
||||
- pest
|
||||
BLOCCO_DATI: no
|
||||
NOTE: Mismatch test
|
||||
ABSORBED_LEGACY_FRAGMENTS: id_cond=12"
|
||||
NOTE:
|
||||
- Mismatch test
|
||||
ABSORBED_LEGACY_FRAGMENTS:
|
||||
- id_cond=12"
|
||||
|
||||
set +e
|
||||
TEST5_OUT="$(python3 "$PARSER" --expected-repo "$REAL_REPO" --expected-branch "$REAL_BRANCH" --expected-commit "$REAL_COMMIT" <<< "$MISMATCH_REPORT" 2>&1)"
|
||||
TEST5_EXIT=$?
|
||||
TEST6_OUT="$(python3 "$PARSER" --expected-repo "$REAL_REPO" --expected-branch "$REAL_BRANCH" --expected-commit "$REAL_COMMIT" <<< "$MISMATCH_REPORT" 2>&1)"
|
||||
TEST6_EXIT=$?
|
||||
set -e
|
||||
|
||||
if [ $TEST5_EXIT -eq 1 ] && [[ "$TEST5_OUT" == *'"ok": false'* ]] && [[ "$TEST5_OUT" == *'"repository"'* ]]; then
|
||||
echo "PASS (Exit Code: $TEST5_EXIT)"
|
||||
if [ $TEST6_EXIT -eq 1 ] && [[ "$TEST6_OUT" == *'"ok": false'* ]] && [[ "$TEST6_OUT" == *'"repository"'* ]]; then
|
||||
echo "PASS (Exit Code: $TEST6_EXIT)"
|
||||
else
|
||||
echo "FAIL (Expected exit code 1 with git mismatch)"
|
||||
echo "$TEST5_OUT"
|
||||
echo "$TEST6_OUT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user