kintex/docs/deliverables/제안서/_gen/_qa_rtm.py
zio ba90b54d81 feat(proposal): G2B-standard 7-chapter proposal deck (97 slides, QA-approved)
- Restructure to KONEPS (조달청 협상계약 별지5호) standard TOC: I general / II strategy-methodology / III tech-function / IV performance-quality / V PM / VI support / VII misc
- 9 new slides: staffing M/M, quantitative eval, standard framework, PM methodology, handover/training, SM/SLA, incident/BCP, managerial security, subcontracting
- Scoring alignment updated to tech 90 (70 qual + 20 quant) / price 10
- Nanobanana win-theme dual placement (II applied-tech + III function)
- Appendix D screen gallery (19 Stitch drafts) with AI-draft disclosure
- QA PASS: RTM 142/142 (3 fixes: F-008/F-010/F-026), no secrets, honesty labels verified
- Preserve rebuild toolchain + source docs in deliverables/제안서/_gen (16 files)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 00:44:44 +09:00

65 lines
2.7 KiB
Python

# -*- coding: utf-8 -*-
import re, json, io, sys
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
slides = json.load(open(r"C:\GUARDiA\workspace\kintex\_workspace\proposal\_qa_slides.json", encoding="utf-8"))
# Full REQ universe
UNIV = {}
for pfx, cnt in [("F", 81), ("A", 20), ("N", 21), ("S", 20)]:
for i in range(1, cnt + 1):
UNIV[f"{pfx}-{i:03d}"] = None # slide where covered
# Parse each text line for badge tokens with prefix-context + range + continuation.
# Grammar we support in a run:
# REQ-<P>-<n> single
# REQ-<P>-<n>~<m> range (same prefix)
# ...·<P>-<n> new prefix single continuation
# ...·<P>-<n>~<m> new prefix range continuation
# ...·<n> bare number continues LAST prefix (e.g. A-011·012)
# ...·<n>~<m> bare range continues last prefix (e.g. 067~069)
cover = {} # req -> list of slides
def add(pfx, a, b, sn):
for i in range(a, b + 1):
key = f"{pfx}-{i:03d}"
cover.setdefault(key, set()).add(sn)
# token: optional prefix letter, number, optional ~ number
tok = re.compile(r"(?:REQ-)?(?:([FANS])-)?(\d{2,3})(?:\s*~\s*(?:[FANS]-)?(\d{2,3}))?")
for s in slides:
sn = s["n"]
for t in s["texts"]:
# only scan segments that look like badge context (contain REQ- or letter-number dot chains)
for m in re.finditer(r"REQ-[FANS]-\d{2,3}(?:\s*~\s*\d{2,3})?(?:[·,\s]+(?:[FANS]-)?\d{2,3}(?:\s*~\s*\d{2,3})?)*", t):
seg = m.group(0)
last_pfx = None
for mm in tok.finditer(seg):
p, a, b = mm.group(1), mm.group(2), mm.group(3)
if p:
last_pfx = p
if last_pfx is None:
continue
ai = int(a)
bi = int(b) if b else ai
# sanity: within universe range
add(last_pfx, ai, bi, sn)
missing = sorted(k for k in UNIV if k not in cover)
print("=== RANGE-EXPANDED BADGE COVERAGE ===")
print("COVERED (badge):", len(cover), "/ 142")
print("NOT badge-covered (", len(missing), "):", ", ".join(missing))
# priority 7
prio = ["F-008", "F-010", "F-026", "F-032", "A-003", "A-005", "A-008"]
print("\n=== PRIORITY 7 BADGE STATUS ===")
for r in prio:
print(f"{r}: badge slides = {sorted(cover.get(r, []))}")
# dump per-covered for the previously-flagged 18
flagged = ["F-005","F-008","F-010","F-026","F-032","F-034","F-036","F-038","F-039","F-054","F-074","F-075","F-076","A-003","A-005","A-008","S-005","S-006"]
print("\n=== PREVIOUSLY-FLAGGED 18: badge coverage after range expansion ===")
for r in flagged:
sl = sorted(cover.get(r, []))
print(f"{r}: {'BADGE ' + str(sl) if sl else 'NO BADGE'}")