"""Front matter and chapters 1-6."""
from pathlib import Path

from helpers import Builder, ACCENT, MUTED, WARN, OK, INFO
import facts as F


def front_matter(b: Builder, docx_name: str) -> None:
    if not b.dry:
        d = b.doc
        for _ in range(3):
            d.add_paragraph()
        p = d.add_paragraph()
        p.alignment = 1
        r = p.add_run("KELUARGAMART")
        r.font.size = __import__("docx").shared.Pt(34)
        r.bold = True
        r.font.color.rgb = ACCENT
        p = d.add_paragraph()
        p.alignment = 1
        r = p.add_run("Monorepo Complete Documentation")
        r.font.size = __import__("docx").shared.Pt(24)
        r.bold = True
        p = d.add_paragraph()
        p.alignment = 1
        r = p.add_run("Technical, Operational and Business Reference")
        r.font.size = __import__("docx").shared.Pt(14)
        r.font.color.rgb = MUTED
        d.add_paragraph()
        p = d.add_paragraph()
        p.alignment = 1
        r = p.add_run("Evidence-based audit of the repository at commit "
                      f"{F.COMMIT_SHORT}")
        r.font.size = __import__("docx").shared.Pt(11)
        r.italic = True

    meta = [
        ("Product", "KeluargaMart — retail, distribution and wholesale omnichannel platform"),
        ("Document title", "KeluargaMart Monorepo — Complete Documentation"),
        ("Document version", F.DOC_VERSION),
        ("Audited commit", f"{F.COMMIT} ({F.BRANCH})"),
        ("Commit date", F.COMMIT_DATE),
        ("Generation date", F.AUDIT_DATE),
        ("Document status", "Final — verified against source, migrations and a live instance"),
        ("Classification", "Internal — contains no credentials, but describes internal topology"),
        ("Prepared by", "Automated repository audit (Principal Architect / Backend / Frontend / DBA / DevOps / QA review)"),
        ("Maintenance owner", "Not verified — no CODEOWNERS mapping resolves to a named team for docs/"),
    ]
    b.table(["Field", "Value"], [[k, v] for k, v in meta],
            caption="Document control block", widths=[1.6, 4.9])

    b.h1("Revision history", page_break=True)
    b.table(["Version", "Date", "Change", "Basis"],
            [["1.0.0", F.AUDIT_DATE,
              "Initial complete audit and reference document",
              f"Repository at {F.COMMIT_SHORT}; migrations applied to PostgreSQL 16; "
              "backend executed locally; all test suites executed"]],
            caption="Revision history", widths=[0.8, 1.0, 2.4, 2.3])

    b.h1("How to read this document", page_break=True)
    b.p("This document reconstructs the system from its source code, migrations, "
        "configuration, tests and a locally executed instance. It is not a design "
        "proposal. Every substantive claim is labelled with one of the following "
        "evidence classes, and the labels are used consistently throughout.")
    b.table(
        ["Label", "Meaning", "How it was established"],
        [
            ["Verified implementation",
             "Behaviour directly supported by code, schema or configuration in the repository.",
             "Read the file; path and symbol cited."],
            ["Verified runtime behaviour",
             "Behaviour observed while executing the system during this audit.",
             "Command executed against an isolated PostgreSQL 16 database and a locally started backend; output recorded in the text."],
            ["Inferred behaviour",
             "A reasonable reading of the implementation that was not exercised end to end.",
             "Code path read, but no runtime observation."],
            ["Documented intention",
             "Stated in repository documentation but not confirmed in code.",
             "Existing docs cited; contradicted or unconfirmed claims flagged."],
            ["Missing implementation",
             "Referenced or expected behaviour that does not exist.",
             "Absence verified by search plus a failing runtime check."],
            ["Unverified",
             "Evidence is insufficient for a reliable conclusion.",
             "Named explicitly with the missing evidence."],
            ["Recommendation",
             "A proposed change. Never presented as current behaviour.",
             "Derived from a finding; recorded in chapter 38."],
        ],
        caption="Evidence classes used in this document",
        widths=[1.35, 2.55, 2.6], font_size=8.0)

    b.p("Code excerpts are shown in a monospaced face. File paths are repository-relative "
        "and were valid at the audited commit. Where a path in the repository's own "
        "documentation is wrong, the document shows the real path and records the "
        "discrepancy (see finding F-02).")

    b.h1("Table of contents", page_break=True)
    b.p("Every entry below is an internal hyperlink with a measured page number, so the "
        "document is navigable the moment it opens. The heading styles are real Word "
        "headings, so the navigation pane also lists the full hierarchy (including "
        "level-3 headings that are omitted here for length). Page numbers were measured "
        "by rendering the document to PDF with LibreOffice; if you edit the text, page "
        "numbers can shift by a page until the document is rebuilt.",
        italic=True, size=9, color=MUTED)
    b.toc(getattr(b, "planned_toc", None))

    b.h1("List of figures", page_break=True)
    b.p("Figure numbers are sequential in document order. Captions are also embedded "
        "under each figure, so this list stays usable if pagination changes.",
        italic=True, size=9, color=MUTED)
    planned_figs = getattr(b, "planned_figures", []) or []
    if planned_figs:
        b.table(["Figure", "Title"],
                [[n, c] for n, c in planned_figs],
                caption="Figures in this document", widths=[0.8, 5.7], font_size=7.8)
    else:
        b.p("(Populated on the second build pass.)", italic=True, size=9, color=MUTED)

    b.h1("List of tables", page_break=True)
    b.p("Tables include inventories, matrices and configuration references. Wide "
        "inventories (data dictionary, API index, route index) are set in landscape "
        "sections and split by domain so no row is clipped.",
        italic=True, size=9, color=MUTED)
    planned_tabs = getattr(b, "planned_tables", []) or []
    if planned_tabs:
        b.table(["Table", "Caption"],
                [[n, c] for n, c in planned_tabs],
                caption="Tables in this document", widths=[0.8, 5.7], font_size=7.2)
    else:
        b.p("(Populated on the second build pass.)", italic=True, size=9, color=MUTED)

    b.h1("Abbreviations", page_break=True)
    b.table(
        ["Term", "Meaning"],
        [
            ["AO / EC / NOO", "Order source labels: Office, sales-visit (E-Call), New Outlet Order. Parallel labels, not lifecycle stages."],
            ["COA", "Chart of Accounts"],
            ["CO / checkout", "Checkout. Not a separate document type."],
            ["DO", "Delivery Order (Surat Jalan)"],
            ["GR", "Goods Receipt"],
            ["HPP / LHPP", "Harga Pokok Penjualan / Laporan Hasil Penjualan & Piutang — cost-of-goods and route settlement documents"],
            ["KVM", "Kernel-based Virtual Machine (the Hostinger VPS virtualisation)"],
            ["PO", "Purchase Order"],
            ["POS", "Point of Sale"],
            ["RBAC", "Role-Based Access Control"],
            ["RLS", "Row-Level Security (PostgreSQL feature; not used by this schema — see chapter 16)"],
            ["SO", "Sales Order"],
            ["SPA", "Single Page Application"],
            ["SSR", "Server-Side Rendering (Nuxt/Nitro)"],
            ["WIB", "Waktu Indonesia Barat (UTC+7), the business timezone"],
        ],
        caption="Abbreviations", widths=[1.5, 5.0])


