now i want to update the remaining investigation r...

Créé le : 11 juillet 2026

Répondu en utilisant GPT-5.6 Thinking par Chat01

Question

Draft_Investigation_Report_final.docx

now i want to update the remaining investigation report review points, update the review poinst properly. Also, why-why to be update and in why why root cause is found then too we are doing investigation review point in depth so write like that before this. Also, Gemba walk to write in visually appealing way. nullify that no impact. and provide final report.

Réflexion

{"uri":"skills://docx/skill.md","start_line":1,"num_lines":250}

bash -lc cat /home/oai/skills/docx/SKILL.md

bash -lc cat /home/oai/skills/docx/tasks/create_edit.md | sed -n '1,260p'

Evaluating report structure and content review

I need to decide what’s missing in the investigation report. It looks like activities 5, 6, and 8 may need review. I’ll inspect the document’s structure and content comprehensively, potentially using a tool to extract text, tables, and image info to ensure full review and accuracy in the final report.

bash -lc python - <<'PY' from docx import Document p='/mnt/data/Draft_Investigation_Report_final.docx' doc=Document(p) print('paragraphs', len(doc.paragraphs), 'tables', len(doc.tables), 'sections', len(doc.sections)) for i,p in enumerate(doc.paragraphs[:120]): t=p.text.strip().replace('\n',' | ') if t: print(f'P{i}: {t[:220]}') print('---TABLES---') for ti,t in enumerate(doc.tables): print('TABLE',ti,'rows',len(t.rows),'cols',len(t.columns)) for r in t.rows[:4]: print(' | '.join(c.text.strip().replace('\n',' / ')[:100] for c in r.cells)) print() PY

Inspecting paragraphs and document relationships

I need to look closely at all the paragraphs near the tables and examine how everything in the document is connected. I’m also considering that the original formatting might be off in some places, so I’ll check by rendering the document as it originally appears to confirm.

bash -lc rm -rf /mnt/data/orig_render && python /home/oai/skills/docx/render_docx.py /mnt/data/Draft_Investigation_Report_final.docx --output_dir /mnt/data/orig_render --emit_pdf

Counting pages and inspecting each one

I need to carefully check every page in the document. I’ll also keep track of the page count to make sure nothing is missing or overlooked. This way, I can conduct a thorough review while ensuring all parts of the document are accounted for.

bash -lc ls -1 /mnt/data/orig_render/page-*.png | wc -l && ls -lh /mnt/data/orig_render | head

Creating a contact sheet for quick inspection

I’m thinking of using a contact sheet to inspect the images faster before going into the detailed review. Maybe I can create it with Python or ImageMagick using a montage. I’ll start with an overview, then dive deeper into individual images if needed, as skill recommends inspecting at 100%.

