Handbook
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:
- Text extraction —
pdfplumberpage text for subject name, respondent counts, importance table, competency definitions, statement text, averages, qualitative comments, and snapshot highlight bullets. - 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). - 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— Templatetemplates/report_template.htmlwith 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 fromtemplates/app_template.html(live sidebar controls)./api/metrics— POST body with optional weight overrides; calls the samecompute_metrics(data, params)pure function asanalyze.py./reportand/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.dumpwith 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 insidedata.json/metrics.json(source paths insourcesare relative strings as passed to CLI). - Re-running
--stage allon 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:
- Arithmetic reconciliation —
feedback360/verify_extraction.pychecks 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. - Independent PDF reconciliation — the same verifier re-reads the Thomas PDF with a separate
pdfplumberpath (geometry for the page-7 importance grid, normalized text for statements/comments/respondents) and must agree withdata.json. - Golden drift gate —
orchestration/golden/data-golden.jsonis compared byte-for-byte (canonical JSON) on everycheck-95run.
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