def ch1_exec(b: Builder) -> None:
    b.h1("1. Executive summary")
    b.p("KeluargaMart is a five-application monorepo: a Go REST API that owns every "
        "business rule, two Vue 3 single-page applications (back-office ERP and a "
        "cashier POS), a Nuxt 4 server-rendered wholesale storefront, and a Node/Chromium "
        "report renderer. A pnpm workspace plus Turborepo ties them together, and five "
        "small shared packages carry the route list, the permission list, formatting "
        "helpers, an HTTP wrapper and a set of design tokens.")

    b.h2("1.1 What was verified")
    b.bullets([
        f"{F.COUNTS['api_operations']} method-routed HTTP operations are mounted and the "
        f"same {F.COUNTS['api_operations']} appear in the OpenAPI contract — the two sets are "
        "equal, verified by parsing both and diffing (and by the repository's own "
        "TestMountedRoutesMatchOpenAPI). Two further routes, /reports/render and "
        "/reports/preview, are mounted with HandleFunc and therefore sit outside both sets "
        "(finding F-24).",
        f"{F.COUNTS['permission_keys']} permission keys in {F.COUNTS['permission_groups']} "
        "catalogue groups are the single source for RBAC, and the generated client key list "
        "matches it exactly (pnpm drift:check passes). The client ROLES array does not match "
        "the backend role set (F-08), and 76 keys have no holder after a clean migration "
        "(F-22).",
        f"{F.COUNTS['tables_from_migrations']} tables are created by the "
        f"{F.COUNTS['sql_migrations']} migrations, and the migration runner adds "
        f"schema_migrations on first boot — {F.COUNTS['tables']} base tables and "
        f"{F.COUNTS['columns']} columns in the running database, with "
        f"{F.COUNTS['foreign_keys']} declared foreign keys, "
        f"{F.COUNTS['indexes']} indexes, {F.COUNTS['check_constraints']} check constraints "
        "and two enforcing triggers.",
        f"All {F.COUNTS['go_tests_passed']} Go tests pass ({F.COUNTS['go_tests_skipped']} skip "
        f"by design) and all {F.COUNTS['js_tests']} JavaScript tests pass across eight "
        "workspace packages, when run against a real database.",
        "A POS sale was executed end to end against the running backend: order created, "
        "stock deducted, invoice auto-issued, payment recorded, and an idempotent replay "
        "returned the same response while a conflicting payload returned 409.",
    ])

    b.h2("1.2 What the system actually is")
    b.p("The backend is a modular monolith: 35 packages under apps/backend/internal, "
        "one chi router in cmd/server/main.go, and sqlc-generated pgx queries (531 named "
        "queries across 24 .sql files) for the older modules plus hand-written SQL for the "
        "newest ones. Authorisation is a two-axis model — role/glob permissions on one "
        "axis and an application-access scope on the other — with a per-user JSON override "
        "that can both grant and deny.")
    b.p("Money is NUMERIC(15,2) and handled with shopspring/decimal; quantities are "
        "NUMERIC(12,4) with per-line conversion factors snapshotted at sale time. Document "
        "numbers come from one atomic upsert table (document_number_sequences) keyed by "
        "prefix and date, replacing the Laravel COUNT()+1 scheme that could collide.")
    b.note("Important structural fact",
           "The outlet is the tenancy boundary. stores.warehouse_id binds each outlet to "
           "exactly one warehouse, sales_orders.store_id records the origin, and every "
           "scoped service resolves the caller's store list from store_users before it "
           "touches stock, shifts or orders.", "verified")

    b.h2("1.3 Highest-risk findings")
    b.table(
        ["ID", "Severity", "Finding", "Why it matters"],
        [
            ["F-22", "High", "Launch-reset migration left 76 of 201 permission keys unheld by any role",
             "On a fresh deployment only admin/owner can create products, read financial reports, administer users or deliver orders."],
            ["F-03", "High", "CI pins Go 1.24 while go.mod requires 1.26.5",
             "The backend quality gate cannot build; every PR would fail or silently skip the build step."],
            ["F-05", "High", "Integration tests TRUNCATE 66 tables when consent is given",
             "A single mis-pointed DATABASE_URL destroys business data. The repository's own comment records this happening once."],
            ["F-14", "Medium", "ERP mints a random Idempotency-Key for unmigrated writes",
             "Double submission of money forms is not actually protected on those call sites."],
            ["F-07", "Medium", "SMTP_FROM is never read from the environment",
             "Password-reset mail leaves with an empty From header and is rejected or spam-filed."],
            ["F-17", "Medium", "POS has no offline queue, despite documentation claiming one",
             "A cashier may believe sales survive a network drop; they do not."],
            ["F-10", "Medium", "Two compose stacks disagree on Postgres version and ports",
             "Following the wrong runbook yields a stack that does not match the tunnel ingress."],
        ],
        caption="Highest-severity findings (full register in chapter 38)",
        widths=[0.55, 0.7, 2.35, 2.9], font_size=8.0)

    b.h2("1.4 Scope boundary of this document")
    b.p("This audit read the repository and executed it locally. It did not connect to "
        "any production database, did not deploy, and did not modify the working tree "
        "except to add documentation artifacts under docs/. The Cloudflare tunnel "
        "mapping, the GHCR images and the Hostinger VPS were verified only as far as "
        "the repository documents them; no live infrastructure was inspected. Those "
        "areas are marked as documented intention rather than verified runtime behaviour.")


