Gap audit 2026-07-29 - lane qa-feel-loop (12 findings)
Verbatim from workflow wf_d0ca605f-891. Each finding carries either its own register entry id or
the cross-lane merge that absorbed it. This file is the evidence of record the compact register
entries cite.
qa-feel-loop#1 [CRITICAL] merged into GAP-137 - The accreted regression suite has no clock — the only scheduled QA cadence explicitly skips it
Vision rules. AI_QA_LOOP_ARCHITECTURE.md §4.1: "Per-increment (I). On every commit: the Tier-1 functional pack plus the full accreted regression suite run headless." §5.3 + VOL2 §11.5 QT-21 (marked LIVE): "is this bug back" must be "the regression test going red again, never an argument." QT-22 (VOL2 §11.5): non-zero exit on any Tier-1 failure blocks the wave. ROADMAP_POST_5090_TO_SHIP.md P3 exit (L355): "the full accreted regression suite is green."
What exists (verified). 67 automation tests exist (grep IMPLEMENT_*_AUTOMATION_TEST over game Source/Humanity/Private/QA/*.cpp = 67; 79 distinct Humanity.* test ids). The ONLY scheduled cadence is the HumanityNightlySoak task driving Tools/nightly_soak.cmd → run_soak.py, and run_soak.py:130 builds cmd = [sys.executable, RUN_QA, "--map", map_key, "--skip-tests"] for all seven belt maps — the suite is disabled on every nightly run. Game-repo .git/hooks/pre-push and post-commit are Git-LFS stubs only; no .github/workflows directory exists. POSITIVE CONTROL on the zero: --skip-tests is a real flag (run_qa_pass.py:890) and the same runner does execute tests when it is absent (Tools/run_tests_chunk.py, 412 lines, BUG-0022's fixed filter-coverage assertion) — so a run WITHOUT the flag would have matched, and none is scheduled.
Delta. Between the 67 tests and any automatic clock there is nothing: no per-commit hook, no CI, and the one nightly job opts out by flag. Every never-relitigate claim, every "suite green" claim, and P3's exit criterion depend on a human or agent remembering to invoke the runner. A fix that re-breaks BUG-0012 or BUG-0021 can sit undetected for an arbitrary number of waves and no artifact would show it.
Blocking. Every content wave from now, starting with the Ch 6-13 region legs and the P2 surface passes — each lands into a slice whose regression signal is manual. It also silently invalidates the P3 zero-bug exit, which arrives right after the 2026-07-30 handshake.
Proposed home. Drop --skip-tests from Tools/nightly_soak.cmd's belt (or add a second nightly leg that runs the full filter), plus a pre-push hook or a scheduled run_tests_chunk.py --all writing a dated verdict under QA/regression/, and a canon-side gate reading the newest verdict's age (stale-verdict = red).
qa-feel-loop#2 [CRITICAL] merged into GAP-137 - No frame-time signal anywhere in the QA loop, and the ship bar carries no performance clause
Vision rules. ENGINE_OPTIMIZATION_DOCTRINE.md §1.1 rules the frame-rate canon (minimum 30 fps/33.33 ms · recommended 60 fps/16.67 ms · high-end 120/8.33 ms) and §1.5 rules that two clauses "must be written verbatim into the ship spec": "60 fps at 1080p internal … with frame generation off" and "60 fps HELD, not 60 fps average." DOC_MAP.md:106 also names "the dev-on-5090-must-not-hide-recommended-spec-misses scalability rule."
What exists (verified). The producer exists but is hardware-gated: UHumanityBenchSamplerSubsystem (Source/Humanity/Public/QA/HumanityBenchSamplerSubsystem.h:31-41) emits FrameMs/GameMs/RenderMs/GpuMs/DrawCalls/StreamingPoolMb per frame, and its only consumer is Tools/bench/kt3_wp_pcg_runtime.py (a 5090 benchmark-day kill test). The nightly soak samples nothing but process RSS (run_soak.py:10 "the editor process PEAK memory (psutil…)"). In ROADMAP_POST_5090_TO_SHIP.md — the doc that owns P0→P5, the zero-bug bar (L352-359) and the P4 Steam exit (L451) — occurrence counts are: "fps" 0 · "frame time" 0 · "frame-time" 0 · "p99" 0 · "profil" 0, against "zero-bug" 10. POSITIVE CONTROL: "perf budget" matches once (L82, the runtime-inference budget), so the file is greppable for perf language. No optimization/perf/profiling PASS row exists in any docs/*.md (grep "optimi[sz]ation pass|perf pass|performance pass|profiling pass" = 0), and ROADMAP_POST_5090_TO_SHIP.md never cites the doctrine (the citing docs are ASSET_DROPIN_CONTRACT, DESIGN_GAP_REGISTER, DOC_MAP, MARKETING_WEB_PROGRAM, PRE_5090_BUILD_PLAN).
Delta. The ruled frame-rate canon has no consumer on the ship path and no measurement cadence on the built slice. A content wave can double the frame cost of Ch 2-5 and every gate, scorecard and soak report stays green; the slice can reach the "honest zero-bug bar" and pass GATE 1 and GATE 2 having never been measured for frame time once. The 182 KB doctrine is the exact failure class: doctrine present, producing pipeline and gate absent.
Blocking. Benchmark day itself (box arrives 2026-07-30 per 5090_ASBUILT_BENCHMARKS.md) — U-07's "build one complete region, profile" has no per-map baseline to compare against; and every P2 surface pass, which is where Nanite/Lumen/MegaLights cost actually enters.
Proposed home. Enroll the BenchSampler in run_soak.py's per-map loop behind a --perf leg writing Saved/QA/Soak/perf_<map>.json + a committed per-map p99 baseline (drop-not-fail on an unstable clock, shapes-only per the tuning firewall); add a performance clause to the P3 exit and P4 store-spec rows in ROADMAP_POST_5090_TO_SHIP.md.
qa-feel-loop#3 [CRITICAL] merged into GAP-137 - Nothing about FEEL is measured — zero of the six ruled feel-telemetry funnels exist
Vision rules. QA_WATCHING_PROGRAM.md §1.5 rules six instrumentation funnels at sites "already called": RecordAttackPhase (four attack-phase transitions), RecordPlayerAnswer (parry/dodge/neutralize + pip mutation), RecordInputLatency (EnhancedInput trigger → first active frame), RecordHitStop (PlayHitStop + release), RecordStagger (EnterRecovery/part-break), RecordCameraSample (10 Hz). §3.2 makes the greybox-feel register conditional on a real measurement and names register inflation "a logged defect class." §2.1 rules that gating verdicts are sampled_invariant arithmetic, never critic prose.
What exists (verified). grep over the game Source/ for RecordAttackPhase|RecordPlayerAnswer|RecordInputLatency|RecordHitStop|RecordStagger|RecordCameraSample = ZERO hits. POSITIVE CONTROL both ways: the same search idiom finds PlayHitStop at four sites in Source/Humanity/Private/Combat/HumanityCombatFeelSubsystem.cpp (:109 definition, :217/:233/:248 callers — the funnels' intended anchors are live code), and the existing telemetry header declares five Record* functions (CombatTelemetrySubsystem.h:41/48/55/63/72 — RecordNodeBreak, RecordTellRead, RecordDialSample, RecordQuestEvent, RecordAudioCue). So both halves of the search can match; the six feel funnels genuinely do not exist.
Delta. Input latency, hitstop bracketing around the strike frame, stagger, and camera behaviour are unmeasured quantities. The feel critic that is supposed to replace Josh until the gate has no arithmetic at all — it has still frames and prose. Every "it reads", "it lands", "the parry feels right" claim in this lane is by construction a vibe or a pose, which is precisely the BUG-0010 failure ("declared fixed from a frozen pose") the program was written to close.
Blocking. The parry primitive and chain-meter pip system already landed (game e1994ea) with difficulty-scaled timing bands and no latency/hitstop instrument; the P2.4 combat surface pass and RB-7's boss-feel rubric both exit against measures that have no producer.
Proposed home. Extend UHumanityCombatTelemetrySubsystem with the six funnels (state-only, wall-clock, at the named existing call sites), landing QS-13..QS-18 as the first build slice after QS-0's schema; each new field enters as a diagnostic per §1.5's graduation rule.
qa-feel-loop#4 [MAJOR] GAP-153 - The project's one locked performance gate measures against a spec-class ladder that is not the ruled canon
Vision rules. ENGINE_OPTIMIZATION_DOCTRINE.md §1.1 rules THREE classes with named ms budgets (30 fps/33.33 ms · 60 fps/16.67 ms · 120/8.33 ms) and §1.2 anchors each to hardware (minimum RTX 2060 SUPER/RX 6600; recommended RTX 5060/4060 Ti/RX 7600 XT at 1080p High, 7.0 GB VRAM ceiling, 6c/12t). DOC_MAP.md:106 names "KT-3's bars" as the doctrine's first consumer.
What exists (verified). Tools/bench/bench_criteria.json kill_tests.kt3_wp_pcg_runtime declares FOUR classes — steam_deck_minimum (target_fps 30, p99_frame_ms_max 50.0), mid_range_pc (60, 33.3), high_end_pc (60, 25.0), ultra (60, 25.0) — with provenance canon_illustrative and a _note reading: "target_fps is harness-declared: canon names 'target frame rate' as a per-region field but rules no value -- logged in TODO_CANON.md." The criteria body is sha256-LOCKED at v1.2.0 (2026-07-28T04:22Z), i.e. locked AFTER the 2026-07-27 ruling. Game-repo TODO_CANON.md:1301 still carries the row "no frame-rate NUMBER is ruled anywhere. The whole KT-3 frame budget derives from it."
Delta. Four harness classes versus three ruled classes, with no declared mapping — so a KT-3 PASS cannot be read as "meets the ruled canon." Worse arithmetic: mid_range_pc carries target_fps 60 with a p99 ceiling of 33.3 ms, which IS the 30-fps frame time — exactly double the ruled 16.67 ms recommended budget, and exactly the "60 average with hitches" that §1.5 forbids. The doctrine's two verbatim ship clauses and its 15-row per-pass ms table (§2.2, each row with a stat gpu handle) appear in no gate at all; U-13 defers pinning the 5.8 pass names to "benchmark day" although capturing one frame needs no new hardware (the belt already drives seven maps nightly).
Blocking. Benchmark day (2026-07-30 onward) — KT-3 is scheduled first-week and will emit verdicts against the non-canon ladder, and once a bar is locked and cited it acquires authority (the doctrine's own §8.3 self-check names this failure mode).
Proposed home. Re-lock bench_criteria.json kt3.spec_classes onto the §1.1/§1.2 three-class ladder with per-class ms budgets and a canon_ruled provenance + cites; retire the stale TODO_CANON.md:1301 row; file the §2.2 pass-name pinning as an ungated dev-box item, not a benchmark-day one.
qa-feel-loop#5 [MAJOR] merged into GAP-137 - The visual-verification instrument has expected content for 9 of the 50 shots it captures nightly
Vision rules. The standing visual-verification directive (CLAUDE.md model-seats block; MEMORY.md visual-verification-standing-directive): game-side work is verified by LOOKING, critics READ the PNGs, and no play-term claim ships without a backing frame. AI_QA_LOOP_ARCHITECTURE.md QA-1/QA-6 make this mechanical via "the per-shot expectation manifest"; QA_WATCHING_PROGRAM.md §2.4 adds the director re-read gate over the deciding frames.
What exists (verified). Seven capture scripts declare 50 shot entries (Tools/qa/capture_script_*.json — angkor 5, bali 6, borobudur 3, flores 18, greybox 10, palembang 3, samosir 5) and the nightly belt drives all seven maps. harness/qa/capture_expectations.json declares 9 shot expectations, ALL greybox_* (greybox_spawn, hud_wellspring, hud_forgotten, boss_closeup, direct_broken, phase_p2, feel_swing, lockon, break_moment) plus 2 cross_checks. Intersection computed: 9 of 50 declared shot ids have an expectation; 41 do not (angkor_opening, bali_besakih_site, borobudur_site, flores_boss_at_site, flores_caci_ch03, samosir_naga_mutation, …). harness/read_captures.py:120-122 is honest about it — it WARNs "frame captured but nothing to judge it against" — but WARN never fails: structural FAIL fires only on a missing or zero-byte PNG (:115-117, :159). DOC_MAP.md:409 still scopes the file to "the C1.18 greybox capture set (6 shot_ids)".
Delta. The instrument was built for the greybox arena and never grew with the six real region maps that ARE the slice (CH_02-05 across flores/bali/samosir/palembang/borobudur/angkor). 82% of the nightly capture surface is pixels with no content contract, warning quietly forever while the wave goes green — the visual directive is instrumented for 18% of what it photographs.
Blocking. The Ch 6-13 region legs (eight more region pages already on disk) multiply the uncovered surface immediately; every P2 surface-pass exit that cites a captured frame as evidence.
Proposed home. Grow harness/qa/capture_expectations.json to one entry per declared shot id across all seven scripts (surface/expect/must_show/must_not_show), and promote read_captures.py's no-expectation WARN to a FAIL once a declared coverage floor is met, with the floor itself a scorecard number.
qa-feel-loop#6 [MAJOR] merged into GAP-137 - QS-0 — the one frame-record schema ruled to land before any C++ — does not exist, so all nine sequence teeth have no data contract
Vision rules. QA_WATCHING_PROGRAM.md §1.1: "harness/qa/frame_record_schema.json is the single definition both lanes consume" — one root, one vocabulary, append-only JSONL, 4 KB per record; §6 build order item 1: "QS-0 plus the Json module link — one schema, one parser, before any C++ in either lane"; §10 lists it as a wiring obligation with a DOC_MAP row and a run_gates.py tooth. §2.2 defines nine permanent teeth (T-SEQ-PRESENCE/RENDERED/UPRIGHT/PHASE-ORDER/CLOCK/SOURCE-AGREE/HITSTOP-RELEASE/CAM-CONTINUITY/PIP-WIPE) that all read that record.
What exists (verified). harness/qa/ contains exactly three entries: bug_record_schema.json (4,206 B), capture_expectations.json (14,854 B), fixtures/ (session_complete, session_missing_png, session_zero_byte). frame_record_schema.json: absent. POSITIVE CONTROL: grep "frame_record_schema" over the canon repo matches docs/proposals/QA_WATCHING_PROGRAM.md, docs/PRE_5090_BUILD_PLAN.md and docs/DOC_MAP.md — the string is greppable, so the file's absence is real. Related zeros: no Json link in the game module's declared dependencies for a JSON reader, and the whole motion class is guarded by one bespoke test (Humanity.Combat.BossUprightDuringAutonomousCycle) rather than a schema-backed tooth. The QS/T2/RB ids appear in NO ranked plan row: grep "QS-0|QS-10|QS-20|T2-1|RB-1" over docs/PRE_5090_BUILD_PLAN.md = 0 matches, and the 30-item window queue (§▶, L60-111) contains no sequence-capture rank.
Delta. The program's own first build item — declared a precondition for every other line of work in both its lanes — has no artifact, no rank, no owner and no date. Consequently there is no per-frame state record, no contact sheet, no min_body_up arithmetic, no three-source cadence cross-check, and the reference program's temporal leg (RB-3) consumes a schema that does not exist. The BUG-0012 class (a boss standing on its head through a whole autonomous cycle while every still-frame tooth stayed green) is closed by luck-of-one-test, not by construction.
Blocking. Any motion, animation, camera or timing claim made during the Ch 6-13 build and the P2 presentation-ladder passes — i.e. the animation/VFX work that is the hard 5090 requirement.
Proposed home. Mint harness/qa/frame_record_schema.json with a DOC_MAP row and a run_gates.py tooth, and give the QS/T2/RB tables a ranked home in PRE_5090_BUILD_PLAN.md §11.5 (the §10 obligation that never landed).
qa-feel-loop#7 [MAJOR] GAP-154 - No agent can PLAY the build — zero input-injection call sites, and no charter or action data home
Vision rules. CLAUDE.md model-seats: "The AI QA loop + image/feel critics are the ONLY players until then." AI_QA_LOOP_ARCHITECTURE.md §2.1 Tier 2 and QA-4 rule the beta player as screenshot → decide → InjectInputForAction (packaged-valid). QA_WATCHING_PROGRAM.md §3.1 rules a deny-by-default vocabulary in a checked-in sidecar Tools/qa/action_annotations.json (an unannotated action makes the run RED), §3.2 rules the injection-ACK floor and the register field, §2.6 rules the charter schema.
What exists (verified). grep InjectInputForAction|InjectInputVectorForAction over the game Source/, Tools/ and Plugins/NeoStackAI = ONE hit and it is a comment (Source/Humanity/Private/Input/HumanityInputConfig.cpp:108). POSITIVE CONTROL: the control query AddMappingContext hits Source/Humanity/Private/Core/HumanityCharacter.cpp:396 — the search reaches live input code, so the zero is real. Tools/run_qa_pass.py exposes no agent or sequence mode (its flags are --self-test, --skip-capture, --skip-tests, --timeout, --lock-wait, --map). Tools/qa/ holds index_bugs.py, check_site_map_binding.py, repro_bug_0022.py, seven capture_script_*.json and fixtures/ — no action_annotations.json, no charter files.
Delta. The only player until the Josh gate is a state-teleporting driver that poses the game for photographs. The mapping context, ability gate, input buffer, lock-on cycle, fork UI focus and traversal are untested by construction, and there is no coverage denominator of any kind — actions never injected, beats never advanced, sites never reached are all uncountable, so "the machine played the build tonight" and "the machine photographed the build tonight" produce identical artifacts.
Blocking. The Ch 6-13 traversal and between-site route work (window-plan rank 21) and the P2.11 character-creation entry architecture — both are input-path surfaces a pose-driver cannot reach; and GATE 1 at the Ch 2-13 P3 exit, whose whole premise is that the machine already played what Josh is about to.
Proposed home. T2-1/T2-2/T2-3/T2-10 as a ranked qa-teeth item: the injection seam plus the checked-in Tools/qa/action_annotations.json sidecar and a charter file per slice chapter, proven by the briefed CH_02 spawn-to-first-site-marker walk with allow_dev_shortcuts:false.
qa-feel-loop#8 [MAJOR] merged into GAP-137 - The bug schema cannot hold the anti-still-frame rule that was ruled onto it
Vision rules. QA_WATCHING_PROGRAM.md §2.3 rules three deliverables in terms ("Ruled: add the field"): motion_class as a closed enum (none|motion|animation|orientation|timing|camera) in harness/qa/bug_record_schema.json with all 17 records backfilled; regression_test_ref becomes a typed object {kind: automation_test|sequence_artifact|expectation|harness_selftest, ref}; and a must-fire fixture Tools/qa/fixtures/motion_class_still_ref. §10 repeats all three as wiring obligations. The rule they enforce: a motion/animation/orientation/timing/camera bug may not carry a single still frame as its regression reference.
What exists (verified). harness/qa/bug_record_schema.json read in full (100 lines, mtime 2026-07-26 23:52 — before the 2026-07-27 program): no motion_class property; regression_test_ref is a plain string (:70-74); additionalProperties: false at :7, so a record that DID carry motion_class would fail validation in Tools/qa/index_bugs.py. Tools/qa/fixtures/ holds valid, fixed_without_regression, bad_enum, duplicate_id, filename_id_mismatch, malformed_json — no motion_class fixture. The live ledger is now 23 records (QA/bugs/BUG-0001..0023), so the backfill target grew past the ruled 17 and still has not run. POSITIVE CONTROL: grep "motion_class" over the canon repo matches PRE_5090_BUILD_PLAN.md, DOC_MAP.md and QA_WATCHING_PROGRAM.md — greppable, and absent from the schema.
Delta. A ruled ledger law is structurally unimplementable: the field it keys on does not exist, the schema actively rejects it, and the check has no fixture. BUG-0010's ruled migration (motion_class: orientation, ref retyped to the BUG-0012 automation test) never happened, so the record that started this whole program still closes on the evidence class the program forbids.
Blocking. Every motion or timing bug opened by the presentation-ladder and animation waves — the first one lands with no way to be typed, and the ledger's severity/status arithmetic feeds the P3 zero-bug bar.
Proposed home. Add motion_class + the typed regression_test_ref object to harness/qa/bug_record_schema.json, ship Tools/qa/fixtures/motion_class_still_ref with the check, and backfill all 23 records in the same commit.
qa-feel-loop#9 [MAJOR] merged into GAP-137 - Not one QA tooth is enrolled in either gate suite — the green-before-land claim describes nothing
Vision rules. AI_QA_LOOP_ARCHITECTURE.md §4.2: "Gates are non-zero-exit floors. A Tier-1 functional failure, a DataValidation error, a crash, an unreachable beat, or a missing expected frame blocks the wave." VOL2 §11.5 QT-22: "The QT harnesses ride run_gates.py (canon-side, unpiped, green-before-land)… non-zero exit on any Tier-1 or DataValidation failure blocks the wave." QA_WATCHING_PROGRAM.md §10 requires a run_gates.py tooth for the frame-record schema and the register↔board join.
What exists (verified). harness/gates_config.json holds 34 gates and every one is a canon-data gate: stress, fidelity, scan, topography, layer_register, lint, anchors, graph, no_dead_end, boss_axes, spine_graph, lifecycle, reveal_discipline, registry_extensions, index_freshness, store_integrity, region_pages, ws_value_form, slice_coherence, seed_housing, build_readiness, entity_taxonomy, care_scope, grand_sage_silence, weave_lifecycle, build_space, rarity_firewall, counter_class_coverage, ally_build, factory_contract, realm_ruleset, arc_continuity, promise_ledger, emotional_curve. Substring probe over the whole file for capture / qa / read_captures / bug / perf / frame / soak / image_critic = False on all eight. POSITIVE CONTROL: the 34 names above are printed from that same file, so it is readable and matchable. read_captures.py and Tools/qa/index_bugs.py are director-invoked scripts; nothing runs them as a floor.
Delta. The QA loop's floors are advisory. A broken bug ledger, a missing expected frame, a red capture session, or a stale regression verdict cannot block a canon landing or a game commit, in either repo. QT-22 is written in the present tense about machinery that does not exist, which is the register-inflation defect class the program itself names.
Blocking. Every landing from now in both repos — and specifically the first landing where a capture session goes red while the canon suite goes green, which the nightly belt makes a matter of time.
Proposed home. Enroll two canon-side teeth in harness/gates_config.json: qa_captures (read_captures.py over the newest session resolved via last_run.json) and qa_ledger (bug-record schema validity + fixed⇒regression_test_ref + verdict staleness), each with must-fire/must-not-fire fixtures per the self-testing-gate law.
qa-feel-loop#10 [MAJOR] GAP-155 - The factory contract's per-chapter TEST-COVERAGE row class has an orphaned data home and no producer
Vision rules. docs/factory_contract.json rider FR-042 (lane qa-teeth, scope all): "Score this chapter on all five scorecard row classes — content budget, structure completeness, test coverage, care and reveal, and rider completeness," tooth gate:factory_contract, consumption_point p5:scorecard. VOL2 §11.5 QT-18: "Per node, what fraction of that content is under an actual QT harness: beats with a reachability test (QT-7), bosses with an invariant test (QT-5), forks with a completability test (QT-7), minigames with a runtime test, care/reveal surfaces with a validator (QT-9), audio cues fired (QT-10)." QT-5 sizes itself as "one test per boss row × preset" over DT_BossEncounter/DT_BossPhase (343 rows).
What exists (verified). FR-042's own fields read status PARTIAL and data_home: "NONE_YET(rank 1)". Window-plan rank 1 is "[qa-teeth·L] Author the X9.5 kill-test/benchmark harness set" (PRE_5090_BUILD_PLAN.md L60) and it LANDED (game 7d3de25) — producing Tools/bench/KT-0..KT-5 and bench_criteria.json, not a per-chapter QA scorecard. No coverage scorecard exists: ls harness/*coverage* and Tools/*coverage* return only check_counter_class_coverage.py + its scorecard (POSITIVE CONTROL — the glob matches when a coverage artifact exists). The 79 live test ids are overwhelmingly bespoke-per-chapter (CH02_*, CH03_*, CH05_*) rather than row-generalized, against denominators of 343 boss rows, 891 DT_Beat rows, 90 DT_Fork, 305 DT_ForkOption, 42 ws.* vars and 163 personas cited in VOL2 §11.5.8.
Delta. The factory's own definition of a finished chapter includes a test-coverage score whose data home points at a completed rank that never owned it, and whose producing script does not exist. So "is Ch NN tested?" is unanswerable as arithmetic — the 79 tests have no denominator, and 67 bespoke tests over a 343-boss / 891-beat corpus reads as coverage it is not.
Blocking. Rank 2.5's factory contract is the gate every later rank emits riders into; the first chapter to be scored at P5 (and the Ch 6-13 legs already queued) hits FR-042 with no producer, so the rider passes vacuously.
Proposed home. Re-point FR-042.data_home at a new harness/check_test_coverage.py + build/qa/test_coverage_scorecard.json that joins the automation-test id list against the DT row inventories (QT-18), and enroll it as the gate the rider names.
qa-feel-loop#11 [MINOR] GAP-156 - The 60 fps promise has no machine it can be verified on, and no plan row acquires one
Vision rules. ENGINE_OPTIMIZATION_DOCTRINE.md §1.2 anchors the ruled 60 fps to "RTX 5060 / RTX 4060 Ti / RX 7600 XT class … 1080p output, High preset, upscaler Quality, NO frame generation, 7.0 GB VRAM ceiling, 6-core/12-thread CPU"; §8.2 U-07 is "THE HYPOTHESIS… Build one complete region, profile on RTX 5060-class"; U-35 records that laptop thermal/power behaviour "is not reproducible by downclocking a desktop part, so this closes only on the laptop reference machine" and blocks printing a mobile part on a store page; DOC_MAP.md:106 names the dev-on-5090-must-not-hide-recommended-spec-misses rule.
What exists (verified). The program's hardware is one RTX 5090 workstation (9950X3D, 32 GB VRAM, 128 GB RAM — docs/5090_ASBUILT_BENCHMARKS.md, arriving 2026-07-30) plus a ROG Ally X that appears only as the walkthrough narration terminal and UPS-notification target (5090_SETUP_RUNBOOK.md L443 "the ROG Ally X appeared only as a UPS-notification target", L460/L511; 5090_WALKTHROUGH_SCRIPT.md L9, L224). POSITIVE CONTROL on the zero: grep -i "5060|4060 Ti|7600 XT|steam deck|rog ally" across docs/*.md returns hits ONLY in ENGINE_OPTIMIZATION_DOCTRINE.md (the ruled ladder) and the Ally-as-terminal rows above — the search reaches both repos' hardware prose, and no verification-machine row exists. Note the harness already assumes a device nobody owns: bench_criteria.json's minimum class is literally named steam_deck_minimum.
Delta. Every ms budget, every p99 bar and the entire recommended-spec ship claim will be measured on a 5090 — the one machine the doctrine says must not be allowed to hide a recommended-spec miss. There is no ranked item to buy, rent, borrow or cloud-instance an RTX 5060-class or minimum-spec target, and no fallback protocol (locked clocks, resolution scaling, a declared-invalid stamp) for deriving a class verdict from the wrong machine. P4 will need published minimum/recommended specs for the store page that U-35 forbids printing unmeasured.
Blocking. U-07's falsification test in the P0/P1 window (the first complete-region profile) produces a 5090 number that cannot verdict the ruled class; P4's store-page spec rows at ship.
Proposed home. A ranked hardware row in PRE_5090_BUILD_PLAN.md's window plan (or a P0 handshake item): acquire or borrow one recommended-class target (RTX 5060 / 4060 Ti / RX 7600 XT, 16 GB RAM, 6c/12t) as the perf verification box, plus a written INVALID-CLASS stamp rule for any verdict measured on the 5090.
qa-feel-loop#12 [MINOR] GAP-157 - QT-10's audio event-fire harness has almost nothing to assert against — the producer exists, the expectation table does not
Vision rules. VOL2 §11.5 QT-10: "Audio event-fire … cue_id/sfx_id_ref arrays (§10.6, per registry)" must catch "a declared cue that never fires on its trigger; a MetaSound not consuming tempo/bar/stem-role; footfall not keyed to footfall_surface." AI_QA_LOOP_ARCHITECTURE.md §3 WS-6 requires a "cue→trigger coverage matrix" as the loop artifact. VOL2 §11.5 HEARING sense: "no cue→trigger matrix in harness/."
What exists (verified). The producer half is live: UCombatTelemetrySubsystem::RecordAudioCue(FName CueId) at CombatTelemetrySubsystem.h:72. The expectation half is absent: no cue or audio artifact in harness/ (ls harness/*cue* harness/*audio* = none; POSITIVE CONTROL — 27 harness/check_*.py exist and the same glob form finds them). And the denominator itself is nearly empty: a scan of all registries/**/*.csv finds 15 registries carrying cue_id or sfx_id_ref columns but only 40 non-empty cue/sfx reference tokens corpus-wide, with 7 of those 15 registries carrying any *trigger* column at all.
Delta. Built as specified, QT-10 would go green having asserted roughly forty cue tokens for a 79-node game — a harness whose denominator is so thin that a pass carries no information, which is the "a check that cannot fail is not armed" defect in data form rather than in code. Neither the coverage matrix nor the per-cue trigger declaration has a data home, so the audio surface has no measurable definition of done.
Blocking. Window-plan rank 8 (the Section-10 machine cue table + Theme/Scene music columns, now unblocked by the emotional-register landing) is about to author cue rows into registries with no trigger column and no coverage instrument waiting — retrofitting the trigger declaration after four-plus region pages of cue authoring costs a second pass.
Proposed home. Declare the trigger alongside the cue in rank 8's own schema (a cue_trigger column beside every cue_id/sfx_id_ref rail), and mint harness/check_audio_cue_coverage.py reading the RecordAudioCue telemetry stream against that declaration as the cue→trigger matrix.
Generated by harness/site/structure_site.py — the URL path is the repo path. review root