Capablio

Pipeline architecture

Three sequential stages implemented in the feedback360 package:

Updated

PDF sources  →  parse_360.py  →  data.json
data.json    →  analyze.py    →  metrics.json
data + metrics → render_html.py → 360-report.html + wiki/

Entry point: python -m feedback360 (feedback360/__main__.py).

Parse (parse_360.py)

Input: Thomas 360 PDF (required), optional snapshot deck PDF.

Strategy:

  1. Text extractionpdfplumber page text for subject name, respondent counts, importance table, competency definitions, statement text, averages, qualitative comments, and snapshot highlight bullets.
  2. Geometric extraction — For per-statement score distributions, locate table headers (1 2 3 4 5 6 7), read filled cells per rater group row, and validate counts against known group sizes (Self=1, Manager=1, Peer=5, Team=5, Customer=3).
  3. Validation — Hard checks on competency count (12), statement count (54), per-competency statement counts, respondent minimums/completed, importance row values, and qualitative section shape (3 questions × 15 comments).

When geometric validation fails for a statement, distributions is set to null and a human-readable note is appended to top-level warnings. Optional overrides.json at the project root merges last-resort corrections; paths land in overrides_applied.

Output: data.json (schema version 1). See data-contract.md.

Analyze (analyze.py)

Input: data.json.

Output: metrics.json — competency-level scores, quadrants, priority scores, statement flags, rank inversions, CTA cards, qualitative theme groupings, lexicon sentiment scores, SWOT extraction, and per-tab executive summaries.

Formulas match the shared context spec (medians for quadrants, weighted priority score with executive-relevance multipliers, keyword-based qual themes). Qualitative analytics (sentiment, SWOT, section summaries) use fixed lexicons and keyword rules — fully deterministic, no ML. All floats rounded per field rules (2 or 3 decimals).

Render (render_html.py)

Input: data.json, metrics.json.

Output:

  • 360-report.html — Template templates/report_template.html with embedded JSON blob, all 54 statement rows and 12 competency panels pre-rendered in HTML, plus inline CSS/JS (fully offline).
  • wiki/*.html — Reader-facing mini-handbook sharing the dark visual language.

No external assets, CDN links, or timestamps in JSON outputs.

Dynamic mode (serve.py)

Input: existing <out>/data.json and <out>/metrics.json (from analyze).

Entry: python -m feedback360 --serve --out report [--port 8913]

A stdlib ThreadingHTTPServer on 127.0.0.1 serves:

  • / — dynamic app from templates/app_template.html (live sidebar controls).
  • /api/metrics — POST body with optional weight overrides; calls the same compute_metrics(data, params) pure function as analyze.py.
  • /report and /wiki/* — passthrough to rendered static artifacts.

analyze.py exposes compute_metrics() so disk output (--stage analyze) and API recomputation share one code path. Default params reproduce byte-identical competency fields to metrics.json; non-default rater_weights or importance_source values recompute quadrants, priority scores, and statement aggregates per the params contract.

Determinism rules

  • json.dump with stable key order from constructed dicts; sorted iterations where needed (e.g. distribution score keys, theme matching).
  • No datetime, random IDs, or environment-specific paths inside data.json / metrics.json (source paths in sources are relative strings as passed to CLI).
  • Re-running --stage all on unchanged inputs produces byte-identical JSON.

PDCA orchestration

Development is gated by read-only assets under orchestration/:

Path Role
orchestration/run-pdca.sh Runner for phased build loop
orchestration/prompts/ Phase prompts (00-context, 10-parse, …)
orchestration/checks/check-*.py Acceptance tests per phase
orchestration/logs/pdca/ Iteration status and check logs

Agents implement one phase at a time, run the matching check script, and iterate until exit 0. Checks are ground truth — fix implementation, not checks.

See pdca-log.md for iteration outcomes.

Verification harness

Three layers guard extraction accuracy and prevent silent parser drift:

  1. Arithmetic reconciliationfeedback360/verify_extraction.py checks all 54 statements: distribution means vs group averages, range/consistency, respondent counts, competency overall ratings, and the importance table. No PDF required for this pass.
  2. Independent PDF reconciliation — the same verifier re-reads the Thomas PDF with a separate pdfplumber path (geometry for the page-7 importance grid, normalized text for statements/comments/respondents) and must agree with data.json.
  3. Golden drift gateorchestration/golden/data-golden.json is compared byte-for-byte (canonical JSON) on every check-95 run.

Run the verifier manually:

.venv/bin/python -m feedback360.verify_extraction \
  --thomas sources/thomas-360-report.pdf \
  --data report/data.json

Run the pytest suite:

.venv/bin/pytest feedback360/tests -q