def ch2_scope(b: Builder) -> None:
    b.h1("2. Scope, methodology and evidence standards")
    b.h2("2.1 Method")
    b.numbered([
        "Enumerated the tracked file set with git ls-files and classified it by extension and directory.",
        "Read every root manifest (package.json, pnpm-workspace.yaml, turbo.json, .env.example) and every AGENTS.md.",
        "Parsed the Go router with the repository's own AST extractor (TestAuditDumpRoutes, added temporarily) to obtain the mounted route set together with its middleware gate stack.",
        "Diffed that route set against apps/backend/docs/openapi.yaml and against packages/contracts/src/routes.txt.",
        "Applied all 123 migrations, in version order, to a throwaway PostgreSQL 16 container, then introspected information_schema and pg_catalog for tables, columns, constraints, indexes, sequences, functions and triggers.",
        "Started the backend against that database with Redis, and exercised health, login, catalogue, POS checkout, idempotency replay/conflict, and PDF report rendering.",
        "Ran the complete Go suite (with and without the destructive-integration consent) and the complete JS suite via Turborepo.",
        "Extracted the ERP router, the ERP navigation config, the POS router and the B2B page tree, and cross-checked every UI permission key against the backend catalogue.",
    ])

    b.h2("2.2 Reproducibility")
    b.p("Every inventory in this document is produced by a script committed under docs/audit/tools "
        "and docs/docgen. The raw introspection dumps live in docs/audit/raw. Re-running "
        "docs/docgen/build_doc.py regenerates this DOCX; re-running docs/diagrams/gen_erd.py "
        "regenerates the ER diagrams from the live schema.")
    b.code("""# Reproduce the audit environment (isolated; no production contact)
podman run -d --name km-audit-pg -e POSTGRES_USER=audit \\
  -e POSTGRES_PASSWORD=auditpw -e POSTGRES_DB=km \\
  -p 127.0.0.1:55433:5432 docker.io/library/postgres:16-alpine

cd apps/backend/migrations
for f in $(ls [0-9]*.sql | sort); do
  podman exec -i km-audit-pg psql -U audit -d km \\
    -v ON_ERROR_STOP=1 -q --single-transaction < "$f"
done

# Backend
cd ../..
DATABASE_URL='postgres://audit:auditpw@127.0.0.1:55433/km?sslmode=disable' \\
REDIS_URL='redis://127.0.0.1:56379/0' APP_PORT=18080 \\
  go run ./cmd/server""", caption="Audit environment reproduction")

    b.h2("2.3 What could not be verified")
    b.table(
        ["Area", "Reason", "Status in this document"],
        [
            ["Production runtime state", "No access to the Hostinger VPS or its containers.", "Documented intention from compose + runbooks; no measured values."],
            ["Cloudflare tunnel configuration", "cloudflared config.yml is not committed (it carries the tunnel UUID and credentials).", "Hostname→port mapping taken from docs/deployment/cloudflare-tunnel.md and cross-checked against compose port bindings."],
            ["GHCR image contents", "No registry access during the audit.", "Image names and tags read from the workflow and compose files."],
            ["Real customer/business data volumes", "No production database was contacted.", "All row counts in this document are from the throwaway audit database (empty except the seed)."],
            ["Third-party provider behaviour", "Midtrans and SMTP were not called with real credentials.", "Gateway code paths read; disabled behaviour verified by leaving keys empty."],
            ["Browser rendering of the SPAs", "Not exercised in a browser during this audit.", "Component and route inventories come from source; visual behaviour is inferred."],
        ],
        caption="Unverified areas and how they are handled",
        widths=[1.5, 2.4, 2.6], font_size=8.0)