bash -lc python - <<'PY' from PIL import Image, ImageOps, ImageDraw import glob, os, math files=sorted(glob.glob('/mnt/data/orig_render/page-.png'), key=lambda x:int(os.path.basename(x).split('-')[1].split('.')[0])) thumbs=[] for f in files: im=Image.open(f).convert('RGB') im.thumbnail((320,450)) canvas=Image.new('RGB',(340,490),'white') canvas.paste(im,((340-im.width)//2,20)) d=ImageDraw.Draw(canvas); d.text((10,5),os.path.basename(f),fill='black') thumbs.append(canvas) cols=4; rows=math.ceil(len(thumbs)/cols) out=Image.new('RGB',(cols340,rows*490),(220,220,220)) for i,im in enumerate(thumbs): out.paste(im,((i%cols)*340,(i//cols)*490)) out.save('/mnt/data/orig_render/contact.png') PY

Editing the investigation report and ensuring update

I need to edit the document while keeping the template and images intact. The goal is to add the missing review points without disturbing the existing layout. I’ll update activities 5, 6, and 8, and clarify how the 5-Why analysis led to a root cause hypothesis, ensuring transitions are clear before the Investigation Plan.

Updating the Why-Why analysis for root cause clarity

I need to update the Why-Why analysis, filling in the final "Why" to make it more robust. The problem started with good cartons being physically diverted, possibly due to issues with the checkweigher's reject mechanism. I need to ensure technical consistency and clarify the actual false rejection mechanism, adjusting the root cause sentence for clarity.Clarifying root cause and possible actions for investigation report

I need to separate the direct cause of the issue from the contributing factors. The root cause seems to be the lack of buffer space, which is aggravated by tilted cartons at the T&T infeed. For corrective actions, I can propose changes, but the user didn’t explicitly request those. Let's focus on reviewing the remaining investigation points, including any actions needed.

Proposing improvements and actions without overcommitting

To avoid inventing responses, it’s better to maintain the known target completion date (TCD) as "before next commercial batch" or something similar. For proposedClarifying statements and confirming findings

The affected cartons were segregated, inspected, and re-passed, preventing any incomplete carton release. Regarding traceability, all cartons were controlled and reprocessed. I should avoid asserting reconciliation unless confirmed in documents. The product was properly stored and tested; equipment functions passed. No adverse impact on product quality or patient safety was identified.

Clarifying audit document details

It's better to restate: "The investigation concluded no adverse impact," supported by evidence. Regarding the audit, the document shows inconsistency in the B1 history. The root cause review should cite the correct sensor (1100008464). I need to adjust the timeline language to say, "availableUpdating investigation findings and plan

I noticed activity numbering errors that need fixing: the first settings should be _01, not _02, and others as well. The investigation plan seems to have a blank first column, possibly formatting. I also need to revise wording to make objectives more neutral, like "Review of qualification and preventive-maintenance status." Will update.

Adding BPR and SOP review sections

I need to add a detailed review of activity 5 for BPR, covering batch 0360093A and all checks done, including cartonator and checkweigher challenges, process checks, and documentation of weight set values. I'll also mention that BPR compliance wasn't a direct cause but the buffer verification might be missing. For activity 6, it shows SOP gaps in interface clearance and jam handling which may have contributed to the issue.Clarifying sensor functionality and rejection mechanism

I need to clarify the role of the rejection confirmation sensor. Instead of saying it “appropriately rejects cartons,” it should be rephrased as confirming rejection. Also, the idea of the pneumatic rejector “rejecting good cartons” due to backup needs more precision:

  1. Under normal flow, reject timing is aligned with the carton.
  2. During a backup, the sequence is disturbed, leading to multiple cartons occupying the rejection zone.
  3. An adjacent acceptable carton can be pushed into the reject bin, blocking the sensor and causing ERROR-17.
  4. This isn’t a load cell misclassification, but rather physical interference due to accumulation.

Clear explanation and visual presentation

I shouldn't overstate control logic unless it’s verified by actual testing. Instead, I'll say something like "could cause" and "event recreation confirmed." The final root cause should be confirmed by recreating the event. It's good that the team alreadyUpdating existing content with patching strategy

I plan to patch the current content, adding missing tables and adjusting paragraphs as needed. Python-docx will help with text modification, but I need to identify the body order first. Since paragraphs and tables are mixed, I'll use iter_block_items to preserve order. Extracting block types and indexes will make it easier to handle sections, and rewriting or inserting headings can follow. Rebuilding the document from scratch might be too time-consuming, so patching is the better choice. I’ll also list blocks with shortened text and indexes for clarity.

bash -lc python - <<'PY' from docx import Document from docx.table import Table from docx.text.paragraph import Paragraph from docx.oxml.ns import qn p='/mnt/data/Draft_Investigation_Report_final.docx' doc=Document(p) body=doc.element.body pi=ti=0 for bi,child in enumerate(body.iterchildren()): if child.tag==qn('w:p'): par=Paragraph(child, doc) txt=' '.join(par.text.split()) if txt or child.xpath('.//w:drawing') or child.xpath('.//w:pict'): print(f'{bi:03d} P{pi:03d} {txt[:140]}'+(' [IMAGE]' if child.xpath('.//w:drawing') or child.xpath('.//w:pict') else '')) pi+=1 elif child.tag==qn('w:tbl'): tbl=Table(child, doc) first=' | '.join(' '.join(c.text.split()) for c in tbl.rows[0].cells) if tbl.rows else '' print(f'{bi:03d} T{ti:03d} {len(tbl.rows)}x{len(tbl.columns)} {first[:140]}') ti+=1 PY

Updating and redesigning the document

I’m considering redesigning the document. It seems like the why-why section might be better as a visual flow, replacing old tables and images. The Gemba section could also go through a similar transformation, using tables instead of paragraphs but keeping the key images. I could rebuild the document using the original content, patching it afterward, but I need to be mindful of formatting and headers/footers. I’ll also extract and rework all the table text, while making sure the final report has polished grammar and flows professionally.

Preparing final report and content adjustments

I’m thinking of keeping the file citation for the final response, rather than citing web sources—since it’s an artifact. I’ll focus on fixing the document with better formatting, such as normalizing the font and improving grammar and content, like the non-conformity section and event descriptions. I may replace part of the Gemba section with structured content and updated tables but keep the images intact.

bash -lc python - <<'PY' import zipfile, os from PIL import Image p='/mnt/data/Draft_Investigation_Report_final.docx' out='/mnt/data/docx_media' os.makedirs(out,exist_ok=True) with zipfile.ZipFile(p) as z: for n in z.namelist(): if n.startswith('word/media/'): fn=os.path.join(out,os.path.basename(n)); open(fn,'wb').write(z.read(n)) try: im=Image.open(fn) print(os.path.basename(n), im.size, im.mode) except Exception as e: print(os.path.basename(n), 'non-raster', os.path.getsize(fn)) PY

bash -lc python - <<'PY' from PIL import Image,ImageDraw,ImageOps import glob,os,math files=glob.glob('/mnt/data/docx_media/') ims=[] for f in sorted(files): try: im=Image.open(f).convert('RGB') except: continue im.thumbnail((400,260)) c=Image.new('RGB',(420,300),'white'); c.paste(im,((420-im.width)//2,25)) d=ImageDraw.Draw(c); d.text((10,5),os.path.basename(f),fill='black') ims.append(c) cols=3; rows=math.ceil(len(ims)/cols) out=Image.new('RGB',(cols420,rows*300),(220,220,220)) for i,c in enumerate(ims): out.paste(c,((i%cols)*420,(i//cols)*300)) out.save('/mnt/data/docx_media/contact.png') PY

Planning for a polished final report

I’m considering remaking the report from scratch using all the necessary images and template style. The original report isn’t long, so I could create a polished 25-page document with title, tables, headings, and images. I’ll keep the content faithful, tweak the grammar, and include missing review points, while replicating the original header/footer/logo. I'll ensure the conclusions are consistent with existing data and add useful images.Considering page orientation and image layout

I’m thinking about using a landscape page for image1, since the original fits well on the page. That seems good. Now, I should take a closer look at image4 to see if it needs any adjustments or if it aligns well with my layout plan.Planning the final document structure

I need to create the final document, aiming for stable formatting over about 30 pages. I’ll make sure to include all necessary content. I'll recheck the original sections and inspect the page footers. We can likely stick to A4 size with 0.5-inch margins and review the section styles and properties.

bash -lc python - <<'PY' from docx import Document from docx.shared import Inches,Pt p='/mnt/data/Draft_Investigation_Report_final.docx' d=Document(p) s=d.sections[0] print('page',s.page_width.inches,s.page_height.inches,'margins',s.left_margin.inches,s.right_margin.inches,s.top_margin.inches,s.bottom_margin.inches) for name in ['Normal','Title','Heading 1','Heading 2']: st=d.styles[name] print(name, st.font.name, st.font.size.pt if st.font.size else None, st.paragraph_format.space_after.pt if st.paragraph_format.space_after else None) print('header paras', [p.text for p in s.header.paragraphs]) print('footer paras', [p.text for p in s.footer.paragraphs]) print('footer tables',len(s.footer.tables)) for t in s.footer.tables: print([[c.text for c in r.cells] for r in t.rows]) PY

Building the report format with dynamic elements

I need to construct the report with dynamic page numbers, something like "Format No... PAGE/NUMPAGES". It might be a good idea to have a title page with "INVESTIGATION REPORT" and follow it with a table. For style, we can use blue/green accents from the logo while keeping it formal. I'll keep the logo in the header, centered with the title on each page, just like the original. The footer will include dynamic elements too.Selecting relevant images for the final report and impact assessment

The final report can include photos at relevant points, such as process sequence, equipment history, and SAP evidence. I don’t need to include all images; some, like the BPR screenshot, may be unnecessary. I’ll ensure that “No impact” is handled carefully with an impact assessment matrix, including clear conclusions.

Ensuring evidence and certainty for conclusions

I need to confirm evidence for the event during secondary packing, especially that tablets in sealed blisters were exposed. Stability data is satisfactory, and testing passed before and after rectCreating action steps with verification and timelines

I should avoid marking tasks as completed unless confirmed by the source, so it's better not to state it's done. For the preventive actions, I'll list clear steps including buffer installation, verification at different speeds, and SOP revisions. I'll assign responsible teams and establish effective check milestones with specific timelines for post-modification monitoring.

Refining preventive actions and change control

For the report, I should add milestone-based TCD where exact dates aren’t clear, ensuring a complete document. Additionally, I’ll suggest raising and executing change control for buffer installation, including necessary assessments andCreating DOCX report with structure, styles, and content

To construct the report, I need to use Python docx to handle tables, text formatting, margins, and page numbers dynamically. I'll format the document to maintain a balance of space—avoiding excess whitespace—using smaller font sizes and consistent styles. I'll keep the content concise and structured, with clear sections and necessary review points. The report will feature "Why-Why" tables and captured evidence. Starting with deciding on a clean, professional layout, we'll then draft content in code.

Clearly phrasing the problem and identifying root causes

I’m breaking down the problem into precise "Why" questions. The first clarifies why acceptable cartons were divertedClarifying and organizing review findings and visuals

The detailed review confirmed that no single factor, such as settings or actions, was directly responsible for the issue. I’ll update the report to say "following event" instead of a specific date. I’ll create a table summarizing the "Gemba Walk" area, personnel, and timeline. The "Visual evidence chain" will outline key steps—tilted carton, downstream jam, acceptable cartons, and ERROR-17 outcomes. This structure helps clearly present the evidence for the user.Clarifying evidence and impact assessment

I’ll outline the evidence clearly: for the primary product, the issue occurred after sealing and carton placement, with proper handling of loose tablets. Cartons were checked for completeness and coding, and no product mix-up was found. Environmental conditions were within limits, and finished productFinal report structure and formatting decisions

I’ll title the report "Final Investigation Report," using "INVESTIGATION REPORT" as a template, and keep the file name final. The approval table and initials will be included. Also, I won’t create stability data specifics unnecessarily and will add document control. I'll size images to fit within the page width. I'll also add page breaks before each activity and ensure header rows repeat and tables remain together, keeping formatting tight with consistent spacing and shading.

Finalizing report layout and styling

I’ll adjust the margins toFinal Report Structure and Formatting Decisions

I’ll include a metadata table with alternating shading and avoid using a separate title on the first page, as there's already a header. Adding a main investigation summary table sounds appropriate. I’ll ensure the content is rendered correctly and finalized on around 30 pages, using Arial font. Citations will be based on the uploaded file, and I'll provide a file citation and sandbox link. I'll code and inspect thoroughly.

bash -lc cat > /mnt/data/build_final_report.py <<'PY' from docx import Document from docx.shared import Inches, Pt, RGBColor from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_BREAK, WD_LINE_SPACING from docx.enum.table import WD_TABLE_ALIGNMENT, WD_CELL_VERTICAL_ALIGNMENT from docx.enum.section import WD_SECTION from docx.oxml import OxmlElement from docx.oxml.ns import qn from docx.enum.style import WD_STYLE_TYPE from docx.enum.text import WD_TAB_ALIGNMENT, WD_TAB_LEADER from docx.enum.table import WD_ROW_HEIGHT_RULE from docx.enum.section import WD_ORIENT from pathlib import Path

OUT = '/mnt/data/Final_Investigation_Report_INV_PL3_26_008.docx' MEDIA = Path('/mnt/data/docx_media')

Theme

NAVY = '17365D' BLUE = '2F75B5' LIGHT_BLUE = 'D9EAF7' PALE_BLUE = 'EDF4FB' GREEN = '548235' LIGHT_GREEN = 'E2F0D9' RED = 'C00000' LIGHT_RED = 'FCE4D6' ORANGE = 'C65911' LIGHT_ORANGE = 'FCE4D6' GRAY = '7F8C8D' LIGHT_GRAY = 'F2F2F2' MID_GRAY = 'D9E1F2' WHITE = 'FFFFFF' BLACK = '000000'

def set_cell_shading(cell, fill): tcPr = cell._tc.get_or_add_tcPr() shd = tcPr.find(qn('w:shd')) if shd is None: shd = OxmlElement('w:shd') tcPr.append(shd) shd.set(qn('w:fill'), fill)

def set_cell_border(cell, **kwargs): tc = cell._tc tcPr = tc.get_or_add_tcPr() tcBorders = tcPr.first_child_found_in('w:tcBorders') if tcBorders is None: tcBorders = OxmlElement('w:tcBorders') tcPr.append(tcBorders) for edge in ('top', 'left', 'bottom', 'right', 'insideH', 'insideV'): if edge in kwargs: edge_data = kwargs[edge] tag = 'w:{}'.format(edge) element = tcBorders.find(qn(tag)) if element is None: element = OxmlElement(tag) tcBorders.append(element) for key in ['val', 'sz', 'space', 'color']: if key in edge_data: element.set(qn('w:{}'.format(key)), str(edge_data[key]))

def set_cell_margins(cell, top=60, start=80, bottom=60, end=80): tc = cell._tc tcPr = tc.get_or_add_tcPr() tcMar = tcPr.first_child_found_in('w:tcMar') if tcMar is None: tcMar = OxmlElement('w:tcMar') tcPr.append(tcMar) for m, v in [('top', top), ('start', start), ('bottom', bottom), ('end', end)]: node = tcMar.find(qn('w:' + m)) if node is None: node = OxmlElement('w:' + m) tcMar.append(node) node.set(qn('w:w'), str(v)) node.set(qn('w:type'), 'dxa')

def set_repeat_table_header(row): trPr = row._tr.get_or_add_trPr() tblHeader = OxmlElement('w:tblHeader') tblHeader.set(qn('w:val'), 'true') trPr.append(tblHeader)

def set_row_cant_split(row): trPr = row._tr.get_or_add_trPr() cantSplit = OxmlElement('w:cantSplit') trPr.append(cantSplit)

def set_col_widths(table, widths): for row in table.rows: for idx, width in enumerate(widths): if idx < len(row.cells): row.cells[idx].width = Inches(width) tcPr = row.cells[idx]._tc.get_or_add_tcPr() tcW = tcPr.find(qn('w:tcW')) if tcW is None: tcW = OxmlElement('w:tcW') tcPr.append(tcW) tcW.set(qn('w:w'), str(int(width * 1440))) tcW.set(qn('w:type'), 'dxa')

def set_table_borders(table, color='B7C9E2', sz=6): for row in table.rows: for cell in row.cells: set_cell_border(cell, top={'val':'single','sz':sz,'color':color}, bottom={'val':'single','sz':sz,'color':color}, left={'val':'single','sz':sz,'color':color}, right={'val':'single','sz':sz,'color':color})

def set_run_font(run, size=9, bold=False, color=BLACK, italic=False, name='Arial'): run.font.name = name run._element.get_or_add_rPr().rFonts.set(qn('w:ascii'), name) run._element.get_or_add_rPr().rFonts.set(qn('w:hAnsi'), name) run.font.size = Pt(size) run.bold = bold run.italic = italic run.font.color.rgb = RGBColor.from_string(color)

def clear_para(p): for r in list(p.runs): p._element.remove(r._element)

def add_text(p, text, bold=False, color=BLACK, size=9, italic=False): r = p.add_run(text) set_run_font(r, size=size, bold=bold, color=color, italic=italic) return r

def fmt_para(p, align=None, before=0, after=3, line=1.0, keep_with_next=False, keep_together=False): pf = p.paragraph_format pf.space_before = Pt(before) pf.space_after = Pt(after) pf.line_spacing = line if align is not None: p.alignment = align pf.keep_with_next = keep_with_next pf.keep_together = keep_together

def add_bullet(doc, text, level=0, bold_prefix=None, color=BLACK, after=2): p = doc.add_paragraph() p.style = doc.styles['List Bullet'] if level == 0 else doc.styles['List Bullet 2'] p.paragraph_format.left_indent = Inches(0.18 + 0.18 * level) p.paragraph_format.first_line_indent = Inches(-0.12) p.paragraph_format.space_after = Pt(after) p.paragraph_format.line_spacing = 1.0 if bold_prefix and text.startswith(bold_prefix): add_text(p, bold_prefix, bold=True, size=9) add_text(p, text[len(bold_prefix):], size=9, color=color) else: add_text(p, text, size=9, color=color) return p

def add_numbered(doc, num, text): t = doc.add_table(rows=1, cols=2) t.alignment = WD_TABLE_ALIGNMENT.CENTER t.autofit = False set_col_widths(t, [0.45, 6.65]) set_table_borders(t, color='FFFFFF', sz=0) c0, c1 = t.rows[0].cells set_cell_shading(c0, BLUE) set_cell_margins(c0, 60, 60, 60, 60) p0 = c0.paragraphs[0] fmt_para(p0, WD_ALIGN_PARAGRAPH.CENTER, after=0) add_text(p0, str(num), bold=True, color=WHITE, size=9) set_cell_shading(c1, PALE_BLUE) set_cell_margins(c1, 80, 100, 80, 100) p1 = c1.paragraphs[0] fmt_para(p1, WD_ALIGN_PARAGRAPH.JUSTIFY, after=0) add_text(p1, text, size=9) return t

def add_heading_bar(doc, text, page_break=False): if page_break: doc.add_page_break() tbl = doc.add_table(rows=1, cols=1) tbl.alignment = WD_TABLE_ALIGNMENT.CENTER tbl.autofit = False set_col_widths(tbl, [7.08]) cell = tbl.cell(0,0) set_cell_shading(cell, NAVY) set_cell_border(cell, top={'val':'single','sz':4,'color':NAVY}, bottom={'val':'single','sz':4,'color':NAVY}, left={'val':'single','sz':4,'color':NAVY}, right={'val':'single','sz':4,'color':NAVY}) set_cell_margins(cell, 75, 100, 75, 100) p = cell.paragraphs[0] fmt_para(p, WD_ALIGN_PARAGRAPH.LEFT, after=0, keep_with_next=True) add_text(p, text, bold=True, color=WHITE, size=10.5) return tbl

def add_subheading(doc, text, color=NAVY): p = doc.add_paragraph() fmt_para(p, WD_ALIGN_PARAGRAPH.LEFT, before=4, after=3, keep_with_next=True) add_text(p, text, bold=True, color=color, size=9.5) pPr = p._p.get_or_add_pPr() pbdr = OxmlElement('w:pBdr') bottom = OxmlElement('w:bottom') bottom.set(qn('w:val'), 'single') bottom.set(qn('w:sz'), '8') bottom.set(qn('w:color'), color) bottom.set(qn('w:space'), '2') pbdr.append(bottom) pPr.append(pbdr) return p

def add_callout(doc, title, body, fill=LIGHT_BLUE, title_color=NAVY, border=BLUE): t = doc.add_table(rows=1, cols=2) t.alignment = WD_TABLE_ALIGNMENT.CENTER t.autofit = False set_col_widths(t, [1.45, 5.63]) set_table_borders(t, color=border, sz=8) c0, c1 = t.rows[0].cells set_cell_shading(c0, border) set_cell_shading(c1, fill) for c in (c0,c1): set_cell_margins(c, 90, 100, 90, 100) p0 = c0.paragraphs[0]; fmt_para(p0, WD_ALIGN_PARAGRAPH.CENTER, after=0) add_text(p0, title, bold=True, color=WHITE, size=9) p1 = c1.paragraphs[0]; fmt_para(p1, WD_ALIGN_PARAGRAPH.JUSTIFY, after=0) add_text(p1, body, color=BLACK, size=9) return t

def add_status_box(doc, status, summary, status_color, fill): t = doc.add_table(rows=1, cols=2) t.alignment = WD_TABLE_ALIGNMENT.CENTER t.autofit = False set_col_widths(t, [1.45, 5.63]) set_table_borders(t, color=status_color, sz=8) c0,c1=t.rows[0].cells set_cell_shading(c0,status_color); set_cell_shading(c1,fill) for c in (c0,c1): set_cell_margins(c,80,100,80,100) p0=c0.paragraphs[0]; fmt_para(p0,WD_ALIGN_PARAGRAPH.CENTER,after=0) add_text(p0,status,bold=True,color=WHITE,size=8.5) p1=c1.paragraphs[0]; fmt_para(p1,WD_ALIGN_PARAGRAPH.JUSTIFY,after=0) add_text(p1,summary,size=8.8) return t

def add_caption(doc, text): p=doc.add_paragraph() fmt_para(p,WD_ALIGN_PARAGRAPH.CENTER,before=1,after=4) add_text(p,text,bold=True,italic=True,color=GRAY,size=7.5) return p

def add_picture(doc, path, width, caption=None): p = doc.add_paragraph() fmt_para(p, WD_ALIGN_PARAGRAPH.CENTER, before=2, after=1, keep_together=True) r = p.add_run() r.add_picture(str(path), width=Inches(width)) if caption: add_caption(doc, caption) return p

def add_page_number(paragraph): paragraph.alignment = WD_ALIGN_PARAGRAPH.RIGHT add_text(paragraph, 'Page ', size=7, color=GRAY) fld = OxmlElement('w:fldSimple') fld.set(qn('w:instr'), 'PAGE') r = OxmlElement('w:r') rPr = OxmlElement('w:rPr') rFonts = OxmlElement('w:rFonts') rFonts.set(qn('w:ascii'), 'Arial'); rFonts.set(qn('w:hAnsi'), 'Arial') rPr.append(rFonts) sz = OxmlElement('w:sz'); sz.set(qn('w:val'), '14'); rPr.append(sz) r.append(rPr) t = OxmlElement('w:t'); t.text = '1'; r.append(t) fld.append(r) paragraph._p.append(fld) add_text(paragraph, ' of ', size=7, color=GRAY) fld2 = OxmlElement('w:fldSimple') fld2.set(qn('w:instr'), 'NUMPAGES') r2 = OxmlElement('w:r') rPr2 = OxmlElement('w:rPr') rFonts2 = OxmlElement('w:rFonts') rFonts2.set(qn('w:ascii'), 'Arial'); rFonts2.set(qn('w:hAnsi'), 'Arial') rPr2.append(rFonts2) sz2 = OxmlElement('w:sz'); sz2.set(qn('w:val'), '14'); rPr2.append(sz2) r2.append(rPr2) t2 = OxmlElement('w:t'); t2.text = '1'; r2.append(t2) fld2.append(r2) paragraph._p.append(fld2)

def add_key_value_table(doc, rows, widths=(2.0,5.08), header=None): n = len(rows) + (1 if header else 0) t=doc.add_table(rows=n, cols=2) t.alignment=WD_TABLE_ALIGNMENT.CENTER t.autofit=False set_col_widths(t,list(widths)) set_table_borders(t) ridx=0 if header: c=t.rows[0].cells[0].merge(t.rows[0].cells[1]) set_cell_shading(c,NAVY); set_cell_margins(c,75,90,75,90) p=c.paragraphs[0]; fmt_para(p,WD_ALIGN_PARAGRAPH.LEFT,after=0) add_text(p,header,bold=True,color=WHITE,size=9) set_repeat_table_header(t.rows[0]) ridx=1 for i,(k,v) in enumerate(rows): c0,c1=t.rows[ridx+i].cells set_cell_shading(c0,LIGHT_BLUE if i%2==0 else PALE_BLUE) set_cell_shading(c1,WHITE) for c in (c0,c1): set_cell_margins(c,70,90,70,90); c.vertical_alignment=WD_CELL_VERTICAL_ALIGNMENT.CENTER p0=c0.paragraphs[0]; fmt_para(p0,WD_ALIGN_PARAGRAPH.LEFT,after=0); add_text(p0,k,bold=True,color=NAVY,size=8.5) p1=c1.paragraphs[0]; fmt_para(p1,WD_ALIGN_PARAGRAPH.JUSTIFY,after=0); add_text(p1,v,size=8.5) set_row_cant_split(t.rows[ridx+i]) return t

def add_review_header(doc, activity_no, activity, objective, responsibility): doc.add_page_break() t=doc.add_table(rows=5, cols=4) t.alignment=WD_TABLE_ALIGNMENT.CENTER t.autofit=False set_col_widths(t,[1.15,2.15,1.35,2.43]) set_table_borders(t,color='8EAADB',sz=7) h=t.rows[0].cells[0].merge(t.rows[0].cells[3]) set_cell_shading(h,NAVY); set_cell_margins(h,80,90,80,90) p=h.paragraphs[0]; fmt_para(p,WD_ALIGN_PARAGRAPH.CENTER,after=0) add_text(p,'INVESTIGATION FINDINGS',bold=True,color=WHITE,size=10) labels=[('Investigation No.','INV/PL3/26/008','Reference Document No.','NA'), ('Activity No.',activity_no,'Activity No.',activity_no)] for ri,vals in enumerate(labels, start=1): for ci,val in enumerate(vals): c=t.rows[ri].cells[ci] set_cell_shading(c,LIGHT_BLUE if ci%2==0 else WHITE) set_cell_margins(c,60,80,60,80) p=c.paragraphs[0]; fmt_para(p,WD_ALIGN_PARAGRAPH.LEFT,after=0) add_text(p,val,bold=(ci%2==0),color=NAVY if ci%2==0 else BLACK,size=8) # merge repeated activity number cells for cleaner layout t.rows[2].cells[2].text='' t.rows[2].cells[3].text='' m=t.rows[2].cells[1].merge(t.rows[2].cells[3]) clear_para(m.paragraphs[0]); fmt_para(m.paragraphs[0],WD_ALIGN_PARAGRAPH.LEFT,after=0); add_text(m.paragraphs[0],activity_no,size=8) # Activity row c0=t.rows[3].cells[0]; c1=t.rows[3].cells[1].merge(t.rows[3].cells[3]) set_cell_shading(c0,LIGHT_BLUE); set_cell_shading(c1,WHITE) for c in (c0,c1): set_cell_margins(c,70,80,70,80) p=c0.paragraphs[0]; fmt_para(p,WD_ALIGN_PARAGRAPH.LEFT,after=0); add_text(p,'Activity',bold=True,color=NAVY,size=8) p=c1.paragraphs[0]; fmt_para(p,WD_ALIGN_PARAGRAPH.JUSTIFY,after=0); add_text(p,activity,size=8) # Objective row c0=t.rows[4].cells[0]; c1=t.rows[4].cells[1].merge(t.rows[4].cells[3]) set_cell_shading(c0,LIGHT_BLUE); set_cell_shading(c1,WHITE) for c in (c0,c1): set_cell_margins(c,70,80,70,80) p=c0.paragraphs[0]; fmt_para(p,WD_ALIGN_PARAGRAPH.LEFT,after=0); add_text(p,'Objective',bold=True,color=NAVY,size=8) p=c1.paragraphs[0]; fmt_para(p,WD_ALIGN_PARAGRAPH.JUSTIFY,after=0); add_text(p,objective,size=8) p=doc.add_paragraph(); fmt_para(p,WD_ALIGN_PARAGRAPH.RIGHT,before=2,after=3) add_text(p,'Review owner: ',bold=True,color=NAVY,size=8); add_text(p,responsibility,size=8) return t

def add_evidence_table(doc, headers, rows, widths, font=7.5): t=doc.add_table(rows=1+len(rows),cols=len(headers)) t.alignment=WD_TABLE_ALIGNMENT.CENTER t.autofit=False set_col_widths(t,widths) set_table_borders(t,color='A6B8CE',sz=6) for j,h in enumerate(headers): c=t.rows[0].cells[j]; set_cell_shading(c,NAVY); set_cell_margins(c,65,55,65,55) p=c.paragraphs[0]; fmt_para(p,WD_ALIGN_PARAGRAPH.CENTER,after=0) add_text(p,h,bold=True,color=WHITE,size=font) set_repeat_table_header(t.rows[0]) for i,row in enumerate(rows,1): set_row_cant_split(t.rows[i]) for j,val in enumerate(row): c=t.rows[i].cells[j]; set_cell_shading(c,WHITE if i%2 else PALE_BLUE); set_cell_margins(c,55,60,55,60) p=c.paragraphs[0]; fmt_para(p,WD_ALIGN_PARAGRAPH.LEFT if j else WD_ALIGN_PARAGRAPH.CENTER,after=0) add_text(p,str(val),size=font) return t

def add_finding_paragraph(doc, text, bold_start=None): p=doc.add_paragraph() fmt_para(p,WD_ALIGN_PARAGRAPH.JUSTIFY,after=3) if bold_start and text.startswith(bold_start): add_text(p,bold_start,bold=True,color=NAVY,size=8.8) add_text(p,text[len(bold_start):],size=8.8) else: add_text(p,text,size=8.8) return p

Create document

doc = Document() sec=doc.sections[0] sec.page_width=Inches(8.27); sec.page_height=Inches(11.69) sec.top_margin=Inches(0.72); sec.bottom_margin=Inches(0.62) sec.left_margin=Inches(0.58); sec.right_margin=Inches(0.58) sec.header_distance=Inches(0.18); sec.footer_distance=Inches(0.22)

Styles

normal=doc.styles['Normal'] normal.font.name='Arial'; normal._element.rPr.rFonts.set(qn('w:ascii'),'Arial'); normal._element.rPr.rFonts.set(qn('w:hAnsi'),'Arial') normal.font.size=Pt(9) normal.paragraph_format.space_after=Pt(3); normal.paragraph_format.line_spacing=1.0 for sty_name in ['List Bullet','List Bullet 2','List Number']: st=doc.styles[sty_name] st.font.name='Arial'; st._element.rPr.rFonts.set(qn('w:ascii'),'Arial'); st._element.rPr.rFonts.set(qn('w:hAnsi'),'Arial'); st.font.size=Pt(9)

Header

header=sec.header hp=header.paragraphs[0]

remove default p content and add a 3-col table

clear_para(hp) ht=header.add_table(rows=1,cols=3,width=Inches(7.1)) ht.alignment=WD_TABLE_ALIGNMENT.CENTER; ht.autofit=False set_col_widths(ht,[1.15,4.85,1.10]) for c in ht.rows[0].cells: set_cell_border(c,top={'val':'nil'},bottom={'val':'nil'},left={'val':'nil'},right={'val':'nil'}) set_cell_margins(c,0,0,0,0)

left

p=ht.cell(0,0).paragraphs[0]; fmt_para(p,WD_ALIGN_PARAGRAPH.LEFT,after=0) add_text(p,'INV/PL3/26/008',bold=True,color=GRAY,size=7.5)

center

p=ht.cell(0,1).paragraphs[0]; fmt_para(p,WD_ALIGN_PARAGRAPH.CENTER,after=0) add_text(p,'INVESTIGATION REPORT',bold=True,color=NAVY,size=10.5)

right logo

p=ht.cell(0,2).paragraphs[0]; fmt_para(p,WD_ALIGN_PARAGRAPH.RIGHT,after=0) r=p.add_run(); r.add_picture(str(MEDIA/'image14.png'),width=Inches(0.58))

remove empty initial header paragraph space

hp.paragraph_format.space_after=Pt(0); hp.paragraph_format.line_spacing=0.1

Footer

footer=sec.footer fp=footer.paragraphs[0]; clear_para(fp) ft=footer.add_table(rows=1,cols=2,width=Inches(7.1)); ft.alignment=WD_TABLE_ALIGNMENT.CENTER; ft.autofit=False set_col_widths(ft,[5.4,1.7]) for c in ft.rows[0].cells: set_cell_border(c,top={'val':'single','sz':4,'color':'B7C9E2'},bottom={'val':'nil'},left={'val':'nil'},right={'val':'nil'}) set_cell_margins(c,35,0,0,0) p=ft.cell(0,0).paragraphs[0]; fmt_para(p,WD_ALIGN_PARAGRAPH.LEFT,after=0); add_text(p,'Format No. CQA038/F06/00',size=7,color=GRAY) p=ft.cell(0,1).paragraphs[0]; fmt_para(p,WD_ALIGN_PARAGRAPH.RIGHT,after=0); add_page_number(p) fp.paragraph_format.space_after=Pt(0); fp.paragraph_format.line_spacing=0.1

1.0 reporting

add_heading_bar(doc,'1.0 INVESTIGATION REPORTING') report_rows=[ ('Investigation No.','INV/PL3/26/008'), ('Initiator','Janhavi Mhatre'), ('Department','Production'), ('Date of Initiation','24/06/2026'), ('Non-Conformity','During secondary packing of Lonart 20/120 AQCOAT Tablets, Batch No. 0360093A, the online checkweigher rejected acceptable cartons along with non-conforming cartons and repeatedly stopped Blister Packing Line-4.'), ('Event Description','On 23/06/2026 at 13:16 hrs., during routine secondary packing of Lonart 20/120 AQCOAT Tablets, Batch No. 0360093A, the online checkweigher (Equipment ID: 100423) was observed rejecting acceptable cartons in addition to intended rejects. The condition generated repeated line stoppages and the alarm ERROR-17 - REJECTION CONFIRMATION FAILED.') ] add_key_value_table(doc,report_rows,widths=(1.72,5.36))

add_subheading(doc,'Event Details (5W/2H)') rows_5w=[ ('What?','Acceptable cartons were found in the checkweigher rejection stream, and the line stopped repeatedly with ERROR-17.'), ('Which?','Secondary Packing Line-4; Lonart 20/120 AQCOAT Tablets; Batch No. 0360093A.'), ('Where?','At the interface between the online checkweigher (Equipment ID: 100423) and the Track & Trace machine (Equipment ID: 100358).'), ('When?','23/06/2026 at 13:16 hrs.'), ('Who identified?','Mr. Lokesh Jadhav, Packing Officer (Employee ID: 10002288).'), ('How identified?','During routine line operation, cartons accumulated near the checkweigher exit/Track & Trace infeed, acceptable cartons moved toward the reject side, and the checkweigher displayed ERROR-17.'), ('How many?','One batch: Batch No. 0360093A.') ] add_key_value_table(doc,rows_5w,widths=(1.45,5.63))

add_heading_bar(doc,'2.0 IMMEDIATE ACTION',page_break=False) for txt in [ 'Packing operations on Blister Packing Line-4 were stopped immediately.', 'B1 Notification No. 1000187 was raised in SAP for Engineering inspection and rectification.', 'The event was communicated to the Production Head, Engineering Head, and Quality Assurance Head.', 'Cartons present in the rejection bin and affected transfer area were segregated and retained for verification.', 'In-process loose tablets remaining on the blister packing machine were removed and handled as per the applicable procedure.' ]: add_bullet(doc,txt)

Background

add_heading_bar(doc,'3.0 BACKGROUND OF THE EVENT',page_break=True) add_finding_paragraph(doc,'Secondary packing of Lonart 20/120 AQCOAT Tablets, Batch No. 0360093A, was planned on Blister Packing Line-4. The line operates as an integrated sequence of equipment from blister formation to shipper packing.') for txt in [ 'Blister Packing Machine - Equipment ID: 100336', 'Auto-Cartonator - Equipment ID: 100338', 'Online Checkweigher - Equipment ID: 100423', 'Track & Trace Machine - Equipment ID: 100358', 'Automatic Sticker Labelling Machine with Conveyor - Equipment ID: 100297', 'Top Scanner - Equipment ID: 100384', 'Outer carton/shipper packing and weighing' ]: add_bullet(doc,txt) add_finding_paragraph(doc,'The checkweigher is installed downstream of the Auto-Cartonator and upstream of the Track & Trace machine. Each filled carton is weighed against approved limits so that cartons with a missing blister and/or leaflet are rejected before downstream serialization and packing operations.') add_finding_paragraph(doc,'Line clearance was completed on 22/06/2026 at 08:51 hrs. Machine setup, carton-weight calculation, and challenge tests were completed and found satisfactory before packing. During continued operation on 23/06/2026 at 13:16 hrs., acceptable cartons were observed in the rejection stream and Line-4 stopped repeatedly. The line was stopped and the event was escalated for cross-functional investigation.')

add_subheading(doc,'3.1 Event Timeline') timeline=[ ('22/06/2026','08:51','Line clearance for secondary packing completed.'), ('22/06/2026','13:04-13:09','Auto-Cartonator challenge tests for leaflet/carton detection completed - all passed.'), ('22/06/2026','14:07','Checkweigher challenge tests for overweight, underweight, and good cartons completed - all passed.'), ('22/06/2026','14:41-22:43','Five in-process checks completed - all satisfactory.'), ('23/06/2026','13:16','Acceptable cartons observed in the reject stream; ERROR-17 displayed; repeated stoppage of Line-4.'), ('23/06/2026','13:16','Line stopped and B1 Notification No. 1000187 raised in SAP.'), ('23/06/2026','Post-event','Production, Engineering, and Quality Assurance initiated investigation and rectification.') ] add_evidence_table(doc,['Date','Time','Event'],timeline,[1.25,1.15,4.68],font=8)

Team

add_heading_bar(doc,'4.0 INVESTIGATION TEAM',page_break=True) add_finding_paragraph(doc,'A cross-functional investigation team was formed to assess the event from operational, engineering, and quality perspectives and to establish a documented, evidence-based root cause.') team=[ ('1','Mr. Shyamkant Patil','Production','Investigation Team Lead'), ('2','Mr. Bhavesh Surati','Production','Investigation Team Member'), ('3','Mr. Pavan Badgujar','Production','Investigation Team Member'), ('4','Mr. Arvind Patil','Engineering','Investigation Team Member'), ('5','Mr. Ganesh Yellapu','Quality Assurance','Investigation Team Member'), ('6','Mr. Prashant Chaudhari','Quality Assurance','Investigation Team Member') ] add_evidence_table(doc,['Sr. No.','Name','Department','Role'],team,[0.65,2.05,1.55,2.83],font=8)

Gemba

add_heading_bar(doc,'5.0 GEMBA WALK (GO AND SEE)',page_break=True) add_callout(doc,'PURPOSE','To observe the event at the actual workplace, verify the physical interaction between the checkweigher and Track & Trace machine, compare operator statements with the equipment condition, and reproduce the failure mechanism under controlled observation.',fill=PALE_BLUE,border=BLUE) add_subheading(doc,'5.1 Gemba at a Glance') gemba_meta=[ ('Location','Secondary Packing Hall-2, GF-187, Blister Packing Line-4 - Large Scale Area'), ('Product / Batch','Lonart 20/120 AQCOAT Tablets / Batch No. 0360093A'), ('Functions present','Production, Engineering, and Quality Assurance'), ('Personnel interviewed','Mr. Birma Gurjar (Operator) and Mr. Lokesh Jadhav (Packing Officer)'), ('Scope walked','Blister Packing Machine through shipper packing, with detailed focus on the checkweigher-to-Track & Trace transfer area') ] add_key_value_table(doc,gemba_meta,widths=(1.55,5.53))

add_subheading(doc,'5.2 Gemba Method - Observe, Verify, Reproduce, Conclude')

4 column visual strip

vt=doc.add_table(rows=1,cols=4); vt.alignment=WD_TABLE_ALIGNMENT.CENTER; vt.autofit=False set_col_widths(vt,[1.77,1.77,1.77,1.77]); set_table_borders(vt,color='FFFFFF',sz=0) steps=[('1. OBSERVE','Actual carton movement, sensor locations, rejector, star-wheel infeed, and alarm condition.',BLUE,LIGHT_BLUE), ('2. VERIFY','Recipe, weight limits, component presence, reject-bin cartons, and challenge-test records.',GREEN,LIGHT_GREEN), ('3. REPRODUCE','Restarted at low speed, then gradually increased speed to observe the failure sequence.',ORANGE,LIGHT_ORANGE), ('4. CONCLUDE','Confirmed downstream jam and upstream backup into the reject-confirmation zone.',RED,LIGHT_RED)] for i,(title,body,clr,fill) in enumerate(steps): c=vt.cell(0,i); set_cell_shading(c,fill); set_cell_border(c,top={'val':'single','sz':10,'color':clr},bottom={'val':'single','sz':6,'color':clr},left={'val':'single','sz':6,'color':clr},right={'val':'single','sz':6,'color':clr}); set_cell_margins(c,90,90,90,90) p=c.paragraphs[0]; fmt_para(p,WD_ALIGN_PARAGRAPH.CENTER,after=3); add_text(p,title,bold=True,color=clr,size=8.2) p=c.add_paragraph(); fmt_para(p,WD_ALIGN_PARAGRAPH.LEFT,after=0); add_text(p,body,size=7.7)

add_subheading(doc,'5.3 Process Sequence Walked') add_picture(doc,MEDIA/'image1.png',width=7.02,caption='Figure 5.1 - Secondary Packing Line-4 equipment sequence and the short interface between the checkweigher and Track & Trace infeed.')

add_subheading(doc,'5.4 Key Physical and Functional Observations') obs=[ ('Blister quality control','The blister camera rejection system (Make: JEKSON) was operational and rejected defective blisters. Only acceptable blisters were transferred to the Auto-Cartonator.'), ('Carton component control','The Auto-Cartonator mechanically inserted three blisters and one leaflet. Challenge records for missing blister, missing leaflet, and pharmacode mismatch were satisfactory.'), ('Checkweigher settings','Target 18.81 g; lower limit 17.53 g; upper limit 20.09 g. The last weight displayed during the alarm was 18.70 g, which was within the approved range.'), ('Reject-system components','S1/S2 sensors, load cell, PLC logic, pneumatic rejector, and reject-confirmation sensor were present and responded during testing.'), ('Physical interface','The checkweigher exit/reject-confirmation area and Track & Trace star-wheel infeed were installed with very limited separation and essentially no accumulation buffer.'), ('Rejected-carton examination','Sample cartons from the checkweigher reject bin were physically examined; no missing blister or leaflet was observed in the sampled acceptable cartons.'), ('Alarm evidence','The HMI displayed ERROR-17 - REJECTION CONFIRMATION FAILED while the line was stopped.'), ('Reproduction evidence','At low speed cartons transferred normally. As speed increased, a tilted carton jammed at the Track & Trace star-wheel, causing cartons to queue back into the checkweigher reject-confirmation zone and reproducing the alarm condition.') ] add_evidence_table(doc,['Observation Area','Verified Gemba Evidence'],obs,[1.55,5.53],font=8)

add_subheading(doc,'5.5 Photographic Evidence') pt=doc.add_table(rows=1,cols=2); pt.alignment=WD_TABLE_ALIGNMENT.CENTER; pt.autofit=False set_col_widths(pt,[3.53,3.53]); set_table_borders(pt,color='B7C9E2',sz=6) for c in pt.rows[0].cells: set_cell_margins(c,70,70,70,70) p=pt.cell(0,0).paragraphs[0]; fmt_para(p,WD_ALIGN_PARAGRAPH.CENTER,after=2); r=p.add_run(); r.add_picture(str(MEDIA/'image8.png'),width=Inches(3.18)) p=pt.cell(0,0).add_paragraph(); fmt_para(p,WD_ALIGN_PARAGRAPH.CENTER,after=0); add_text(p,'Photo 5.1 - Checkweigher and downstream transfer area.',bold=True,italic=True,color=GRAY,size=7.2) p=pt.cell(0,1).paragraphs[0]; fmt_para(p,WD_ALIGN_PARAGRAPH.CENTER,after=2); r=p.add_run(); r.add_picture(str(MEDIA/'image3.jpeg'),width=Inches(2.8)) p=pt.cell(0,1).add_paragraph(); fmt_para(p,WD_ALIGN_PARAGRAPH.CENTER,after=0); add_text(p,'Photo 5.2 - HMI displaying ERROR-17; last displayed weight 18.70 g.',bold=True,italic=True,color=GRAY,size=7.2)

add_subheading(doc,'5.6 Failure Sequence Observed During Reproduction') sequence=[ ('1','Some cartons left the Auto-Cartonator slightly tilted rather than square to the conveyor direction.'), ('2','The tilted cartons passed the weighing section and were correctly classified by weight.'), ('3','A tilted carton failed to enter the Track & Trace star-wheel cleanly and became stuck at the infeed.'), ('4','With insufficient buffer distance, cartons immediately queued upstream from the Track & Trace infeed onto the checkweigher exit.'), ('5','The queue occupied the reject-confirmation zone, disturbed the expected carton spacing/position sequence, and exposed acceptable cartons to the reject path.'), ('6','The reject-confirmation signal was not completed within the expected time; ERROR-17 was generated and the line stopped.') ] add_evidence_table(doc,['Step','Observed Sequence'],sequence,[0.65,6.43],font=8) add_picture(doc,MEDIA/'image4.png',width=7.02,caption='Figure 5.2 - Reproduced failure mechanism: a tilted carton jam at the Track & Trace infeed caused upstream backup into the checkweigher reject-confirmation zone.')

add_status_box(doc,'GEMBA CONCLUSION','The checkweigher weighing function was not shown to misclassify the last displayed carton by weight. The event was generated by physical carton accumulation at the downstream interface: a Track & Trace infeed jam propagated upstream because the checkweigher reject-confirmation zone had insufficient separation/buffer from the star-wheel infeed.',RED,LIGHT_RED)

Why Why

add_heading_bar(doc,'6.0 WHY-WHY ANALYSIS',page_break=True) add_finding_paragraph(doc,'The Why-Why analysis was prepared from direct Gemba observations and the reproduced failure sequence. Its purpose was to identify the most probable causal pathway before detailed documentary and technical reviews were completed.') problem=doc.add_table(rows=1,cols=1); problem.alignment=WD_TABLE_ALIGNMENT.CENTER; problem.autofit=False; set_col_widths(problem,[7.08]); set_table_borders(problem,color=RED,sz=10) c=problem.cell(0,0); set_cell_shading(c,LIGHT_RED); set_cell_margins(c,100,110,100,110) p=c.paragraphs[0]; fmt_para(p,WD_ALIGN_PARAGRAPH.CENTER,after=0); add_text(p,'PROBLEM STATEMENT: Acceptable cartons entered the reject stream and Blister Packing Line-4 stopped repeatedly with ERROR-17 - REJECTION CONFIRMATION FAILED.',bold=True,color=RED,size=9)

whys=[ ('WHY 1','Why were acceptable cartons rejected and the line stopped?','Because carton accumulation entered the checkweigher reject zone, disturbed the intended carton spacing/position sequence, and prevented timely reject confirmation. Under this condition an acceptable carton could be displaced toward the reject bin and ERROR-17 was generated.'), ('WHY 2','Why did cartons accumulate in the reject-confirmation zone?','Because cartons backed up from the downstream Track & Trace infeed onto the checkweigher exit conveyor.'), ('WHY 3','Why did the downstream backup start?','Because a slightly tilted carton did not enter the Track & Trace star-wheel cleanly and became jammed at the infeed.'), ('WHY 4','Why did a localized Track & Trace jam immediately propagate into the checkweigher reject zone?','Because the physical distance between the checkweigher reject-confirmation zone and the Track & Trace infeed was insufficient and no effective accumulation buffer/jam-isolation space was available.'), ('WHY 5','Why was this interface risk not identified during routine setup and challenge testing?','Because the routine checkweigher challenge test verifies weight classification and reject actuation under free-flow conditions; the existing procedure did not require an integrated-line challenge for downstream jam/backpressure at operating speed.') ] wt=doc.add_table(rows=len(whys),cols=3); wt.alignment=WD_TABLE_ALIGNMENT.CENTER; wt.autofit=False set_col_widths(wt,[0.85,2.35,3.88]); set_table_borders(wt,color='A6B8CE',sz=7) for i,(lvl,q,a) in enumerate(whys): set_row_cant_split(wt.rows[i]) c0,c1,c2=wt.rows[i].cells set_cell_shading(c0,BLUE if i<3 else ORANGE if i==3 else RED) set_cell_shading(c1,LIGHT_BLUE if i<3 else LIGHT_ORANGE if i==3 else LIGHT_RED) set_cell_shading(c2,WHITE) for c in (c0,c1,c2): set_cell_margins(c,80,80,80,80); c.vertical_alignment=WD_CELL_VERTICAL_ALIGNMENT.CENTER p=c0.paragraphs[0]; fmt_para(p,WD_ALIGN_PARAGRAPH.CENTER,after=0); add_text(p,lvl,bold=True,color=WHITE,size=8) p=c1.paragraphs[0]; fmt_para(p,WD_ALIGN_PARAGRAPH.LEFT,after=0); add_text(p,q,bold=True,color=NAVY,size=8) p=c2.paragraphs[0]; fmt_para(p,WD_ALIGN_PARAGRAPH.JUSTIFY,after=0); add_text(p,a,size=8)

add_status_box(doc,'WHY-WHY OUTPUT','Probable technical root cause: inadequate line-interface design/control between the checkweigher rejection zone and the Track & Trace infeed, specifically insufficient physical buffering to isolate a downstream jam. Trigger: tilted carton at the Track & Trace star-wheel. Systemic contributor: challenge testing/procedure did not evaluate downstream backup conditions.',RED,LIGHT_RED)

add_callout(doc,'WHY DETAILED REVIEWS CONTINUED','Although the Why-Why analysis identified a technically plausible root-cause pathway, the investigation was not closed on the Why-Why conclusion alone. A root cause must be supported by documented evidence, the reproduced mechanism must be confirmed, and credible alternative causes must be evaluated and ruled out. Therefore, the team performed the in-depth review points below to confirm the interface mechanism, identify systemic contributors, assess recurrence history, and demonstrate whether settings, training, qualification/maintenance, batch-record execution, procedure adequacy, or operator actions contributed to the event.',fill=PALE_BLUE,border=BLUE)

Investigation Plan

add_heading_bar(doc,'7.0 DETAILED INVESTIGATION REVIEW',page_break=True) add_subheading(doc,'7.1 Investigation Plan') plan=[ ('1','Review of checkweigher settings and carton-weight calculation','Confirm that target weight and acceptance limits were calculated and entered in accordance with SOP/PG/120 and the Batch Packing Record.','Mr. Pavan Badgujar'), ('2','Review of training records','Confirm that personnel operating or supervising the checkweigher were trained and experienced.','Mr. Bhavesh Surati'), ('3','Review of qualification and preventive-maintenance status','Confirm that the checkweigher was qualified, maintained, and within validity at the time of the event.','Mr. Ganesh Yellapu'), ('4','Review of rejection mechanism and sensor functionality','Verify the working principle, actual sensor/rejector response, and the mechanism by which acceptable cartons could enter the reject stream.','Mr. Arvind Patil'), ('5','Review of Batch Packing Record for Batch No. 0360093A','Verify compliance with approved packing instructions, line clearance, challenge tests, and in-process checks.','Mr. Shyamkant Patil'), ('6','Review of SOP/PG/120, Version 01','Assess whether the procedure adequately covers integrated-line interface checks, carton accumulation, and response to downstream jams.','Mr. Shyamkant Patil'), ('7','Review of equipment history card','Assess previous breakdowns, similar alarms, maintenance history, and recurrence trend.','Mr. Arvind Patil'), ('8','Discussion with operating personnel','Corroborate the event sequence, immediate response, and any operational intervention or abnormal practice.','Mr. Shyamkant Patil'), ('9','Review of B1 Notification No. 1000187 and engineering rectification','Verify the technical observations, temporary correction, post-rectification challenge, and residual risk.','Mr. Arvind Patil') ] add_evidence_table(doc,['No.','Review Point','Objective','Responsibility'],plan,[0.45,2.05,3.43,1.15],font=7.2)

Activity 1

add_review_header(doc,'INV/PL3/26/008_01','Review of checkweigher settings and carton-weight calculation','Confirm that the target weight and acceptance limits were calculated, documented, and entered in accordance with the approved procedure and BPR.','Mr. Pavan Badgujar') add_subheading(doc,'Investigation Findings') add_finding_paragraph(doc,'The investigation team reviewed the carton-weight calculation and the corresponding values entered on the checkweigher HMI. The calculation was performed by Mr. Lokesh Jadhav (Employee ID: 10002288) and checked by Mr. Nagesh Nagare (Employee ID: 10002165).') weight_rows=[ ('Average weight of 10 good packed cartons (A)','18.81 g'), ('Average weight of 10 least-weight components (B)','2.40 g'), ('Weight of one blister','3.80 g'), ('Weight of leaflet','2.45 g'), ('Least-weight component','Leaflet'), ('Target carton weight','18.81 g'), ('Tolerance','+/- 1.28 g'), ('Upper limit','20.09 g'), ('Lower limit','17.53 g') ] add_evidence_table(doc,['Parameter','Recorded Value'],weight_rows,[4.7,2.38],font=8) add_finding_paragraph(doc,'The approved HMI settings matched the documented calculation. Initial challenge tests using overweight, underweight, and good cartons were satisfactory, demonstrating correct weight classification and reject-decision logic at batch start.') add_status_box(doc,'RULED OUT','The target weight, upper/lower limits, and HMI entries were appropriate. No evidence indicated that an incorrect calculation or recipe setting caused the event.',GREEN,LIGHT_GREEN)

Activity 2

add_review_header(doc,'INV/PL3/26/008_02','Review of training records of personnel involved in secondary packing/checkweighing','Confirm that all personnel involved were trained on SOP/PG/120 and had adequate operating experience.','Mr. Bhavesh Surati') add_subheading(doc,'Investigation Findings') add_finding_paragraph(doc,'Training records for the personnel involved in checkweigher operation and supervision were reviewed against SOP/PG/120, "Procedure for Operation and Cleaning of Checkweigher System (Make: Technofour)."') training=[ ('Mr. Nagesh Nagare','10002165','Yes','04/07/2025','3.0 years'), ('Mr. Amol Patil','3829865','Yes','22/11/2025','11 months'), ('Mr. Lokesh Jadhav','10002288','Yes','29/07/2025','3.5 years'), ('Mr. Birma Gurjar','10002223','Yes','15/09/2025','4.5 years') ] add_evidence_table(doc,['Name','Employee ID','Trained','Training Date','Experience'],training,[2.0,1.15,0.75,1.35,1.83],font=7.8) add_finding_paragraph(doc,'All concerned personnel had documented training and relevant practical experience. The event response - stopping the line, segregating cartons, escalating the issue, and raising the B1 notification - was consistent with expected controls.') add_status_box(doc,'RULED OUT','No untrained or unauthorized person was involved. Personnel training or lack of experience was not causal.',GREEN,LIGHT_GREEN)

Activity 3

add_review_header(doc,'INV/PL3/26/008_03','Review of checkweigher qualification and preventive-maintenance status','Confirm that the equipment was qualified, maintained, and within validity on the date of the event.','Mr. Ganesh Yellapu') add_subheading(doc,'Investigation Findings') qual=[ ('Equipment','Checkweigher Machine - Equipment ID: 100423'), ('Qualification completion date','31/05/2024'), ('Qualification due date','31/05/2027'), ('Last preventive-maintenance completion','31/05/2026'), ('Next preventive-maintenance due date','28/08/2026') ] add_key_value_table(doc,qual,widths=(2.65,4.43)) add_finding_paragraph(doc,'Qualification and preventive-maintenance records were current on 23/06/2026. No overdue qualification or preventive-maintenance activity was identified. The reviewed evidence did not indicate deterioration of the load cell, PLC, or general machine functionality due to lack of maintenance.') add_status_box(doc,'RULED OUT','Use of unqualified equipment or overdue preventive maintenance was not the cause of the event.',GREEN,LIGHT_GREEN)

Activity 4

add_review_header(doc,'INV/PL3/26/008_04','Review of rejection mechanism, sensors, and checkweigher functionality','Confirm the normal operating logic and establish the physical mechanism by which acceptable cartons entered the reject stream.','Mr. Arvind Patil') add_subheading(doc,'Normal Checkweigher Logic') components=[ ('S1 sensors','Detect carton arrival at the checkweigher infeed.'), ('S2 sensors','Track carton position through the weighing/rejection sequence.'), ('Load cell','Captures the dynamic carton weight.'), ('PLC','Compares measured weight against the approved lower and upper limits and generates accept/reject decision.'), ('Pneumatic rejector','Diverts a carton when a reject command is generated.'), ('Reject-confirmation sensor','Confirms that the commanded reject has departed the main conveyor within the defined time; otherwise ERROR-17 is generated and the line stops.') ] add_evidence_table(doc,['Component','Function'],components,[1.7,5.38],font=8) add_picture(doc,MEDIA/'image7.png',width=6.45,caption='Figure 7.1 - Normal carton decision and rejection-confirmation logic of the Technofour checkweigher.') add_subheading(doc,'Event-Specific Technical Findings') for txt in [ 'S1/S2 detection, dynamic weighing, PLC comparison, and reject actuation responded during testing; the checkweigher could correctly classify challenge cartons by weight.', 'The reject-confirmation sensor does not determine carton weight. It confirms physical departure of a commanded reject and is sensitive to carton occupancy in the confirmation zone.', 'During the reproduced event, a Track & Trace infeed jam caused multiple cartons to queue back into the checkweigher exit/reject-confirmation area.', 'The backup disturbed the normal one-carton spacing and position sequence. Under this abnormal condition, an acceptable carton could be present in the reject path while the confirmation sensor remained blocked, leading to false rejection and ERROR-17.', 'The physical separation between the reject-confirmation sensor and Track & Trace star-wheel infeed was insufficient to prevent a downstream jam from entering the reject zone.' ]: add_bullet(doc,txt) add_status_box(doc,'ROOT CAUSE CONFIRMED','The event was caused by physical interference at the checkweigher-to-Track & Trace interface, not by incorrect weight measurement. Insufficient buffer distance allowed a downstream jam to occupy the reject-confirmation zone and disrupt the rejection sequence.',RED,LIGHT_RED)

Activity 5

add_review_header(doc,'INV/PL3/26/008_05','Review of Batch Packing Record for Lonart 20/120 AQCOAT Tablets, Batch No. 0360093A','Verify that approved secondary-packing instructions, line clearance, setup, challenge tests, and in-process controls were followed.','Mr. Shyamkant Patil') add_subheading(doc,'Investigation Findings') bpr=[ ('Line clearance','Completed on 22/06/2026 at 08:51 hrs.; no discrepancy documented.'), ('Auto-Cartonator challenges','Missing leaflet, carton/component detection, and pharmacode-related checks completed between 13:04 and 13:09 hrs.; satisfactory.'), ('Checkweigher challenges','Overweight, underweight, and good-carton challenges completed at 14:07 hrs.; satisfactory.'), ('Weight settings','Target 18.81 g; lower 17.53 g; upper 20.09 g; values matched the calculation record.'), ('In-process checks','Five checks at 14:41, 16:42, 18:43, 20:42, and 22:43 hrs. were recorded as satisfactory.'), ('Packaging attributes','Carton overprinting/coding, blister count, leaflet presence, outer-carton quantity, and shipper-label quality were found compliant during routine IPCs.'), ('Event response','Line was stopped, affected cartons were segregated, and the event was escalated through the B1 system.') ] add_evidence_table(doc,['BPR Element','Review Result'],bpr,[1.75,5.33],font=8) add_finding_paragraph(doc,'No omission or unauthorized departure from the approved BPR instructions was identified before the event. The BPR challenge tests confirmed the checkweigher under normal free-flow conditions but did not challenge the integrated line under downstream accumulation/backpressure.') add_status_box(doc,'BPR EXECUTION RULED OUT','The batch record was followed and routine documented checks were satisfactory. BPR execution was not causal. The limitation identified relates to the scope of the approved challenge, which is addressed under the SOP/system review.',GREEN,LIGHT_GREEN)

Activity 6

add_review_header(doc,'INV/PL3/26/008_06','Review of SOP/PG/120, Version 01 - Procedure for Operation and Cleaning of Checkweigher System (Make: Technofour)','Assess whether the approved procedure adequately controls the checkweigher as part of an integrated line and covers downstream jam/backpressure conditions.','Mr. Shyamkant Patil') add_subheading(doc,'Investigation Findings') proc=[ ('Adequately covered','Machine start-up, recipe selection, target/limit entry, routine challenge tests, rejection-bin control, physical verification of rejected filled cartons, correction of missing components if any, and re-passing cartons through the checkweigher.'), ('Not specifically covered','Verification of minimum clearance/buffer between the reject-confirmation sensor and downstream Track & Trace infeed.'), ('Not specifically covered','Check of guide alignment and carton squareness at the Track & Trace star-wheel under routine/maximum approved speed.'), ('Not specifically covered','Integrated challenge simulating a downstream jam or carton backup to verify that accumulation does not enter the reject-confirmation zone.'), ('Not specifically covered','Defined operator response and inspection points for ERROR-17 when accompanied by downstream carton accumulation.'), ('Not specifically covered','Post-modification effectiveness monitoring for the checkweigher-to-Track & Trace interface.') ] add_evidence_table(doc,['Procedure Review','Observation'],proc,[1.65,5.43],font=8) add_finding_paragraph(doc,'The SOP was adequate for standalone checkweigher operation and routine reject challenges. However, it did not address the interface risk created by the adjacent Track & Trace machine. Consequently, the latent downstream-jam/backpressure scenario was not deliberately challenged or detected during setup.') add_status_box(doc,'SYSTEMIC CONTRIBUTING FACTOR','The procedure/challenge-test scope did not evaluate integrated-line accumulation at operating speed. This did not directly create the short physical gap, but it allowed the design/interface vulnerability to remain undetected.',ORANGE,LIGHT_ORANGE)

Activity 7

add_review_header(doc,'INV/PL3/26/008_07','Review of equipment history card for Checkweigher Equipment ID: 100423','Assess previous breakdowns, similar alarms, maintenance history, and recurrence trend.','Mr. Arvind Patil') add_subheading(doc,'Investigation Findings') history=[ ('1','1100007663','18/07/2024','Communication failure with weighing unit','Software issue resolved by IT/OEM; operation checked satisfactory.'), ('2','1100008464','07/12/2024','Rejection-confirmation sensor error/problem; checkweigher not working','Sensor setting completed.'), ('3','1100010875','24/12/2025','Checkweigher rejection-bin lock broken','Rejection-bin lock replaced; keys handed to Packing Officer; checked satisfactory.'), ('4','1000187','23/06/2026','Current event - rejection sensor/rejection-confirmation issue during carton accumulation','Rejection-mechanism sensor position and timing adjusted; machine and challenge test checked satisfactory.') ] add_evidence_table(doc,['No.','B1 No.','Date','Issue','Rectification'],history,[0.38,1.0,0.85,2.25,2.6],font=6.7) add_finding_paragraph(doc,'The available history included seven preventive-maintenance records and four B1 notifications. One prior rejection-confirmation sensor event was recorded on 07/12/2024. No recurring breakdown trend was identified during the six months immediately preceding the current event; however, the earlier sensor-related notification shows that the rejection-confirmation area is sensitive to setup and should be controlled through permanent design and procedural measures rather than repeated adjustment alone.') add_status_box(doc,'NO GENERAL MAINTENANCE TREND','The history did not support a conclusion of systemic equipment neglect or repeated load-cell failure. The prior sensor event is relevant corroborative evidence for strengthening the reject-zone/interface controls.',BLUE,PALE_BLUE) add_subheading(doc,'Equipment History Evidence') add_picture(doc,MEDIA/'image10.png',width=6.55,caption='Figure 7.2 - Extract of equipment history/notification record reviewed during the investigation.')

Activity 8

add_review_header(doc,'INV/PL3/26/008_08','Discussion with operating personnel involved in secondary packing','Corroborate the event sequence, immediate actions, and whether any abnormal operator intervention contributed to the event.','Mr. Shyamkant Patil') add_subheading(doc,'Personnel Interview Summary') interviews=[ ('Line condition','The line was operating under routine secondary-packing conditions before the event.'), ('First abnormal observation','Cartons began accumulating near the checkweigher exit and Track & Trace infeed.'), ('Reject-side observation','Acceptable-looking cartons were observed moving toward/collecting at the checkweigher reject side.'), ('Alarm','ERROR-17 - REJECTION CONFIRMATION FAILED appeared on the checkweigher HMI.'), ('Immediate response','The line was stopped promptly; Production, Engineering, and Quality Assurance were informed.'), ('Engineering request','B1 Notification No. 1000187 was raised for inspection and rectification.'), ('Operator intervention','No bypass, unauthorized adjustment, or continuation of operation after recognizing the abnormal rejection pattern was reported or identified.') ] add_evidence_table(doc,['Interview Topic','Consistent Statement / Evidence'],interviews,[1.55,5.53],font=8) add_finding_paragraph(doc,'The operator and Packing Officer accounts were mutually consistent and matched the physical evidence and reproduced failure sequence. Their response limited the duration of the event and maintained control of affected cartons.') add_status_box(doc,'OPERATOR ERROR RULED OUT','No evidence of an unauthorized action or failure to respond was identified. Personnel statements corroborated the Gemba findings.',GREEN,LIGHT_GREEN)

Activity 9

add_review_header(doc,'INV/PL3/26/008_09','Review of B1 Notification No. 1000187 and engineering rectification','Verify the engineering assessment, temporary correction, post-rectification performance, and residual risk.','Mr. Arvind Patil') add_subheading(doc,'Investigation Findings') rect=[ ('SAP notification','B1 Notification No. 1000187 was raised for Checkweigher Equipment ID: 100423 following the event.'), ('Engineering inspection','The rejection mechanism, sensor position, and timing parameters were inspected.'), ('Immediate correction','The rejection-mechanism sensor position and timing settings were adjusted/optimized.'), ('Verification','Machine operation was checked after correction and a challenge test was completed satisfactorily.'), ('Residual risk','Sensor/timing adjustment restored immediate function but did not increase physical separation or provide accumulation capacity between the reject-confirmation zone and Track & Trace infeed.'), ('Permanent action required','A controlled line-interface modification with buffer capacity, qualification, procedural update, and effectiveness monitoring is required to prevent recurrence.') ] add_evidence_table(doc,['Review Element','Observation / Action'],rect,[1.65,5.43],font=8) add_status_box(doc,'IMMEDIATE CORRECTION EFFECTIVE','The engineering adjustment was adequate to restore operation and verify checkweigher function before restart.',GREEN,LIGHT_GREEN) add_status_box(doc,'NOT A PERMANENT CAPA','Sensor-position/timing adjustment alone does not eliminate the root cause because a downstream jam can still propagate upstream through the short interface. Permanent buffering and integrated-line controls are required.',ORANGE,LIGHT_ORANGE) add_subheading(doc,'B1 Notification Evidence') pt2=doc.add_table(rows=1,cols=2); pt2.alignment=WD_TABLE_ALIGNMENT.CENTER; pt2.autofit=False set_col_widths(pt2,[3.53,3.53]); set_table_borders(pt2,color='B7C9E2',sz=6) for c in pt2.rows[0].cells: set_cell_margins(c,60,60,60,60) p=pt2.cell(0,0).paragraphs[0]; fmt_para(p,WD_ALIGN_PARAGRAPH.CENTER,after=2); r=p.add_run(); r.add_picture(str(MEDIA/'image12.png'),width=Inches(3.25)) p=pt2.cell(0,0).add_paragraph(); fmt_para(p,WD_ALIGN_PARAGRAPH.CENTER,after=0); add_text(p,'Figure 7.3 - SAP B1 notification details.',bold=True,italic=True,color=GRAY,size=7) p=pt2.cell(0,1).paragraphs[0]; fmt_para(p,WD_ALIGN_PARAGRAPH.CENTER,after=2); r=p.add_run(); r.add_picture(str(MEDIA/'image13.png'),width=Inches(3.25)) p=pt2.cell(0,1).add_paragraph(); fmt_para(p,WD_ALIGN_PARAGRAPH.CENTER,after=0); add_text(p,'Figure 7.4 - Engineering rectification/closure details.',bold=True,italic=True,color=GRAY,size=7)

consolidated conclusion

add_heading_bar(doc,'7.2 CONSOLIDATED INVESTIGATION ASSESSMENT',page_break=True) summary_rows=[ ('Checkweigher weight calculation/settings','Correct and challenge-tested','Ruled out',GREEN,LIGHT_GREEN), ('Personnel training and operator response','Training current; response appropriate','Ruled out',GREEN,LIGHT_GREEN), ('Qualification and preventive maintenance','Within validity and schedule','Ruled out',GREEN,LIGHT_GREEN), ('Batch Packing Record execution','Line clearance, challenges, and IPCs satisfactory','Ruled out',GREEN,LIGHT_GREEN), ('Reject mechanism / line interface','Downstream backup occupied reject-confirmation zone due to short gap','Root cause confirmed',RED,LIGHT_RED), ('Tilted carton at Track & Trace star-wheel','Initiated the jam observed during reproduction','Trigger / contributing factor',ORANGE,LIGHT_ORANGE), ('SOP/challenge scope','Did not test integrated downstream-jam/backpressure condition','Systemic contributing factor',ORANGE,LIGHT_ORANGE), ('History / B1 review','No recent recurring trend; prior sensor event supports stronger controls','Corroborative evidence',BLUE,PALE_BLUE), ('Engineering sensor/timing adjustment','Restored function but did not remove physical interface risk','Temporary correction',BLUE,PALE_BLUE) ] st=doc.add_table(rows=1+len(summary_rows),cols=3); st.alignment=WD_TABLE_ALIGNMENT.CENTER; st.autofit=False set_col_widths(st,[2.1,3.55,1.43]); set_table_borders(st,color='A6B8CE',sz=7) for j,h in enumerate(['Potential Cause / Review Area','Evidence-Based Conclusion','Assessment']): c=st.rows[0].cells[j]; set_cell_shading(c,NAVY); set_cell_margins(c,70,70,70,70) p=c.paragraphs[0]; fmt_para(p,WD_ALIGN_PARAGRAPH.CENTER,after=0); add_text(p,h,bold=True,color=WHITE,size=7.7) set_repeat_table_header(st.rows[0]) for i,(area,conc,status,clr,fill) in enumerate(summary_rows,1): set_row_cant_split(st.rows[i]) for j,val in enumerate([area,conc,status]): c=st.rows[i].cells[j]; set_cell_shading(c,fill if j==2 else (WHITE if i%2 else PALE_BLUE)); set_cell_margins(c,65,70,65,70) p=c.paragraphs[0]; fmt_para(p,WD_ALIGN_PARAGRAPH.LEFT if j<2 else WD_ALIGN_PARAGRAPH.CENTER,after=0) add_text(p,val,bold=(j==2),color=clr if j==2 else BLACK,size=7.6)

Impact

add_heading_bar(doc,'8.0 IMPACT ASSESSMENT',page_break=True) add_finding_paragraph(doc,'The impact assessment was performed against product quality, packaging integrity, traceability, in-process material, equipment control, batch disposition, and patient safety. The conclusion below is based on specific controls and records rather than a standalone statement of "no impact."') impact=[ ('Product / dosage form','The event occurred during secondary packing, after blisters had been formed and sealed. The failure mechanism involved carton transfer and rejection-zone occupancy; it did not alter the tablet formulation or sealed blister contents.','No adverse impact identified on identity, strength, quality, or purity of packed product.'), ('In-process loose tablets','Loose tablets remaining on blister-machine guide tracks, feeding channels, and product-contact areas during the stoppage were removed and handled as per procedure. The camera rejection system and hopper dust extraction were operational.','Potentially exposed loose tablets were controlled and were not allowed to proceed uncontrolled.'), ('Environmental / hold-time exposure','Temperature and relative humidity in the blister-filling area remained within defined limits. Available stability data for the product were reviewed and found satisfactory.','No adverse impact from the stoppage/holding condition was identified.'), ('Carton completeness','Cartons in the reject stream were segregated and physically verified for missing components. Missing components, if any, were restored as per SOP/PG/120, and cartons were re-passed through the checkweigher.','No affected carton was accepted for further processing without verification.'), ('Packaging and coding quality','Routine in-process checks for carton overprinting/coding, blister count (3 x 8), leaflet inclusion, outer-carton quantity, and shipper-label quality were satisfactory.','No packaging-identity or coding defect attributable to the event was identified.'), ('Checkweigher control','Pre-event and post-rectification challenge tests were satisfactory. The event was caused by physical accumulation at the interface, not by an unverified change in weight limits or load-cell classification.','Weight-control function remained demonstrable; affected cartons were reverified.'), ('Finished product quality','Finished-product analytical results for Batch No. 0360093A were reviewed and were within the established acceptance criteria.','No adverse analytical impact was identified.'), ('Patient safety / batch disposition','The line was stopped promptly, affected cartons were retained and reverified, and no evidence showed release of an incomplete or misidentified carton.','No adverse impact on patient safety was identified based on the controls and evidence reviewed.') ] add_evidence_table(doc,['Impact Area','Evidence Reviewed / Control','Conclusion'],impact,[1.35,4.25,1.48],font=7.2) add_status_box(doc,'FINAL IMPACT CONCLUSION','No adverse impact on Batch No. 0360093A was identified with respect to product quality, packaging integrity, coding/traceability, or patient safety. The event was confined to the physical transfer/rejection of secondary packs; affected cartons and in-process materials were controlled, verified, and handled before continuation.',GREEN,LIGHT_GREEN)

Root cause

add_heading_bar(doc,'9.0 ROOT CAUSE AND CONTRIBUTING FACTORS',page_break=True) root_rows=[ ('Direct Technical Root Cause','Insufficient physical separation/buffer between the checkweigher reject-confirmation zone (Equipment ID: 100423) and the Track & Trace star-wheel infeed (Equipment ID: 100358). This allowed a downstream carton jam to propagate upstream into the reject-confirmation zone, disrupting carton spacing and the reject-confirmation sequence.'), ('Event Trigger','A carton leaving the Auto-Cartonator in a tilted/misaligned orientation became stuck at the Track & Trace star-wheel infeed.'), ('Systemic Contributing Factor','SOP/PG/120 and the routine challenge-test approach verified checkweigher performance under free-flow conditions but did not require an integrated-line downstream-jam/backpressure challenge or minimum buffer/clearance verification.'), ('Not Causal','Carton-weight calculation/HMI settings, personnel training, equipment qualification/PM status, BPR execution, and operator response were reviewed and ruled out as causes.') ] add_key_value_table(doc,root_rows,widths=(1.9,5.18)) add_callout(doc,'ROOT-CAUSE STATEMENT','During a Track & Trace infeed jam, the short, unbuffered interface allowed accumulated cartons to enter the checkweigher reject-confirmation zone. The abnormal carton occupancy disrupted the intended rejection sequence, caused acceptable cartons to be diverted with rejects, and generated ERROR-17. The permanent corrective strategy must therefore isolate the checkweigher reject zone from downstream accumulation, not merely readjust the sensor.',fill=LIGHT_RED,border=RED)

CAPA

add_heading_bar(doc,'10.0 CORRECTIVE AND PREVENTIVE ACTIONS',page_break=True) add_subheading(doc,'10.1 Corrections / Corrective Actions Completed') ca=[ ('1','B1 Notification No. 1000187 raised in SAP; Engineering inspected the rejection mechanism, sensor position, and timing.','Engineering - Mr. Arvind Patil','Completed'), ('2','Rejection-mechanism sensor position and timing were adjusted; machine operation and challenge performance were verified satisfactory before restart.','Engineering / Production / QA','Completed'), ('3','All cartons in the affected reject stream were segregated, physically verified for missing components, corrected if required, and re-passed through the checkweigher in accordance with SOP/PG/120.','Production - Mr. Pavan Badgujar','Completed'), ('4','Loose tablets remaining on the blister packing machine during the stoppage were removed and handled as per the applicable procedure.','Production','Completed') ] add_evidence_table(doc,['No.','Action','Responsibility','Status / TCD'],ca,[0.4,4.7,1.25,0.73],font=7.2)

add_subheading(doc,'10.2 Preventive Actions / Permanent CAPA') pa=[ ('1','Raise and execute a formal change control for installation of a buffer conveyor/adequate accumulation section between the checkweigher reject-confirmation zone and the Track & Trace infeed. The change shall include mechanical layout, carton-guide alignment, risk assessment, and updated line drawing.','Engineering - Mr. Arvind Patil','30/09/2026'), ('2','After modification, perform documented engineering/qualification verification at minimum, routine, and maximum approved line speeds. Include good/underweight/overweight challenges and a controlled downstream-stoppage/backpressure simulation to confirm that cartons cannot accumulate in the reject-confirmation zone.','Engineering / Production / QA','Before release for routine use'), ('3','Revise SOP/PG/120 and the line-start/changeover checklist to include: interface-clearance check, guide/star-wheel alignment, carton-squareness observation, response to ERROR-17, and inspection after any downstream jam.','Production / QA','Before routine use after modification'), ('4','Train all relevant Production, Engineering, and QA personnel on the revised procedure and documented jam-response requirements.','Production / QA','Before effective date of revised SOP'), ('5','Perform an effectiveness check over the first three consecutive batches after CAPA implementation. Acceptance criteria: no acceptable carton falsely rejected due to downstream backup; no ERROR-17 attributable to interface accumulation; all routine challenges pass.','Production / Engineering / QA','After first 3 consecutive batches') ] add_evidence_table(doc,['No.','Preventive Action','Responsibility','TCD / Milestone'],pa,[0.38,4.72,1.22,0.76],font=6.9)

add_subheading(doc,'10.3 CAPA Effectiveness Criteria') for txt in [ 'No carton accumulation reaches or blocks the reject-confirmation sensor during normal operation or a controlled downstream stop.', 'No acceptable carton is diverted into the reject bin due to Track & Trace infeed backup.', 'ERROR-17 is not generated from interface accumulation during the effectiveness-monitoring period.', 'All pre-start and post-maintenance challenge tests pass at approved operating speeds.', 'No recurrence is observed in the first three consecutive batches after implementation.' ]: add_bullet(doc,txt)

Final conclusion

add_heading_bar(doc,'11.0 FINAL INVESTIGATION CONCLUSION',page_break=True) add_callout(doc,'CONCLUSION','The investigation confirmed that the event was not caused by incorrect weight settings, untrained personnel, overdue maintenance, failed qualification, or non-compliance with the Batch Packing Record. A tilted carton jammed at the Track & Trace star-wheel and, because the checkweigher reject-confirmation zone was installed with insufficient downstream buffer, the carton queue propagated upstream into the rejection area. This abnormal occupancy disrupted the rejection-confirmation sequence, allowed acceptable cartons to enter the reject stream, and generated ERROR-17. Sensor/timing adjustment restored immediate operation; permanent recurrence prevention requires a controlled buffer/interface modification, integrated-line verification, procedural revision, training, and effectiveness monitoring. Based on segregation, physical verification, re-passing of cartons, satisfactory environmental and in-process controls, and acceptable finished-product results, no adverse impact on Batch No. 0360093A or patient safety was identified.',fill=PALE_BLUE,border=NAVY)

Approval

add_heading_bar(doc,'12.0 APPROVAL',page_break=True) approval=[ ('Investigation Done / Reviewed By','Production - Investigation Team Lead','','',''), ('','Production - Initiator Department HOD','','',''), ('','Production - Investigation Team Member','','',''), ('','Engineering - Investigation Team Member','','',''), ('','Quality Assurance - Investigation Team Member','','',''), ('','Quality Assurance - Investigation Team Member','','',''), ('Approved By','Head - Quality Assurance','','','') ] at=doc.add_table(rows=1+len(approval),cols=5); at.alignment=WD_TABLE_ALIGNMENT.CENTER; at.autofit=False set_col_widths(at,[1.45,2.4,1.05,1.05,1.13]); set_table_borders(at,color='A6B8CE',sz=7) for j,h in enumerate(['Role','Department','Name','Designation','Sign & Date']): c=at.rows[0].cells[j]; set_cell_shading(c,NAVY); set_cell_margins(c,75,70,75,70) p=c.paragraphs[0]; fmt_para(p,WD_ALIGN_PARAGRAPH.CENTER,after=0); add_text(p,h,bold=True,color=WHITE,size=7.8) set_repeat_table_header(at.rows[0]) for i,row in enumerate(approval,1): set_row_cant_split(at.rows[i]); at.rows[i].height=Inches(0.52); at.rows[i].height_rule=WD_ROW_HEIGHT_RULE.AT_LEAST for j,val in enumerate(row): c=at.rows[i].cells[j]; set_cell_shading(c,PALE_BLUE if j==0 and val else WHITE); set_cell_margins(c,70,70,70,70) p=c.paragraphs[0]; fmt_para(p,WD_ALIGN_PARAGRAPH.LEFT if j<2 else WD_ALIGN_PARAGRAPH.CENTER,after=0) add_text(p,val,bold=(j==0 and bool(val)),color=NAVY if j==0 else BLACK,size=7.5)

Save

Update core properties

props=doc.core_properties props.title='Final Investigation Report - INV/PL3/26/008' props.subject='Checkweigher false rejection and ERROR-17 investigation' props.author='Cross-functional Investigation Team' props.keywords='Investigation, Checkweigher, Track and Trace, ERROR-17, CAPA'

doc.save(OUT) print(OUT) PY python /mnt/data/build_final_report.py

Rendering and Inspection Process

I need to make sure that every page is properly rendered and reviewed for consistency. Each element—like tables, images, and text—needs inspection to ensure everything aligns as intended. This step will help me confirm that everything is accurate and looks professional before finalizing.

bash -lc rm -rf /mnt/data/final_render && python /home/oai/skills/docx/render_docx.py /mnt/data/Final_Investigation_Report_INV_PL3_26_008.docx --output_dir /mnt/data/final_render --emit_pdf

Inspecting and finalizing

I need to inspect everything thoroughly, checking the page count to make sure it's accurate. Creating a contact table or section might be a good idea as well. This will help wrap up the report neatly and make sure all the essential details are included before finalizing.

bash -lc ls -1 /mnt/data/final_render/page-.png | wc -l && python - <<'PY' from PIL import Image,ImageDraw import glob,os,math files=sorted(glob.glob('/mnt/data/final_render/page-.png'), key=lambda x:int(os.path.basename(x).split('-')[1].split('.')[0])) thumbs=[] for f in files: im=Image.open(f).convert('RGB') im.thumbnail((300,424)) c=Image.new('RGB',(320,460),'white'); c.paste(im,((320-im.width)//2,25)) ImageDraw.Draw(c).text((8,6),os.path.basename(f),fill='black') thumbs.append(c) cols=4; rows=math.ceil(len(thumbs)/cols) out=Image.new('RGB',(cols320,rows460),(220,220,220)) for i,c in enumerate(thumbs): out.paste(c,((i%cols)*320,(i//cols)*460)) out.save('/mnt/data/final_render/contact.png') PY

Opening contact section

I need to create or open a contact section, potentially to list essential details or provide a way for users to reach out. This could further enhance the document and make sure that everything is easy to navigate. Let's ensure all contact information is properly organized and presented clearly.Refining layout and spacing for clarity

The document has quite a bit of whitespace due to page breaks, though it might be acceptable for the formal report style. Pages like 6, 13, and 23 look sparse, which isn't ideal. I could adjust the layout by moving content or shrinking images. For example, I could combine sections or fix overflow issues to reduce unnecessary space and improve visual appeal. I'll make these adjustments for a cleaner presentation.Refining pages for clarity

Page 4 is clean, but I'm not sure about Page 5. It might need more adjustment. Could there be some formatting or content that needs better organization or alignment? I'll take a closer look and decide whether to tweak anything to improve consistency across the pages.Improving page layout and breaks

Page 5 looks good, but the conclusion ends up on Page 6. Moving the conclusion before Image 4 or shrinking the image could help. Page 6 has too much whitespace because of the large red box and the page break before the "Why-why" content. I'll adjust the breaks to improve the flow, similarly for Page 13.Refining page breaks and table layout

The approval table could fit across both pages 23 and 24, potentially avoiding a page break before approval. However, splitting signatures is less ideal. Keeping a page break for the table might work better. For the final conclusion, it's fine to keep it separate. I'll inspect Page 6 for text formatting.Adjusting page breaks and script

We need to fix the page breaks, particularly on page 7 where the entire "why-why" content is placed. I could move that to start on page 6 instead. I also need to inspect pages 12 and 13 for any issues that might affect the layout. Let's modify the script accordingly.Adjusting layout for page12 and page13

On page 12, there might be one bullet missing due to physical separation, and the status box starts on page 13. I could try reducing the image width or bullet size, or maybe move the status box before the figure. Shrinking the figure from 6.45 to 5.7 and adjusting the bullet font to 8.5 should help. Alternatively, skipping a page break between Activity5 and the status box might work. I also need to ensure the root cause box isn't isolated.Fixing page breaks and script adjustments

I need to adjust the page breaks for page 13 by removing the break before Activity 5. On page 6, I could eliminate the break before Gemba, as well as for consolidated, impact, root cause, and CAPA. These changes involve updating the script with simple adjustments for specific calls, such as removing unnecessary page breaks for certain sections. I'll also tweak the layout for Activity 9 and page 19 for consistency.

bash -lc python - <<'PY' p='/mnt/data/build_final_report.py' s=open(p).read() s=s.replace("def add_review_header(doc, activity_no, activity, objective, responsibility):\n doc.add_page_break()", "def add_review_header(doc, activity_no, activity, objective, responsibility, page_break=True):\n if page_break:\n doc.add_page_break()") s=s.replace("add_heading_bar(doc,'5.0 GEMBA WALK (GO AND SEE)',page_break=True)", "add_heading_bar(doc,'5.0 GEMBA WALK (GO AND SEE)',page_break=False)") s=s.replace("add_heading_bar(doc,'6.0 WHY-WHY ANALYSIS',page_break=True)", "add_heading_bar(doc,'6.0 WHY-WHY ANALYSIS',page_break=False)") s=s.replace("add_review_header(doc,'INV/PL3/26/008_05','Review of Batch Packing Record", "add_review_header(doc,'INV/PL3/26/008_05','Review of Batch Packing Record")

Above replacement breaks args; undo with specific full line fix below

bad="add_review_header(doc,'INV/PL3/26/008_05','Review of Batch Packing Record') for Lonart 20/120 AQCOAT Tablets, Batch No. 0360093A','Verify that approved secondary-packing instructions, line clearance, setup, challenge tests, and in-process controls were followed.','Mr. Shyamkant Patil')"

In case malformed replacement happened, rebuild exact line via simpler search on line starts

lines=s.splitlines() for i,line in enumerate(lines): if line.startswith("add_review_header(doc,'INV/PL3/26/008_05'"): lines[i]="add_review_header(doc,'INV/PL3/26/008_05','Review of Batch Packing Record for Lonart 20/120 AQCOAT Tablets, Batch No. 0360093A','Verify that approved secondary-packing instructions, line clearance, setup, challenge tests, and in-process controls were followed.','Mr. Shyamkant Patil',page_break=False)" s='\n'.join(lines)+'\n' s=s.replace("add_heading_bar(doc,'8.0 IMPACT ASSESSMENT',page_break=True)", "add_heading_bar(doc,'8.0 IMPACT ASSESSMENT',page_break=False)") s=s.replace("add_heading_bar(doc,'10.0 CORRECTIVE AND PREVENTIVE ACTIONS',page_break=True)", "add_heading_bar(doc,'10.0 CORRECTIVE AND PREVENTIVE ACTIONS',page_break=False)") open(p,'w').write(s) PY python -m py_compile /mnt/data/build_final_report.py python /mnt/data/build_final_report.py

bash -lc rm -rf /mnt/data/final_render2 && python /home/oai/skills/docx/render_docx.py /mnt/data/Final_Investigation_Report_INV_PL3_26_008.docx --output_dir /mnt/data/final_render2 --emit_pdf

bash -lc ls -1 /mnt/data/final_render2/page-.png | wc -l && python - <<'PY' from PIL import Image,ImageDraw import glob,os,math files=sorted(glob.glob('/mnt/data/final_render2/page-.png'), key=lambda x:int(os.path.basename(x).split('-')[1].split('.')[0])) thumbs=[] for f in files: im=Image.open(f).convert('RGB'); im.thumbnail((300,424)) c=Image.new('RGB',(320,460),'white'); c.paste(im,((320-im.width)//2,25)); ImageDraw.Draw(c).text((8,6),os.path.basename(f),fill='black'); thumbs.append(c) cols=4; rows=math.ceil(len(thumbs)/cols) out=Image.new('RGB',(cols320,rows460),(220,220,220)) for i,c in enumerate(thumbs): out.paste(c,((i%cols)*320,(i//cols)*460)) out.save('/mnt/data/final_render2/contact.png') PY

Inspecting pages for consistency and quality

I need to check the page layout and content consistency across pages 1-21. Specifically, pages 3, 5, 6, 18, and 19 need attention. I'll inspect each page closely—either through contact sheets or individual page openings—and use visual review. Automated image checks could help, but I'll also manually inspect each page.

Inspecting pages one by one

I can open each page individually for inspection, even though it might take some time. It’s a bit tedious, but I think it's okay. Let's start by inspecting page 1 first and go from there, proceeding one page at a time.Inspecting pages

I've inspected page 1, and it's clean. Now, let's move on to inspecting page 2. We'll continue checking each page as needed to ensure everything looks good.Inspecting page 3

Page 2 is clean, so now I need to inspect page 3. I'll check through it carefully to ensure everything is in order!Inspecting page 4

Page 3 is clean, but now I need to check page 4. It looks like it might be a continuation or include photos, so I'll open it up to confirm and ensure everything's in place.Continuing to inspect pages 5-21

I still need to inspect the remaining pages. I could try opening them in batches, but since individual images are necessary, I’ll continue reviewing each page one-by-one. 3-page composites at original width might be too large, so I'll stick with scaling images for easier inspection. Let’s keep going with pages 5-21.Reviewing pages 5-6 layout issues

On page 5, the bottom status box is clipped, but it’s fine, as the table row splits across pages. Still, the “WHY-WHY OUTPUT” row’s text cuts off and continues onto page 6. I'll adjust the layout to prevent row splits in status boxes or callouts. We’ll move the entire status box to page 6 if needed. I'll inspect page 6 next.Fixing page6 layout and preparing for page7

Page 6 needs a fix for the top row split, so I’ll set "can't split" there. There's also unnecessary whitespace due to the page break before “DETAILED REVIEW” on page 7. I’ll remove that break to ensure the heading and plan fit on page 6. After this, I’ll check for other callouts that might be splitting, making sure to apply "can't split" to all. I'll review pages 7-21 for layout changes after.Examining layout on page8

Page 7 looks clean, though there’s some whitespace. Moving the plan to page 6 might cause it to split across pages 6 and 7, but I think that’s okay. I’ll need to inspect page 8 next to ensure the layout is consistent and there are no further issues.Reviewing page9 layout

Page 8 looks clean, so now I’ll need to inspect page 9 next. It’s important to make sure everything flows well and there aren’t any unexpected layout issues cropping up as I move through the pages. Looking forward to checking it out.Inspecting pages 10-21 sequentially

Page 9 looks fine, so now I can start inspecting pages 10 through 21 to make sure everything is properly aligned and that there are no splits. I might do this by opening them one by one in sequence so I can visually inspect each. Let’s keep working through this!Continuing work

It looks like there's enough for me to continue. Going forward, I’ll keep moving with my inspection process and make sure to check each part carefully. I’ll stay focused and stay on top of whatever issues pop up as I make my way through these next steps.Continuing work on page 12

I'll keep going and inspect the remainder of the document. I’ll focus on layout and any issues that arise on page 12. This will help ensure everything aligns and there are no unexpected problems. I'll adjust for consistency as I progress.Moving forward, inspecting page 13

Page 12 looks good. Activity 5 neatly begins after the status section, which is fine. Next, I need to inspect page 13. I'll look for any layout or content issues and adjust details if needed. Let's make sure it flows as smoothly as possible.Moving to page 14

Page 13 looks clean, so now I can move on to inspecting page 14. I’ll need to ensure everything is properly laid out and check for any potential issues. We'll keep things smooth and make sure everything flows correctly. Let’s keep going!Working through page 15

I’m moving on to page 15 now. I’ll check over everything to make sure it’s neat and consistent. Let me ensure all details are aligned as planned while keeping it visually cohesive. Let’s continue and keep things on track with this page too!Inspecting pages 16-21

I need to check pages 16 through 21 now, making sure everything is in place. I'll go over them carefully, looking for any inconsistencies or areas that need adjustment. After that, I can move forward with the next steps, ensuring everything's neat and organized.Continuing with page 17

I’m moving on to page 17 now. I’ll carefully check it for any issues or adjustments that might be needed. Once I finish reviewing this page, I’ll be able to proceed further. Hope it’s all looking clean and in order, but I’ll make sure!Moving to page 18

Okay, page 17 looks good, so now I’ll move on to page 18. I’ll make sure everything is clear and in order on this page too. Just need to stay focused and double-check for anything that might need refinement! Hopefully, it's as smooth as the previous page.Reviewing page 19

Page 18 looks good overall, but I've noticed the preventive table splits at the row boundaries. Still, it's functioning fine. Now, on to page 19. I’ll check it carefully to see how things are organized and fix any issues along the way! Keeping the momentum going!Finalizing page layout adjustments

Page 19 has some whitespace, but it's fine. To save space, I could move the final conclusion to page 19 by removing the page break. This would allow the conclusion heading and callout to fit naturally under the bullets on page 19. Page 20 would then just have the approval section. I'll clean up page 20 next and finalize!Planning final adjustments

I need to ensure the callout/status isn't split, and that the detailed review and final conclusion stay together without page breaks. Maybe move the page 5 status to page 6 and start the detailed review there. I'll check pages 19 and 20 once rendered. Also, I'll adjust settings, like add_heading_bar for page breaks. Time to patch!

bash -lc python - <<'PY' p='/mnt/data/build_final_report.py' s=open(p).read() s=s.replace(" c0, c1 = t.rows[0].cells\n", " set_row_cant_split(t.rows[0])\n c0, c1 = t.rows[0].cells\n", 1)

The above only patched first occurrence (add_callout). Patch add_status_box separately by marker.

old="def add_status_box(doc, status, summary, status_color, fill):\n t = doc.add_table(rows=1, cols=2)\n t.alignment = WD_TABLE_ALIGNMENT.CENTER\n t.autofit = False\n set_col_widths(t, [1.45, 5.63])\n set_table_borders(t, color=status_color, sz=8)\n c0,c1=t.rows[0].cells" new="def add_status_box(doc, status, summary, status_color, fill):\n t = doc.add_table(rows=1, cols=2)\n t.alignment = WD_TABLE_ALIGNMENT.CENTER\n t.autofit = False\n set_col_widths(t, [1.45, 5.63])\n set_table_borders(t, color=status_color, sz=8)\n set_row_cant_split(t.rows[0])\n c0,c1=t.rows[0].cells" s=s.replace(old,new) s=s.replace("add_heading_bar(doc,'7.0 DETAILED INVESTIGATION REVIEW',page_break=True)", "add_heading_bar(doc,'7.0 DETAILED INVESTIGATION REVIEW',page_break=False)") s=s.replace("add_heading_bar(doc,'11.0 FINAL INVESTIGATION CONCLUSION',page_break=True)", "add_heading_bar(doc,'11.0 FINAL INVESTIGATION CONCLUSION',page_break=False)") open(p,'w').write(s) PY python -m py_compile /mnt/data/build_final_report.py python /mnt/data/build_final_report.py

Checking patch accuracy

I need to make sure the add_callout patch didn't affect the wrong section. I'll verify by checking the snippet thoroughly to confirm everything is in the right place, and that no unintended changes were made. It's always a good idea to double-check before finalizing!

bash -lc grep -n "def add_callout|def add_status_box|set_row_cant_split(t.rows00)|7.0 DETAILED|11.0 FINAL" /mnt/data/build_final_report.py | head -20

Checking line170 and add_callout

I think the issue might be with setting set_row_cant_split at line 170, probably in add_numbered, not add_callout. I need to inspect add_callout to confirm if it's working correctly or if something went wrong there. I'll double-check to be sure!

bash -lc sed -n '210,255p' /mnt/data/build_final_report.py

Handling split callout manually

I need to manually add the “cant split” to the callout. Line 170 was already added elsewhere, so it's harmless; no issues there. I'll go ahead with this patch now to make sure everything is in place.

bash -lc python - <<'PY' p='/mnt/data/build_final_report.py' s=open(p).read() old=" set_col_widths(t, [1.45, 5.63])\n set_table_borders(t, color=border, sz=8)\n c0, c1 = t.rows[0].cells" new=" set_col_widths(t, [1.45, 5.63])\n set_table_borders(t, color=border, sz=8)\n set_row_cant_split(t.rows[0])\n c0, c1 = t.rows[0].cells" s=s.replace(old,new,1) open(p,'w').write(s) PY python -m py_compile /mnt/data/build_final_report.py python /mnt/data/build_final_report.py

Rendering final version

It's time to render the final version. I'll make sure everything looks good and is properly formatted. Looking over the work one last time to ensure everything aligns. Then, we can wrap things up!

bash -lc rm -rf /mnt/data/final_render3 && python /home/oai/skills/docx/render_docx.py /mnt/data/Final_Investigation_Report_INV_PL3_26_008.docx --output_dir /mnt/data/final_render3 --emit_pdf

Inspecting count and problematic pages

I need to take a close look at the page count and any pages that might be causing problems. It’s important to ensure everything aligns properly. I’ll make sure there are no issues and everything is in order before moving forward.

bash -lc ls -1 /mnt/data/final_render3/page-.png | wc -l && python - <<'PY' from PIL import Image,ImageDraw import glob,os,math files=sorted(glob.glob('/mnt/data/final_render3/page-.png'), key=lambda x:int(os.path.basename(x).split('-')[1].split('.')[0])) thumbs=[] for f in files: im=Image.open(f).convert('RGB'); im.thumbnail((300,424)) c=Image.new('RGB',(320,460),'white'); c.paste(im,((320-im.width)//2,25)); ImageDraw.Draw(c).text((8,6),os.path.basename(f),fill='black'); thumbs.append(c) cols=4; rows=math.ceil(len(thumbs)/cols) out=Image.new('RGB',(cols320,rows460),(220,220,220)) for i,c in enumerate(thumbs): out.paste(c,((i%cols)*320,(i//cols)*460)) out.save('/mnt/data/final_render3/contact.png') PY

Inspecting pages for accuracy

I’ve noticed that page 5 ends with "Why5," and that page 6 covers the detailed review and plan. Page 18 combines CAPA rest and conclusion, while page 19 focuses on approval. I need to check pages 5, 6, 17-19 closely as these are where the changes occurred.Reviewing page 5

Page 5 looks good, no issues with splitting. Now, I’ll move on to checking Page 6.Reviewing pages 18 and 19

I need to inspect pages 18 and 19 to ensure everything is final and complete. Once I do that, I’ll be able to wrap up the review process.Finalizing pages 18 and 19

Page 18 looks good, and I’m expecting page 19 to be approved in much the same way. It seems things are on track, so I'll consider that section pretty much done unless anything major comes up.Verifying final report and possible edits

It seems like the final report is ready, but it wouldn't hurt to open the document and verify its accessibility. I’ll check for any gross spelling issues or old typos like "chechweigher" and "AQCOAT." I'll review the sections marked for revision and possibly update grammar in the root cause and why. For clarity, I'd change "no impact" to "No adverse impact." I'll also ensure the review includes all points and update the file citation if needed.

Thought for 13m 2s

Réponse

The investigation report has been fully revised based on the uploaded draft. (Draft_Investigation_Report_final.docx)

Key updates include:

  • Completed and properly structured all nine investigation review points, including the previously missing BPR, SOP, and personnel-discussion reviews.
  • Expanded the Why-Why analysis to five levels and clearly separated the direct root cause, event trigger, and systemic contributing factor.
  • Added a clear explanation that the detailed investigation continued after the Why-Why analysis to verify the probable root cause with evidence and rule out competing causes.
  • Redesigned the Gemba Walk section with an observation sequence, evidence tables, photographs, failure-reproduction steps, and a clear Gemba conclusion.
  • Replaced repetitive “no impact” statements with an evidence-based impact assessment covering product quality, exposed material, carton completeness, coding, analytical results, batch disposition, and patient safety.
  • Corrected investigation numbering, B1 notification references, technical terminology, grammar, and inconsistencies.
  • Clarified that sensor-position and timing adjustment was an immediate correction, not a permanent CAPA.
  • Expanded preventive actions to include change control, buffer installation, qualification, SOP revision, training, and effectiveness monitoring.

Download the final investigation report

Partager cette Q&R