def ch3_overview(b: Builder) -> None:
    b.h1("3. System overview")
    b.h2("3.1 Purpose and business model")
    b.p("KeluargaMart operates like a minimarket network. Head office owns the catalogue — "
        "products, prices, categories and units are central; an outlet does not create its "
        "own products. What differs per outlet is stock, not catalogue. Customers buy "
        "offline at the till or online through the storefront. This model is stated in "
        "apps/pos/docs/WORKFLOW.md and is consistent with the schema: products carry no "
        "store_id, while stocks is keyed by (product_id, warehouse_id).")
    b.note("Verified against schema", "products has 17 columns and no store or outlet "
           "column; stocks has a unique (product_id, warehouse_id) constraint; "
           "sales_orders carries both store_id and warehouse_id.", "verified")

    b.h2("3.2 Actors")
    b.table(
        ["Role", "Application", "Scope", "Verified capability boundary"],
        [
            ["owner / gm", "ERP", "All outlets", "Catalogue, outlets, membership tiers, consolidated reports. admin/owner bypass every permission check."],
            ["bm / spv", "ERP", "Area / team", "Distribution, fakturisasi, sales-order supervision; no accounting grants."],
            ["store_manager", "ERP + POS", "One outlet", "Outlet stock, outlet cashier accounts, outlet settings and reports."],
            ["cashier", "POS", "One outlet, one shift", "Sell, return, open/close shift, add customers, enrol members."],
            ["finance / finance_head", "ERP", "Company", "Invoices, payments, cashflow, journals, financial reports."],
            ["warehouse", "ERP", "Warehouses", "Stock in/out, opname, transfers, goods receipts; cannot create sales orders (service returns not-found for the warehouse role)."],
            ["hr_manager / hr_staff / employee", "ERP", "HR", "Employees, attendance, leave, payroll, performance; employees see only their own records via /hr/*/me."],
            ["buyer", "B2B", "Own account", "Catalogue, cart, checkout, own orders, own invoices, returns on own orders."],
            ["admin / system", "ERP", "Technical", "User and role administration, audit log, report templates."],
        ],
        caption="Roles and their verified boundaries", widths=[1.35, 0.95, 1.05, 3.15], font_size=8.0)

    b.h2("3.3 System context")
    b.figure(Path("../diagrams/rendered/fig-system-context.png"),
             "System context. Solid arrows are verified request paths; the optional "
             "integrations on the right are inert unless their keys are configured.")

    b.h2("3.4 Application map")
    b.table(
        ["Application", "Runtime", "Port (prod)", "Responsibility"],
        [
            ["apps/backend", "Go 1.26.5, chi v5, pgx v5", "3004 → 8080", "Authoritative API, business rules, RBAC, schema migrations, report proxy."],
            ["apps/erp", "Vue 3.5, Vite 8, Pinia, vue-router 5, PrimeVue 4, Tailwind 4", "3001 → 8080 (nginx)", "Back-office: master data, inventory, purchasing, finance, accounting, HR, distribution, tracking, reports, system."],
            ["apps/pos", "Vue 3.5, Vite 8, Pinia, zxing-wasm", "3003 → 8080 (nginx)", "Cashier register: sale, return, shift, drawer, customer/member enrolment, receipt printing."],
            ["apps/b2b", "Nuxt 4 (Nitro SSR), @nuxt/ui 4", "3002 → 3000", "Wholesale storefront: catalogue, cart, checkout, orders, payments, returns, support, admin console."],
            ["apps/nextreport", "Node 22 + Puppeteer/Chromium", "internal 5489", "JSON template → HTML → PDF/XLSX rendering."],
        ],
        caption="Applications and runtime identity", widths=[1.05, 1.95, 1.1, 2.4], font_size=8.0)

    b.h2("3.5 Data flow at a glance")
    b.p("A browser never talks to PostgreSQL. The only path to data is: browser → static "
        "host or Nitro proxy → Go API → pgxpool → PostgreSQL. Redis is used for two things "
        "only: rate limiting and idempotency records. Uploaded files are written to a local "
        "directory and served back through GET /uploads/{key}, which is public for product "
        "images and ownership-checked for payment proofs.")


def ch4_repo(b: Builder) -> None:
    b.h1("4. Repository structure and monorepo architecture")
    b.h2("4.1 Top level")
    b.table(
        ["Path", "Contents", "Notes"],
        [
            ["apps/", "backend, erp, pos, b2b, nextreport", "Deployable units. No cross-app imports are allowed."],
            ["packages/", "contracts, permissions, utils, api-client, ui", "Leaf libraries; must not import from apps/."],
            ["infra/", "containers/compose.yml, compose.prod.yml, reverse-proxy/Caddyfile", "Production container stacks."],
            ["scripts/", "gen-contracts.py, gen-permissions.py, check-drift.py, audit-icons.mjs, vps-manage.sh", "Contract generation and drift guard."],
            ["docs/", "adr, architecture, deployment, development, migration, performance, runbooks, security", "Existing project documentation (Indonesian)."],
            ["apps/backend/docs/", "openapi.yaml, business-rules.md, api-design.md, domain-map.md, database-analysis.md, BUGSWEEP reports", "The backend's own specification set."],
            [".github/", "workflows/ci.yml, workflows/deploy-ghcr.yml, ISSUE_TEMPLATE, CODEOWNERS", "Quality gates and image publishing."],
        ],
        caption="Repository top level", widths=[1.4, 2.9, 2.2], font_size=8.0)

    b.h2("4.2 File composition")
    b.table(["Extension", "Tracked files", "Where"],
            [["Go", "334", "apps/backend (296 under internal/, 3 test-bearing command packages)"],
             ["Vue", "290", "erp 90 components + 72 page files (70 routed); pos 42 components + 8 pages; b2b 17 components + 42 pages"],
             ["JavaScript", "163", "frontend services/stores/router; scripts"],
             ["SQL", "152", "123 migrations + 24 sqlc query files + schema.sql + seeds"],
             ["Markdown", "121", "docs/, app-local docs, AGENTS.md files"],
             ["TypeScript", "81", "b2b composables/services/types"],
             ["JSON / YAML", "22", "manifests, turbo, workflows, compose"],
             ["Python", "7", "drift guard, contract generators, docgen"],
             ["Total tracked", "1243", "git ls-files"]],
            caption="File composition at the audited commit", widths=[1.2, 1.1, 4.2], font_size=8.0)

    b.h2("4.3 Workspace and task orchestration")
    b.p("pnpm workspaces (pnpm@12.11.2) declare apps/* and packages/*. Turborepo v2 runs "
        "build, test, typecheck, lint and dev. build depends on ^build and caches .output/** "
        "and dist/**; test and lint have no outputs, so they always re-run. dev is "
        "persistent and uncached.")
    b.table(["Root script", "Command", "What it actually runs"],
            [["dev", "turbo run dev", "All workspace dev servers in parallel (Vite ×2, Nuxt, nextreport watch)"],
             ["dev:backend", "go -C apps/backend run ./cmd/server", "Backend only, on :8080"],
             ["build", "turbo run build", "erp/pos Vite builds, b2b Nuxt build, nextreport syntax check"],
             ["build:backend", "CGO_ENABLED=0 go -C apps/backend build -trimpath -ldflags='-s -w'", "Static binary at apps/backend/bin/server"],
             ["test", "turbo run test && pnpm test:backend", "JS suites, then Go — see finding F-04 for the DB caveat"],
             ["test:backend", "go -C apps/backend test -v ./...", "Go unit + integration (integration skips without DATABASE_URL)"],
             ["lint", "turbo run lint", "Only pos and b2b define a lint script; erp does not"],
             ["typecheck", "turbo run typecheck", "Only b2b defines typecheck (nuxi typecheck)"],
             ["contracts:generate", "python3 scripts/gen-contracts.py", "Regenerates packages/contracts from openapi.yaml"],
             ["permissions:generate", "python3 scripts/gen-permissions.py", "Regenerates packages/permissions from catalog.go"],
             ["drift:check", "python3 scripts/check-drift.py", "Fails if either generated package is stale"]],
            caption="Root scripts and their real effect", widths=[1.15, 2.6, 2.75], font_size=7.8)

    b.h2("4.4 Package dependency rules")
    b.figure(Path("../diagrams/rendered/fig-package-dependency.png"),
             "Package dependency graph. Dashed edges are declared in package.json but have "
             "no import in the source (verified by searching for the package specifier).")
    b.table(["Package", "Consumed by", "Evidence"],
            [["@keluargamart/contracts", "erp, pos, b2b, api-client", "backendContract.js/.ts import BACKEND_ROUTES from '@keluargamart/contracts/routes'"],
             ["@keluargamart/permissions", "erp, pos", "permissionLabels / auth stores import ALL_PERMISSIONS and ROLES"],
             ["@keluargamart/utils", "erp, pos, b2b, api-client", "currency/date formatting, newIdempotencyKey"],
             ["@keluargamart/api-client", "none", "declared by no app; only its own test imports it"],
             ["@keluargamart/ui", "declared by erp, pos, b2b — imported by none", "no '@keluargamart/ui' specifier exists in any app source"]],
            caption="Shared package consumption (verified by import search)",
            widths=[1.6, 2.1, 2.8], font_size=8.0)
    b.note("Gap", "@keluargamart/ui ships eight components and a token stylesheet but no "
           "application imports it. The design tokens are therefore duplicated in each app. "
           "This is a real drift surface: a token change in packages/ui has no effect on "
           "any running application.", "gap")

    b.h2("4.5 Existing documentation and its accuracy")
    b.table(["Document", "Accurate?", "Notes"],
            [["README.md", "Mostly", "Describes the five apps and the shared packages correctly."],
             ["AGENTS.md", "Partly", "Wrong migration and RBAC paths (F-02); otherwise a usable rule set."],
             ["docs/architecture/overview.md", "Partly", "Same wrong paths; also claims a POS offline queue that does not exist (F-17)."],
             ["docs/security/security-baseline.md", "No", "Describes JWT access/refresh tokens with a symmetric key and refresh-token revocation; the implementation uses opaque random bearer tokens (crypto/rand.Text) stored as sha256 hashes with a TTL and no refresh token at all. It also states X-Frame-Options: SAMEORIGIN and Referrer-Policy: strict-origin-when-cross-origin; the middleware sends DENY and no-referrer."],
             ["docs/development/getting-started.md", "Mostly", "Commands exist; the compose file it names lacks the db/redis/minio/mailpit services it tells you to start."],
             ["docs/deployment/backup-and-restore.md", "Partly", "Procedure is sound but references scripts/backup-db.sh, which is not in the repository."],
             ["apps/backend/docs/business-rules.md", "Yes (authoritative)", "576 lines of sourced business rules; the Go implementation follows it closely and cites section numbers in comments."]],
            caption="Documentation accuracy assessment", widths=[1.9, 0.95, 3.65], font_size=8.0)

    b.h2("4.6 Git baseline")
    b.table(["Item", "Value"],
            [["Branch", F.BRANCH],
             ["Commit", F.COMMIT],
             ["Commit date", F.COMMIT_DATE],
             ["Subject", F.COMMIT_SUBJECT],
             ["Working tree before audit", "clean (git status --porcelain empty)"],
             ["Working tree after audit", "docs/audit/, docs/docgen/, docs/diagrams/ and the temporary route-dump test added"],
             ["Versioning", "No git tags and no release file in the repository; the deploy workflow tags images with the commit SHA and, for v*.*.* tags, the tag name."],
             ["CHANGELOG.md", "Product-facing release notes, not a per-commit log."]],
            caption="Git and release context", widths=[1.8, 4.7])
