test: qualify immutable models and Phase 9 regression
MariaDB persistence qualification / mariadb (push) Has been cancelled

This commit is contained in:
cesnimda
2026-10-25 13:43:50 +01:00
parent 30e251a593
commit b48f25c4ff
33 changed files with 67462 additions and 6 deletions
@@ -57,3 +57,5 @@ Repository source review preserves the unconditional first-step exit1, existing
Hosted PASS requires real MariaDB test execution **and** verified isolation/lifecycle evidence. Current owner action is infrastructure proof followed by reviewed repository enabling changes and actual execution. API success, backup success, labels, source examples, mocked guards and local MariaDB qualification do not satisfy it. Production release remains an independent gate.
Raw bounded metadata, source bytes and manifests are retained under `.artifacts/p9-sec-02/ci/`; [ci-assessment.json](ci-assessment.json) records response and source hashes, actual permission failures, limitations and actions. No workflow dispatch, host mutation, Docker socket use, secret-value/log access, database operation or deployment occurred.
Final metadata refresh25October12:32UTC: [ci-final-refresh.json](ci-final-refresh.json) records runs856/857 at22ef8d0/30e251a queued for `jobtracker-mariadb-isolated`, with unassigned runner IDs0. The query returned metadata only; no current HostConfig or service lifecycle was inspected and no job log was downloaded. **Hosted MariaDB BLOCKED; isolation UNVERIFIED;0 hosted database cases.** Operator provisioning and actual isolation/execution proof remain necessary. Review stale owned queued guard jobs during that separately authorised operator handoff; this task did not cancel them.
@@ -38,3 +38,7 @@ Exact installed queries cover63 distributions/126 requests, zero advisory record
Original109 groups remain traceable as65 previous repairs plus44 individual follow-ups. The [current source assessment](advisory-current-scope.md) supports ten explicitly scoped non-applicability dispositions (unshipped/unused conversion, alternate architectures, export archive loader and the disputed numeric chain); it does not claim those upstream flaws globally fixed. Full final dispositions and Phase9 gates are reconciled after broad regression.
Full trained DistilBART, semantic quality, GPU, production cache ownership/migration, real device/provider/manual acceptance and live filesystem/recovery state remain unqualified. The source Dockerfile still has mutable base/apt/bootstrap inputs: this measured immutable local image is retained, while a future rebuild must record its actual identities and requalify. Production digest/supply-chain pinning and release approval remain separate gates. The bounded worker deadline/parser cancellation controls do not establish application-level cancellation of in-flight full-model inference.
The trained-checkpoint successor is reported separately in the final validation/addendum; the preceding sentence records the earlier small-fixture checkpoint boundary. Native Windows unit execution on the retained old virtualenv is predecessor/tooling evidence only. That old graph is not patched-service qualification and must not be used to claim safe untrusted-document processing. Use the exact qualified Linux image and hash locks for the supported tested service. No native virtualenv or production installation was deleted, reset or silently relabelled as updated.
Final25October successor: the configured trained checkpoint passes real CPU loading/generation and offline repository-cache/API contracts under the patched graph. The six current runtime lanes also pass with positive bounded cleanup evidence. All109 original advisory groups have individual dispositions (99 fixed/version-verified,10 narrowly not affected); the additional pytest group is fixed. The final63-distribution scan has0records and the retained vendor PyPI404, so scan coverage remains INCOMPLETE and the independently scoped security decision is CONDITIONAL PASS. Full-image/stdlib/native advisory coverage, old native virtualenvs, semantic/GPU/production qualification are not granted by that decision.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,131 @@
# SEC-M01 / SEC-M03 — individual advisory dispositions
**Scoped assessment complete; broad regression still pending.** Every original alias is retained in [DISPOSITIONS.json](DISPOSITIONS.json), with affected-range references, installed version, role, function, reachability, fix evidence, confidence, residual scope and exact source/test references. The current source image, real fixtures and limits are documented in [dependency remediation](DEPENDENCY_REMEDIATION.md).
Original109 =65 previous repairs +44 investigated here. Current original dispositions:99 fixed/version-verified and10 explicitly scoped Not affected. Nine alternate-loader/conversion issues have no verified general upstream fix; numeric55554 has open/conflicting upstream evidence. Their service-scoped exclusions are not global patch claims. The new pytest group is separate:110 tracked groups total.
The actual63-distribution scan returns0records/126requests, with the exact CPU-version PyPI404 retained as INCOMPLETE coverage. OSV exact local-version lookup and official CPU wheel/hash evidence are separate. No scanner suppression or owner risk acceptance occurs. All current decisions must be reconsidered if a named scope falsifier becomes applicable.
| Package / group | Installed | Disposition | Evidence/operation |
| --- | --- | --- | --- |
| certifi / GHSA-6q48-6c7w-9gw2 | 2026.10.19 | Fixed and verified | certifi bundles emSign root CAs with compromised intermediate CA keys |
| filelock / CVE-2026-112940 | 4.2.1 | Fixed and verified | ReadWriteLock SQLite database reopen and POSIX symlink/side-file handling |
| filelock / CVE-2026-112913 | 4.2.1 | Fixed and verified | ReadWriteLock Windows SQLite -wal/-journal/-shm handling |
| filelock / CVE-2026-112907 | 4.2.1 | Fixed and verified | SoftFileLock marker open/stale breaking on Windows oplock |
| pillow / GHSA-4558-3h8r-v8xp | 13.0.0 | Fixed and verified | Pillow: P;2L and P;4L decoders may read 1 to 3 bytes past the passed buffer size |
| pillow / GHSA-8g5g-8vmr-9782 | 13.0.0 | Fixed and verified | Pillow: Heap buffer overflow in ImagingJpegDecode |
| pillow / GHSA-rfgq-q3w2-pmv2 | 13.0.0 | Fixed and verified | Pillow: Image.quantize() with empty palette leaks uninitialized stack memory |
| pillow / GHSA-xvh5-g6gv-559v | 13.0.0 | Fixed and verified | Pillow: Memory disclosure and segfault in libtiff encoder via crafted TIFF tags |
| pillow / GHSA-p4wg-p73j-c528 | 13.0.0 | Fixed and verified | Pillow: Unbounded recursion parsing a PDF page tree or trailer chain (incomplete fix for CVE-2026-42310) |
| pillow / GHSA-65qm-jvmh-6pqg | 13.0.0 | Fixed and verified | Pillow: GIF seek keeps rejected size after DecompressionBombError, allowing DoS |
| pillow / GHSA-58r4-6rv3-gfh8 | 13.0.0 | Fixed and verified | Pillow: Out-of-bounds access in _imagingmorph on a zero-width image |
| pillow / GHSA-pchr-8j38-3x4p | 13.0.0 | Fixed and verified | Pillow: TIFF encoder ColorMap plane-size mismatch causes a heap out-of-bounds read |
| pillow / GHSA-q45j-58j2-45rg | 13.0.0 | Fixed and verified | Pillow: TiffDecode returns uninitialized memory as pixels for short JPEG strips |
| pillow / GHSA-462x-pgg6-55fp | 13.0.0 | Fixed and verified | Pillow tiled-TIFF decoder reads past tile buffer in copy4 (Unpack.c:1290) |
| pillow / GHSA-c6hw-5grf-ff96 | 13.0.0 | Fixed and verified | Pillow: OOB read in TiffDecode.c tile and RGBA paths leaks heap memory into pixels |
| pillow / GHSA-vx6w-vv9f-6gvg | 13.0.0 | Fixed and verified | Pillow: EPS load(scale) lets Ghostscript render past the decompression bomb limit |
| pillow / GHSA-7mwm-ghpf-9vrm | 13.0.0 | Fixed and verified | Pillow: Double free in ImagingScaleAffine on calloc failure via Image.transform |
| pillow / GHSA-w889-685w-c8fh | 13.0.0 | Fixed and verified | Pillow: Argument Injection in Ghostscript call, potentially leading into RCE |
| pillow / GHSA-j4m9-6w36-pw47 | 13.0.0 | Fixed and verified | Pillow: Invalid free in FreeType glyph rendering when a stroker is active |
| pillow / GHSA-27h8-gf7j-v5hc | 13.0.0 | Fixed and verified | Pillow: NULL dereference in ImagingExpand via rank filters on zero-size images |
| pillow / GHSA-fc9g-5qg7-mf45 | 13.0.0 | Fixed and verified | Pillow: Quadratic GIF comment copying during save |
| pillow / GHSA-cp9v-662q-vvx9 | 13.0.0 | Fixed and verified | Pillow: NULL pointer dereference in Image.merge via an unvalidated band 0 |
| pillow / GHSA-22hg-r758-rrw9 | 13.0.0 | Fixed and verified | Pillow: Infinite loop in MIC n_frames when the embedded TIFF |
| pillow / GHSA-74r2-7ff9-mjj2 | 13.0.0 | Fixed and verified | Pillow: Quadratic GIF comment concatenation allows DoS in Image.open() |
| pillow / GHSA-xgh8-jp6q-p5x8 | 13.0.0 | Fixed and verified | Pillow: ReDoS in XbmImagePlugin: 512-byte file stalls Image.open() for minutes |
| pillow / GHSA-254f-3936-288h | 13.0.0 | Fixed and verified | Pillow: PdfParser can recurse without limit in get_value() and linearize_page_tree() |
| pillow / GHSA-jg86-v3jv-hrpm | 13.0.0 | Fixed and verified | Pillow: Quadratic-time DoS in PDF save_all (PdfParser.next_object_id) |
| pillow / GHSA-f2g6-542v-9j58 | 13.0.0 | Fixed and verified | Pillow: Infinite loop in PdfParser.rewrite_pages on page tree Parent cycle |
| pillow / GHSA-5xm2-6676-qcp9 | 13.0.0 | Fixed and verified | Pillow: APNG background disposal allocates full canvas before decompression bomb check |
| pillow / GHSA-gg2r-wvfm-q9rx | 13.0.0 | Fixed and verified | Pillow: MSP RLE decoder expands a tiny file into unbounded memory |
| pillow / GHSA-332p-7hrc-92wf | 13.0.0 | Fixed and verified | Pillow: Heap buffer overflow in _tiffWriteProc when saving TIFF to BytesIO |
| pillow / GHSA-4rr5-89j8-mwwm | 13.0.0 | Fixed and verified | Pillow: Heap use-after-free when encoding TIFF to an in-memory buffer |
| pillow / GHSA-24rc-8hj2-v98c | 13.0.0 | Fixed and verified | Pillow: BMP RLE decoder memory-amplification DoS via unbounded delta escape / absolute mode |
| pillow / GHSA-4rm8-3hmm-39fg | 13.0.0 | Fixed and verified | Pillow: Reachable undefined behavior in native integer operations, potentially leading to denial of service or logic integrity compromise |
| pillow / GHSA-mrfp-p49p-3hf2 | 13.0.0 | Fixed and verified | Pillow PDF append accepts malformed shared page-tree DAG causing resource exhaustion |
| pillow / GHSA-3j72-p6qg-6xp7 | 13.0.0 | Fixed and verified | Pillow: TarIO negative size field causes infinite CPU-spin loop |
| pillow / GHSA-v9pv-5gc8-w2m6 | 13.0.0 | Fixed and verified | Pillow multi-frame loaders can reuse stale native image storage after mode transitions |
| pillow / GHSA-g4qv-2jxx-769h | 13.0.0 | Fixed and verified | Pillow: PNG eXIf chunk makes EXIF parsing run in quadratic time |
| pillow / GHSA-g842-9rc4-69pw | 13.0.0 | Fixed and verified | Pillow: Decompression bomb check bypass in SpiderImagePlugin.seek() leads to unbounded allocation DoS |
| pillow / GHSA-9v9v-9qvf-h2hj | 13.0.0 | Fixed and verified | Pillow: Heap over-read in WMF/EMF rendering via 16-bit dimension truncation (Windows builds) |
| pillow / GHSA-g7cr-3p24-7wf7 | 13.0.0 | Fixed and verified | Pillow: Heap buffer overflow writing JPEG comment after ICC profile fills buffer |
| pillow / GHSA-p8hx-v2p6-rp84 | 13.0.0 | Fixed and verified | Pillow: Decompression-bomb protection bypass via multi-frame seek() in MPO and DCX (MpoImageFile.seek / DcxImageFile.seek) |
| pillow / GHSA-78g4-xqwv-q3g8 | 13.0.0 | Fixed and verified | Pillow: Bundled libopenjp2 2.5.4 in all wheels since 11.1.0 carries OSV-2025-219 heap-buffer-overflow write reachable from Image.open().load() |
| pillow / GHSA-654x-cwwv-5j9c | 13.0.0 | Fixed and verified | Pillow: Arrow export leaks stale heap memory when PILLOW_ALIGNMENT > 1 |
| pillow / GHSA-5x8w-8jj5-q52h | 13.0.0 | Fixed and verified | Pillow: Heap buffer overflow in FlashPix (FPX) JPEG decoding leads to code execution |
| pypdf / GHSA-5jq2-8x83-x246 | 6.21.2 | Fixed and verified | pypdf: Possible long runtimes/large memory usage when parsing indirect objects |
| pypdf / GHSA-fp3h-c4fm-7vvf | 6.21.2 | Fixed and verified | pypdf: Possible large memory usage for large /ToUnicode streams (Follow-up 2) |
| pypdf / GHSA-w23x-9jrw-r45c | 6.21.2 | Fixed and verified | pypdf: Possible large memory usage when retrieving alphabetical page labels |
| pypdf / GHSA-v247-6f48-mgcj | 6.21.2 | Fixed and verified | pypdf: Possible long runtimes with large amount of embedded files |
| pypdf / GHSA-jw7q-gvrg-4vj3 | 6.21.2 | Fixed and verified | pypdf: Possible long runtimes for partially malformed FlateDecode streams (Follow-up) |
| pypdf / GHSA-g9cg-prrw-2r8q | 6.21.2 | Fixed and verified | pypdf: Possible large memory usage when parsing font data |
| pypdf / GHSA-qv6h-rv94-w285 | 6.21.2 | Fixed and verified | pypdf: Possible large memory usage when retrieving Roman page labels |
| pypdf / GHSA-php9-fj8v-98fj | 6.21.2 | Fixed and verified | pypdf: Possible long runtimes when generating appearance streams |
| pypdf / GHSA-qfv9-64jg-mh7p | 6.21.2 | Fixed and verified | pypdf: Possible infinite loop in PdfWriter.find_outline_item |
| pypdf / GHSA-7mh2-4gg2-979f | 6.21.2 | Fixed and verified | pypdf: Possible large memory usage for streams with multiple filters |
| pypdf / GHSA-9mx8-4j7g-633p | 6.21.2 | Fixed and verified | pypdf: Possible infinite loop when removing tree items |
| pypdf / GHSA-39mj-jf6j-2qj3 | 6.21.2 | Fixed and verified | pypdf: Possible infinite loop when hitting EOF in standard xref table |
| pypdf / GHSA-5hx5-vpf9-5wcv | 6.21.2 | Fixed and verified | pypdf: Unvalidated JPEG image data loading |
| pypdf / GHSA-cgf9-327m-v77c | 6.21.2 | Fixed and verified | pypdf: Possible large memory usage when parsing content streams |
| pypdf / GHSA-f54x-cmq8-qg57 | 6.21.2 | Fixed and verified | pypdf: Possible large memory usage when parsing arrays and dictionaries |
| pypdf / GHSA-6vvc-x485-93v7 | 6.21.2 | Fixed and verified | pypdf: Possible long runtimes/large memory usage when retrieving form fields |
| pypdf / GHSA-6c7f-9265-g8fw | 6.21.2 | Fixed and verified | pypdf: Possible long runtimes for repeated references to the same missing object |
| pypdf / GHSA-jr96-gvgh-j3r4 | 6.21.2 | Fixed and verified | pypdf: Possible long runtimes for repeated malformed cross-reference entries (Follow-up) |
| pypdf / GHSA-gmh7-3g9r-mjh5 | 6.21.2 | Fixed and verified | pypdf: Possible long runtimes for large xref table header limits |
| setuptools / GHSA-xmj3-9gf7-h52w | 84.1.0 | Fixed and verified | setuptools: Windows path escape via namespace_packages.txt during legacy wheel installation Description |
| torch / CVE-2025-3001 | 2.13.0+cpu | Fixed and verified | torch.lstm_cell / native LSTM cell tensor validation |
| torch / CVE-2025-3000 | 2.13.0+cpu | Fixed and verified | torch.jit.script compilation |
| torch / CVE-2025-2999 | 2.13.0+cpu | Fixed and verified | torch.nn.utils.rnn.unpack_sequence |
| torch / CVE-2025-2953 | 2.13.0+cpu | Fixed and verified | torch.mkldnn_max_pool2d |
| torch / CVE-2025-46148 | 2.13.0+cpu | Fixed and verified | nn.PairwiseDistance(p=2), eager/Inductor inconsistent result |
| torch / CVE-2025-46149 | 2.13.0+cpu | Fixed and verified | nn.Fold Inductor code generation assertion |
| torch / CVE-2025-46150 | 2.13.0+cpu | Fixed and verified | FractionalMaxPool2d torch.compile correctness |
| torch / CVE-2025-46152 | 2.13.0+cpu | Fixed and verified | bitwise_right_shift boundary shift in Inductor |
| torch / CVE-2025-46153 | 2.13.0+cpu | Fixed and verified | bernoulli_p decomposition, fallback_random, Dropout1d/2d/3d |
| torch / CVE-2025-55551 | 2.13.0+cpu | Fixed and verified | torch.linalg.lu with slicing in Inductor/AOT |
| torch / CVE-2025-55552 | 2.13.0+cpu | Fixed and verified | torch.rot90 and randn_like compiled graph |
| torch / CVE-2025-55553 | 2.13.0+cpu | Fixed and verified | proxy_tensor.py tracing .random_ syntax error |
| torch / CVE-2025-55554 | 2.13.0+cpu | Not affected, with evidence | torch.nan_to_num then long edge-case numeric conversion |
| torch / CVE-2025-55557 | 2.13.0+cpu | Fixed and verified | Inductor compiled cummin Triton NameError |
| torch / CVE-2025-55558 | 2.13.0+cpu | Fixed and verified | Inductor Conv2d/hardshrink/view/mv compiler failure |
| torch / CVE-2025-55560 | 2.13.0+cpu | Fixed and verified | Inductor to_sparse/to_dense lowering |
| torch / CVE-2026-4538 | 2.13.0+cpu | Not affected, with evidence | torch.export.load .pt2 deserialization |
| torch / CVE-2025-3730 | 2.13.0+cpu | Fixed and verified | torch.nn.functional.ctc_loss / native LossCTC |
| torch / CVE-2026-24747 | 2.13.0+cpu | Fixed and verified | torch.load(weights_only=True) unpickler memory corruption |
| transformers / CVE-2025-14929 | 5.10.0 | Not affected, with evidence | X-CLIP checkpoint conversion unsafe deserialization |
| transformers / CVE-2025-2099 | 5.10.0 | Fixed and verified | testing_utils.preprocess_string doctest ReDoS |
| transformers / CVE-2025-14926 | 5.10.0 | Not affected, with evidence | SEW conversion convert_config string eval |
| transformers / CVE-2025-14930 | 5.10.0 | Not affected, with evidence | GLM4 weights parsing unsafe deserialization |
| transformers / CVE-2025-14920 | 5.10.0 | Not affected, with evidence | Perceiver model conversion/deserialization |
| transformers / CVE-2025-14921 | 5.10.0 | Not affected, with evidence | Transformer-XL tokenizer/model pickle deserialization |
| transformers / CVE-2025-14924 | 5.10.0 | Not affected, with evidence | megatron_gpt2 checkpoint conversion deserialization |
| transformers / CVE-2025-14927 | 5.10.0 | Not affected, with evidence | SEW-D convert_config eval |
| transformers / CVE-2025-14928 | 5.10.0 | Not affected, with evidence | HuBERT convert_config eval |
| transformers / CVE-2025-3933 | 5.10.0 | Fixed and verified | DonutProcessor.token2json ReDoS |
| transformers / CVE-2025-6638 | 5.10.0 | Fixed and verified | MarianTokenizer.remove_language_code ReDoS |
| transformers / CVE-2025-3264 | 5.10.0 | Fixed and verified | dynamic_module_utils.get_imports Python-source regex |
| transformers / CVE-2025-1194 | 5.10.0 | Fixed and verified | SubWordJapaneseTokenizer GPT-NeoX-Japanese ReDoS |
| transformers / CVE-2025-3777 | 5.10.0 | Fixed and verified | image_utils video URL username validation |
| transformers / CVE-2025-6051 | 5.10.0 | Fixed and verified | CLVP EnglishNormalizer.normalize_numbers ReDoS |
| transformers / CVE-2025-6921 | 5.10.0 | Fixed and verified | AdamWeightDecay._do_use_weight_decay user regex |
| transformers / CVE-2025-3263 | 5.10.0 | Fixed and verified | configuration_utils.get_configuration_file ReDoS |
| transformers / CVE-2025-5197 | 5.10.0 | Fixed and verified | convert_tf_weight_name_to_pt_weight_name ReDoS |
| transformers / CVE-2026-1839 | 5.10.0 | Fixed and verified | Trainer._load_rng_state unsafe torch.load |
| transformers / CVE-2026-4372 | 5.10.0 | Fixed and verified | model initialization config attention-kernel code loading |
| transformers / CVE-2026-5241 | 5.10.0 | Fixed and verified | LightGlue nested AutoConfig remote-code override |
| transformers / CVE-2026-9856 | 5.10.0 | Fixed and verified | tokenizer/Processor save_pretrained chat_template traversal |
| urllib3 / GHSA-vxq7-64xx-v4gw | 2.8.0 | Fixed and verified | urllib3: HTTPResponse.stream()/read_chunked() buffers an unbounded chunk-size line into memory |
| urllib3 / GHSA-gh4c-6fx4-qh6g | 2.8.0 | Fixed and verified | urllib3: Chunked Deflate streaming can enter an infinite loop |
| urllib3 / GHSA-8988-9cw3-xx77 | 2.8.0 | Fixed and verified | urllib3: HTTPS proxy TLS configuration may be ignored or overridden |
Additional test group: pytest GHSA-6w46-j5rx-g56g/CVE-2025-71176 —8.3.5→9.0.3, fixed/version-verified with59-case successor and fresh installed audit. It is not silently merged into the original109.
Production cache ownership/migration, base/native package supply chain, full trained checkpoint, GPU, C11/AI semantics, genuine manual/device/provider evidence and production recovery remain independent qualifications. Actual API-level cancellation of full-model inference is not established by the bounded qualification worker.
## Final25October2026 qualification
All109 original groups retain individual dispositions:65 previously addressed plus44 assessed here produce99 fixed/version-verified and10 narrowly not affected within the actual Jobjakt path. One separately tracked pytest group is fixed at9.0.3. No upstream vulnerability is declared globally fixed merely because its path is unused.
The actual source image with exact55 runtime/61 test pins passes59 sidecar cases and both real BART formats,9 integrity/lock cases, synthetic parser/OCR and HTTP startup. The original trained DistilBART checkpoint also passes actual offline repository-cache loading,1024-token processing, finite logits, generation and auth/repeat-cache contracts under Torch2.13/Transformers5.10. Its pinned1,222,317,369bytes match SHA2563bac65d18c99463302d12ca75c2220ea714f9c81ce235f205fa818efe71df6ea.
Final installed review covers63 distributions/126 queries and0 advisory records, with the retained vendor PyPI404 for torch2.13.0+cpu. The scanner therefore remains INCOMPLETE; conditional scoped security qualification uses separate official wheel/vendor/current-source and real-model evidence. This is not a clean two-provider scan, image-wide/stdlib audit, semantic AI approval or production deployment. See validation.json, verdicts.json and the final qualification hashes in DISPOSITIONS.json.
@@ -0,0 +1,72 @@
# P9-SEC-02 finding register
All inherited criteria, sources, evidence, severity, dependencies, owners and closure requirements remain in [findings.json](findings.json). Separate gates are retained; one finding may affect several gates. Manual/provider/production facts remain untested.
| ID | Current disposition | Owner / required closure |
| --- | --- | --- |
| RD01 | OPEN; local static/loopback ingress contracts only | Release operator: actual TLS/IPv6/firewall/topology/trusted peer and deployed auth evidence |
| RD02 | NOT TESTED: independently verified off-disk complete backup/restore | Release operator: isolated restore of DB/files/CVs/keys/tombstones, hashes and recovery rehearsal |
| RD03 | Current actual MariaDB lane and bounded sustained-workload results are in validation.json. Runtime/provider scope only; no hosted execution, capacity SLA, production migration or restart claim. | Database owner: actual approved MariaDB migration, restart, CRUD/constraints/concurrency and effective configuration proof |
| RD04 | NOT TESTED: intended Linux rollback | Release operator: isolated failure/rollback rehearsal using complete prior images/configuration/recovery set |
| RD05 | BLOCKED: dedicated label queued/unassigned in observed metadata; effective current runner isolation/lifecycle unverified;0 hosted MariaDB cases. | CI/operator owner: prove isolated private service execution and lifecycle without host socket/privileges/public ports/production coupling, then successful exact hosted TRX and cleanup. Keep workflow BLOCKED while isolation cannot be proven. Separate deployed runner/storage/release identity remains unqualified. |
| RD06 | PARTIAL: finite axe/DOM/keyboard evidence; human checks open | Accessibility tester: [M09-01–06](../p9-03/MANUAL_CHECKLIST.md), contextual contrast/reader evidence; triage every applicable incomplete |
| RD07 | NOT TESTED: physical input/AT/alternate browsers/forced colors | Product/accessibility owners: actual supported devices/browser/input versions and complete workflows |
| RD08 | DEFERRED; no new model qualification or activation | Separate AI qualification owner: production-equivalent identity/inference, original 366-call protocol, independent human semantics, review UI/integration evidence |
| RD09 | Local withheld-operation contract retained; deployed withholding NOT TESTED | Release/AI owners: keep 503/no-provider/no-write guards, verify actual deployment independently |
| RD10 | PASS within current original Linux24 and supplemental2 scope; Windows results separate; no physical-print/human qualification. | Document owner: intended Linux/fonts/photo/crop/print and alternate-browser proof, original bytes/geometry |
| RD11 | Scoped SQLite bootstrap/WAL mechanism repaired before entry; broad reliability remains PARTIAL | Database owner: retain held-reader/write proof, distinguish old reproduced mechanism from unproven provider/contention cases |
| RD12 | PARTIAL: notification draft/failure recovery and SQLite tests; complete contention/provider behavior unqualified | Database/settings owners: intended-provider overlapping writes and failure/reload recovery with no data loss |
| RD13 | Historical Rules 500 mechanism remains UNCONFIRMED | Rules/API owners: original failure trace plus controlled causal reproduction and successor regression; passing retry alone insufficient |
| RD14 | Historical command/dialog focus incident remains UNCONFIRMED; settled drawer proof is a separate finite result | Shared UI owner: preserve original observations, reproduce affected modal transitions and actual reader/trap/return behavior |
| RD15 | Historical intermittent CV section expansion cause unproven | CV owner: retain failed observation and reproduce causally before closing; do not weaken expansion assertions |
| RD16 | Scoped company-error repair retained; wider reader/dialog/date contract PARTIAL | Company/UI owners: native failed-save → retained draft → successful retry plus human dialogue checks |
| RD17 | Current actual MariaDB lane and bounded sustained-workload results are in validation.json. Runtime/provider scope only; no hosted execution, capacity SLA, production migration or restart claim. | Jobs owner: agreed budget, bounded sustained profile and CPU/frame attribution before optimization; preserve full membership |
| RD18 | NOT TESTED: physical drag/drop/cancel/browser variants | Input/device tester: real Board/CV selection and named alternatives, no hidden result cap |
| RD19 | DEFERRED: reviewed `followMode` consumer | Product/mail owner: separate explicit mode→review/action/fallback design; no auto-send or uncertain resend |
| RD20 | Optional P5-05 quick preview DEFERRED; Phase 8 Dashboard scope was delivered separately | Product owner: explicit separate brief; retain existing full workspace and all routes |
| RD21 | RESOLVED within original tested save/concurrency scope; current backend/MariaDB/recovery companions in validation.json; creation idempotency is separate. | Domain/API/UI owners: separate bounded contract issue covering both callers, server compare-and-swap/transaction semantics, conflict recovery and backward compatibility; characterization is not safety acceptance |
| RD22 | NOT TESTED: enabled-worker outage recovery/durability | Worker owner: isolated enabled-producer failure/restart/recovery, no-loss/no-duplicate proof before activation |
| RD23 | OPEN: actual calendar offset/DST/date-only semantics | Calendar owner: dedicated boundary/DST/provider proof in authorised sandbox before semantic changes |
| RD24 | NOT TESTED: billing/deletion/retention/provider cleanup policy and configuration | Product/security/operator owners: approved policy, explicit destructive-action authority, isolated recovery/cleanup proof |
| RD25 | PARTIAL: local SMTP/HTTP/provider contracts; actual OAuth/Turnstile/mail/calendar/model unavailable | Approved provider/human tester: sandbox consent/revoke/reconnect/origin/state/delivery/uncertain-attempt proof |
| RD26 | Legacy Job/Application cutover OPEN | Migration owner: expand/verify/contract, restore/rollback and all readers/writers/aliases before removal |
| RD27 | NOT TESTED: actual monitoring/alert/recovery coverage | Operations owner: effective sink, alert trigger, responder/runbook and recovery observations |
| RD28 | Ongoing evidence/provenance obligation | QA owner: exact source hashes/counts, original failures, no retries/skips/assertion relaxation; separate characterization from safe behavior |
| P9-OPS-01 | Previously reported EXT4/Docker storage errors UNRECHECKED | Production operator only: independent storage-health/repair and recovery qualification under separate authority |
| P9-SEC-01 | CONDITIONAL PASS: original109 dispositions99 fixed/version-verified and10 scoped not affected; separate pytest advisory fixed; actual model and final scan evidence in current package. | Security/sidecar owners: complete narrowly scoped filelock cache/protocol compatibility work, select a patched compatible CPU Torch/Transformers graph, verify immutable model/checkpoint identities and startup/inference/extraction contracts in an approved environment; serious residual risk requires explicit owner disposition. No automatic waiver, model change/download or production action. |
| P9-PUB-01 | Normal checkpoint pushes22ef8d0/30e251a verified. Final evidence commit/remote/clean-tree/main receipt required and recorded in publication ledger/final delivery; no force push or merge. | QA: retain failed attempts and verify each subsequent normal push; no force push |
| P9-T01 | RESOLVED within mapped automated scope; fresh complete regression PASS; manual qualifications unchanged. | QA; `.artifacts/phase9/sidecar-entry-failed.*`, `sidecar-fixture-red.*`, `sidecar-fixture-green.*`, `sidecar.xml` |
| P9-L01 | RESOLVED within mapped automated scope; fresh complete regression PASS; manual qualifications unchanged. | Frontend; `admin-users-page.test.tsx`, `AdminUsersPage.tsx`; retained RED/GREEN logs/JSON |
| P9-V01 | RESOLVED within mapped automated scope; fresh complete regression PASS; manual qualifications unchanged. | Frontend; `LandingPage.tsx`, new `landing-presentation.spec.ts`; `landing-red`, `landing-qualified`, `landing-accepted` raw reports |
| P9-V02 | RESOLVED within mapped automated scope; fresh complete regression PASS; manual qualifications unchanged. | Frontend/QA: preserve existing LandingPage lineHeight1.4 and exact CTA+heading geometry assertions; qualify fresh complete landing and ordinary successors on frozen source, retain original RED/GREEN evidence and native-width images |
| P9-L02 | RETAINED low development debt | UI/localisation owner; separately map known event enums with unknown-value fallback and history/audit tests; human wording review |
| P9-T02 | RESOLVED within mapped automated scope; fresh complete regression PASS; manual qualifications unchanged. | QA; `phase7-admin-users.spec.ts`; original shard report/trace and `admin-grid-green` retained. Other English-name callers belong to the separate English JobTable owner and remain unchanged. |
| P9-PERF-01 | RETAINED low development debt | Shared reminder read owner; measured benefit and independent shell/dashboard failure/loading tests before consolidation. |
| P9-T03 | RESOLVED within mapped automated scope; fresh complete regression PASS; manual qualifications unchanged. | QA: retain failed run, unchanged no-write assertions, fixture config delta and fresh full successor |
| M09-01 | NOT TESTED | accessibility tester: Names, roles, values, selected state, headings, reading order and errors are understandable; retain reader/version and spoken observations. No hidden background content is announced. |
| M09-02 | NOT TESTED | accessibility tester: Visible focus, logical order, genuine traps only while modal, Escape and focus restoration; no off-screen/hidden tab stops. Record any transition-specific failure. |
| M09-03 | NOT TESTED | accessibility tester: Each action/position/save/error announces once and agrees with visible DOM order; pointer drag has an equivalent keyboard route. |
| M09-04 | NOT TESTED | accessibility tester: Applicable normal text ≥4.5:1, large text ≥3:1 and necessary UI boundaries/focus ≥3:1. Record sampled colors/ratios/state. An axe incomplete is not sufficient to close the row. |
| M09-05 | NOT TESTED | accessibility tester: Invisible zero badge is absent from announcements; live unread count remains meaningful; closed drawer is neither read nor tabbable. Runtime DOM checks cover only the tested states. |
| M09-06 | NOT TESTED | accessibility tester: Essential controls remain reachable/readable, no lost content or focus; distinguish intentional table/document scrollers from root clipping. Preserve fixed A4/Letter geometry. |
| M09-07 | NOT TESTED | product owner with physical devices: No keyboard-obscured primary action/data loss; reachable touch targets, no accidental destructive action; record device/input mode. Emulated touch does not close this. |
| M09-08 | NOT TESTED | Bokmål reviewer: Natural professional Bokmål, consistent established terms, meaningful messages. Separate authored English content, technical names and provider strings from untranslated application copy. |
| M09-09 | NOT TESTED | document reviewer: Legible fonts, intact glyphs/diacritics, margins, page boundaries, searchable text, photo/crop, correct language/date output and no missing/duplicated content. Retain original bytes, renderer/font versions and print observations. |
| M09-10 | NOT TESTED | approved provider tester: Correlated origin/state, explicit confirmation, no accidental resend, correct ownership/timezone. Local SMTP/HTTP fixtures do not close external-provider qualification. |
| P9-AX-01 | Requires manual inspection | Accessibility tester: Shared Dashboard drawer settled predicate, Escape focus and24Tab proof pass. Original Analytics transition cause is not proven; human reader/transition qualification remains. |
| P9-AX-02 | Requires manual inspection | Accessibility tester: Contextual foreground/background measurement remains required. |
| P9-AX-03 | Requires manual inspection | Accessibility tester: Contextual foreground/background measurement remains required. |
| P9-AX-04 | Not applicable in tested settled hidden state | Accessibility tester: Four current native EN/NB theme vectors: aria-hidden=true and zero area. Actual reader/live unread-state remains separate. |
| P9-REQUAL-SEC01 | LOCALLY REMEDIATED; post-pin audits zero and complete affected frozen-source successors PASS; production NOT DEPLOYED. | Dependency/QA owner: Direct compatible package override System.Security.Cryptography.Pkcs8.0.2; retain MimeKit4.17.0 ownership. Retain before/after advisory paths, raw hashes and exact lock/pin delta; complete frontend/browser and required full successors, then bind all reports to final source. Production deployed dependencies/exposure remain independent. |
| P9-REQUAL-SEC02 | LOCALLY REMEDIATED; post-pin audits zero and complete affected frozen-source successors PASS; production NOT DEPLOYED. | Dependency/QA owner: Pin Next and eslint-config-next exactly16.4.1. Existing static export, unoptimized images and Sharp0.35.5 mitigate the image-serving path; they do not close every package advisory. Retain before/after advisory paths, raw hashes and exact lock/pin delta; complete frontend/browser and required full successors, then bind all reports to final source. Production deployed dependencies/exposure remain independent. |
| P9-REQUAL-SEC03 | LOCALLY REMEDIATED; post-pin audits zero and complete affected frozen-source successors PASS; production NOT DEPLOYED. | Dependency/QA owner: Use compatible existing ^4 dependency range via Zod4.6.6 override; do not add runtime functionality. Retain before/after advisory paths, raw hashes and exact lock/pin delta; complete frontend/browser and required full successors, then bind all reports to final source. Production deployed dependencies/exposure remain independent. |
| P9-REQUAL-SEC04 | CONDITIONAL PASS: original109 dispositions99 fixed/version-verified and10 scoped not affected; separate pytest advisory fixed; actual model and final scan evidence in current package. | Security/sidecar owners: complete narrowly scoped filelock cache/protocol compatibility work, select a patched compatible CPU Torch/Transformers graph, verify immutable model/checkpoint identities and startup/inference/extraction contracts in an approved environment; serious residual risk requires explicit owner disposition. No automatic waiver, model change/download or production action. |
| P9-REQUAL-DB01 | LOCALLY REPAIRED at2b26953; three real RED/GREEN cases, full35 MariaDB/1123 backend and complete successor browser/workload PASS. | API DocumentsIndexService owner: narrow read-only projection fix, actual MariaDB regression including tenant/search/data preservation, fresh affected full successors |
| P9-REQUAL-PDF01 | PASS within current original Linux24 and supplemental2 scope; Windows results separate; no physical-print/human qualification. | Document/QA owners: bind final frozen-source Linux and Windows24-fixture results to unchanged oracle/content/geometry checks, review intentional portable font replacement and retained historical bytes; human/physical printing remains M09-09, not automated closure. |
| P9-REMED-PTR01 | RESOLVED within tested scope: focused unitRED/46GREEN and native6GREEN retained; final complete935 frontend/362 ordinary browser PASS with no retries/skips. Source review found no remaining Important issue. | Frontend/QA owners: retain direct-region focus scrolling/mobile-pane selection while preventing descendant-control target movement; bind unit46/46 plus held-pointer4/4 and stale-draft/admin6/6 focused proof to final935 frontend/362 browser successors. No blanket timeout increase or assertion weakening. |
| P9-SEC02-MODEL | PASS | Development QA/security owner: actual pinned trained-model and smaller-format/cache/OCR evidence |
| P9-SEC02-PYTEST | Fixed and verified at pytest9.0.3;59-case actual Linux suite and final scan separately recorded | Development owner: maintain exact test lock and compatible test layer |
| P9-SEC02-CLEANUP | Independent review Important fixed; negative/timeout guards and actual model successors verify positive absence | QA harness owner: keep unknown cleanup as failure and preserve bounded ownership checks |
| P9-SEC02-OAUTH | Successor PASS with original88-case shard retained | Browser QA owner: retain source/origin/owner/read-count assertions and actual destination/disposal prerequisite |
A: Phase9 mandatory local functional/security criteria are evaluated in verdicts.json. B: CV-UX needs its own issue/scope/entry decision. C: Phase10 needs candidate-specific unused-code/route/test/inventory proof. D: production alone retains live recovery/security/deployed/provider/human gates. E: duplicate reminder reads, creation-intent idempotency and optional deferred work remain visible in their inherited records; none is silently folded into RD21 closure.
@@ -0,0 +1,23 @@
# Owner and operator qualification still required
All ten M09 human/provider cards remain **NOT TESTED**. Use the existing [reproducible cards](../p9-remed-02/MANUAL_ACCEPTANCE.md), which retain their original actions, expected behaviour, recordings and pass/fail criteria. This task supplies no human sign-off. Record the tested commit, actual browser/device/assistive-technology version, language/theme, synthetic account, exact card ID and recording; an automated result cannot replace that evidence.
Prioritise screen-reader reading order and announcements, keyboard/focus and cancellation, contrast/forced colours, actual browser zoom, physical touch/drag and orientation, Bokmål, PDF reopening/physical printing, and provider sandbox/outage recovery. Keep these separate. Preserve failures and incomplete observations. No production account, private CV or live provider connection is required for the local cards. Live provider qualifications require their separately approved environment and owner.
For a local owner session, use the source/build identities in [validation.json](validation.json), a synthetic isolated account and development MariaDB. Keep unavailable integrations and C11/P5-13 withheld. Do not interpret an enabled button or a healthy endpoint as intended-model, semantic or provider acceptance.
## Hosted runner operator
Follow the six ordered actions in [CI_ASSESSMENT.md](CI_ASSESSMENT.md). Supply effective job/service configuration and success/failure/cancel/interrupted-run cleanup evidence from a dedicated nonproduction runner. An assigned label, working Docker CLI or successful backup job is insufficient. No production Docker socket, database, deployment runner or secrets may be connected to this test lane. Hosted CI stays BLOCKED until real MariaDB execution and isolation evidence exist.
## Model/cache rollout owner — separate production gate
The local qualification uses newly prepared, private, immutable-identity test artifacts. It does not modify or approve an existing production cache. Before any separately authorised rollout:
1. Establish independent off-disk backup/restore and filesystem integrity evidence. Earlier EXT4/checksum reports remain unverified.
2. Review the exact image, Python/native packages, pinned checkpoint manifest/licence and available memory/storage in a nonproduction rehearsal.
3. Prepare and verify a separate cache. Prove its ownership and permissions. Do not mix old and new filelock participants or reset production/Ollama caches.
4. Test offline cold start, actual extraction/inference, missing/corrupt artifacts, bounded resources, service failure and recovery using synthetic documents. Record the selected image/checkpoint identities and actual network behaviour.
5. Review cache-switch/rollback and old-participant shutdown with the operator before deployment. This document does not authorise those operations or accept residual security risk.
GPU/driver compatibility, human semantic quality/C11, production capacity, application-level cancellation of in-flight trained-model inference, production cache migration and release approval are not established by the local CPU fixture. Their relevance must be decided against the separately authorised deployment/feature requirements.
+10 -2
View File
@@ -6,7 +6,7 @@ The selected full repository `sshleifer/distilbart-cnn-12-6` advertises Apache-2
## Small task-authorised fixtures
[ARTIFACTS.json](model/ARTIFACTS.json) records two independently hashed, isolated fixtures. Their tokenizer/vocabulary/merges/model-card and reference configuration come from the immutable upstream revision. Every downloaded ordinary Git file is checked against the published Git blob identity, then pinned with SHA256. Only1,358,673 bytes of upstream metadata/tokenizer content were downloaded. No pretrained checkpoint or remote Python code was downloaded.
[ARTIFACTS.json](model/ARTIFACTS.json) records two independently hashed, isolated fixtures. Their tokenizer/vocabulary/merges/model-card and reference configuration come from the immutable upstream revision. Every downloaded ordinary Git file is checked against the published Git blob identity, then pinned with SHA256. The initial small-fixture stage downloaded1,358,673 bytes of upstream metadata/tokenizer content. It used no pretrained checkpoint or remote Python code. The separate trained-checkpoint follow-up below is additional evidence, not a relabelling of those small fixtures.
Synthetic BART weights are generated locally with fixed seed73421 using the Apache-2.0 Transformers BART implementation: vocabulary50265, dimension16, one encoder/decoder layer, two heads,32-wide feed-forward layers and1024 positions. The842704 parameters are saved once as Safetensors and once as a known state dictionary. These files are approximately3.58MB each. The second format exercises the same PyTorch serialization family as the selected full checkpoint, with explicit `weights_only=True`. No third-party pickle or trained-weight licence is assumed. The actual tokenizer's Apache-2.0 declaration is preserved from its pinned card; no model weights are redistributed in Git.
@@ -20,4 +20,12 @@ The production model choice is unchanged. A minimal loader repair now pins token
filelock4 changes shared-cache lock protocols. All qualification caches are new isolated disposable directories with a single library generation. No production or developer cache was reset, rewritten or silently mixed with old lock participants. A later production rollout must stop old participants and explicitly select a separately prepared/verified cache or establish documented protocol migration compatibility. That operator action is separate from development fixture compatibility and remains withheld.
Actual compatibility, negative/offline/cache contention/OCR results and any limitations are recorded separately as they execute. The full checkpoint remains absent; no large download was used to manufacture a qualification claim.
Actual compatibility, negative/offline/cache contention/OCR results and any limitations are recorded separately as they execute. The separate trained-checkpoint follow-up uses the actual configured Apache-2.0 repository and pinned1,222,317,369-byte checkpoint, with sufficient nonproduction storage/CPU/memory verified before preparation. Its actual download, integrity, offline Hub-cache loading and generation outcome is reported in validation.json; a failed or unavailable follow-up is not replaced by the small fixture. No full-model semantic, GPU or production claim follows.
The full checkpoint is necessary because the tiny fixture does not reproduce the saved trained configuration: the selected model has1024-wide embeddings,12 encoder/6 decoder layers and50264 model vocabulary entries, while its tokenizer has50265 entries. The small fixture deliberately uses16-wide embeddings and50265 entries. Successful tiny-model inference cannot prove compatibility of those original tensors/configuration with Transformers5/Torch2.13. The follow-up keeps the existing model choice, uses synthetic text and constrains the nonproduction process to4CPU/8GiB/128PIDs/300seconds. It exercises the pinned repository revision through a private offline Hub snapshot cache, with blobs pointing to the already verified read-only artifact files. No production or Ollama cache participates.
For replay, [full-model/prepare.py](full-model/prepare.py) accepts only a new nonproduction directory, the committed immutable source revision and HTTPS repository paths. It checks licence declaration, available space, exact sizes and SHA256 before promoting each partial file. Existing directories are rejected without replacement. [full-model/ARTIFACTS.json](full-model/ARTIFACTS.json) is generated only after successful original preparation; its absence means the follow-up has not supplied a validated artifact. Use the exact qualified image and offline command retained with the actual result; a new runtime requires requalification.
The native English OCR artifact is independently identified by [OCR_ARTIFACT.json](model/OCR_ARTIFACT.json): Debian `tesseract-ocr-eng`1:4.1.0-2,4113088bytes, SHA256`7d4322bd2a7749724879683fc3912cb542f19906c83bcc1a52132556427170b2`. Its installed [copyright notice](model/OCR_COPYRIGHT.txt) identifies `tessdata_fast` and Apache-2.0. This is a file identity inside the exact measured local image, not a claim that a future floating apt install is immutable. Actual PNG/image-PDF OCR is part of the parser qualification.
The two exact small fixtures are retained in a local9,895,179-byte replay capsule, [fixture-capsule.json](model/fixture-capsule.json), SHA256`a1aff347e5f08f82e8ea7176d71d00e7f83ea5735acbdc4e3bf02c73deacb643`. Archive CRC and every artifact hash were checked. Verify that archive identity, then restore only the manifest-listed members into new isolated `artifact`/`artifact-bin` directories and run `verify_fixture` before loading. No weights were committed or uploaded. The original generator used Torch2.6/Transformers4.48; regenerating under different libraries is not promised to produce byte-identical serialization and requires a new manifest/qualification.
@@ -0,0 +1,7 @@
# P9-SEC-02 preservation
The [complete57-group/33-route register](preservation.json) carries every original criterion, owner and qualification forward. **56 remain PARTIAL; C11 remains DEFERRED.** Neither status is silently converted to PASS.
Current actual lanes and exact discovery membership are recorded in [validation.json](validation.json). The shared model loader gains immutable revision/remote-code/restricted-weight controls; no API/model choice, Career Profile/CV canonical ownership, revisions, null-as-inherit settings or stored document bytes are redesigned. The browser fixture adds a real destination/disposal prerequisite while retaining every source/origin/owner/read-count assertion.
Creation idempotency, duplicate reminder reads, C11/P5-13 semantics/withholding, human accessibility/devices/providers and release recovery remain independently classified in [FINDINGS.md](FINDINGS.md). A passing CPU model does not close product-level semantic AI acceptance or authorize CV-UX/CV-IMPORT/Phase10.
@@ -0,0 +1,46 @@
# Reproduce the qualification
Run from the repository root on a dedicated development checkout. Preserve previous evidence directories and developer data. Use new attempt names/directories; the helpers refuse to overwrite evidence. All database credentials are development-only. Do not point these commands at production.
## Runtime and artifacts
Use the exact local image identities in [model/RUNTIME.json](model/RUNTIME.json). They are local image IDs, not pullable registry manifest references. Verify them with `docker image inspect`. The source runtime build, exact installed inventory, native packages, lock SHA256 values and command outcomes are retained in the qualification records. A rebuild with different base/apt/bootstrap inputs requires a new image identity and qualification; this package does not claim a hermetic OS rebuild.
The application lock contains55 exact hash-checked Linux packages; the development lock retains all55 and adds6 exact test packages. The actual qualified test environment has63 distributions, including its2 separately inventoried bootstrap tools. Use `pip --require-hashes` and the official PyTorch CPU index, never an unrestricted upgrade. [Qualification.Dockerfile](model/Qualification.Dockerfile) adds only the6 locked test extras to the verified runtime; its retained build context is `.artifacts/p9-sec-02/test-lock-patched/`.
For the small fixtures, verify the retained [capsule identity](model/fixture-capsule.json), copy only its manifest-listed members into **new** `.artifacts/p9-sec-02/artifact/` and `artifact-bin/` directories, and validate with [verify_fixture](model/verify.py) against the committed [manifest](model/ARTIFACTS.json). The binary weights are intentionally absent from Git. A regenerated fixture with different bytes needs a new manifest and qualification.
For the original trained model, use:
```powershell
python docs/redesign/phase-9/p9-sec-02/full-model/prepare.py NEW_NONPRODUCTION_DIRECTORY
```
The exact reviewed revision, Apache-2.0 declaration, HTTPS source paths, storage bound, file sizes and hashes are checked before loading. This prepares approximately1.23GB of artifact data. It does not change Ollama or an existing cache. Replay the **actual retained full-model Docker command** with that new directory as the read-only `/fixture` mount; retain `--network none`, offline flags, nonroot user, read-only root filesystem and resource limits. The command/probe/manifest/image identity and positive container cleanup are part of the result, not optional environment assumptions.
The six smaller/runtime lanes are individually replayable with unique attempt names:
```powershell
python docs/redesign/phase-9/p9-sec-02/model/run.py sidecar NEW_SIDECAR_ATTEMPT
python docs/redesign/phase-9/p9-sec-02/model/run.py safetensors NEW_SAFETENSORS_ATTEMPT
python docs/redesign/phase-9/p9-sec-02/model/run.py weights-only NEW_WEIGHTS_ATTEMPT
python docs/redesign/phase-9/p9-sec-02/model/run.py cache NEW_CACHE_ATTEMPT
python docs/redesign/phase-9/p9-sec-02/model/run.py parsers NEW_PARSER_ATTEMPT
python docs/redesign/phase-9/p9-sec-02/model/run.py inventory NEW_INVENTORY_ATTEMPT
```
These use the exact qualified image and isolated test artifacts; no inference is mocked in the dedicated inference probes. The59-case sidecar suite includes controlled/model-disabled units separately, including real parser-child timeout, capacity release and process-tree termination tests. It does not establish application-level cancellation of in-flight model HTTP requests.
## Application and database regression
Use `C:/Users/Connor/.dotnet/dotnet.exe`9.0.317 and the repository's installed locked Node dependencies. Actual commands, environment, timestamps, exit codes, TRX/JUnit/Playwright reports, discovery and input hashes are indexed by [validation.json](validation.json). Backend, frontend, four serial ordinary shards, six separate browser-contract lanes, RD21 companions, diagnostics and both volume lanes have separate totals. Disable Playwright retries; do not add focused or failed predecessor executions to the complete successor totals.
Use [the existing MariaDB integration runner](../../../../scripts/mariadb-integration.py) with the pinned official12.2.2 image and generated disposable schemas. The local database service has loopback-only port33308, tmpfs data and no persistent development volume. [mariadb-lane.py](mariadb-lane.py) retains browser recovery, independent HTTP observations and the paced15-minute workload. Run that workload alone, without model loads, builds, browser suites or rendering jobs. Keep current server/version/image and generated-schema ownership checks. Cleanup removes only owned disposable resources; never use `down -v`, broad prune or a production endpoint.
## PDF and source preservation
[linux-run.py](linux-run.py) reuses the original renderer lifecycle, verifies the local immutable image and API source lineage, and retains the unchanged fixture readiness token. The first guard-rejected attempt is preserved separately. The `representative-linux` attempt selects the existing2-document supplemental configuration; use a fresh evidence checkout if that reserved attempt already exists. Normal fidelity attempts take unique names.
Run the existing `p9-requal-01/pdf-proof.py` with the new fidelity/settings roots, output directory and explicit `--platform windows` or `linux`. Preserve the original `scripts/verify-cv-fidelity.py` hash `64f82e622cc11483c33307d987e969f6cf27f82ab6bdbd72c2aeb1bfbceade87`. A renderer exit code alone cannot satisfy the24-fixture content/layout oracle. Physical printing and owner image review remain separate.
[reconcile.py](reconcile.py) checks exact discovery membership, native reports, fixture supersession, image/artifact/input identities and positive cleanup. `--collect-only` records incomplete results honestly; its exit0 means collection succeeded, not acceptance. Normal reconciliation remains nonzero while required hosted automation is BLOCKED. [verdicts.json](verdicts.json) makes the independently scoped development/entry/release decisions.
@@ -0,0 +1,97 @@
{
"observedUtc": "2026-10-25T12:32:06.793055+00:00",
"method": "GET metadata only; existing Git credential used only in memory; redirects refused",
"requests": {
"runs-branch-query": {
"httpStatus": 200,
"path": ".artifacts/p9-sec-02/ci-final-refresh/runs-branch-query.json",
"bytes": 8219,
"sha256": "b499f4634f152939a2c584b14b6eb02ec1de75b5ef92fd4a97a676525891a271"
},
"jobs-857": {
"httpStatus": 200,
"path": ".artifacts/p9-sec-02/ci-final-refresh/jobs-857.json",
"bytes": 653,
"sha256": "ce6b547248f7236eed2c5589e5a7592e5bf25f895d904d130137f5edfa1db13e"
},
"jobs-856": {
"httpStatus": 200,
"path": ".artifacts/p9-sec-02/ci-final-refresh/jobs-856.json",
"bytes": 653,
"sha256": "199e3c4bbf0b3bb9d97881ee0754b8842144044c6b5a5365ad718a3e05a7d1af"
}
},
"returnedRunCount": 2,
"branchRuns": [
{
"id": 857,
"head_sha": "30e251a593849649173badd45ffd7615cda1f85e",
"head_branch": "fix/p9-model-cache-and-ci-qualification",
"status": "queued",
"conclusion": null,
"html_url": "https://git.cesnimda.uk/cesnimda/jobtrackingapp/actions/runs/857",
"created_at": null,
"updated_at": null
},
{
"id": 856,
"head_sha": "22ef8d003c8afcab7b901060a224e1434a7a761c",
"head_branch": "fix/p9-model-cache-and-ci-qualification",
"status": "queued",
"conclusion": null,
"html_url": "https://git.cesnimda.uk/cesnimda/jobtrackingapp/actions/runs/856",
"created_at": null,
"updated_at": null
}
],
"jobs": [
{
"runId": 857,
"head_sha": "30e251a593849649173badd45ffd7615cda1f85e",
"jobs": [
{
"id": 1747,
"name": "mariadb",
"status": "queued",
"conclusion": null,
"runner_id": 0,
"runner_name": null,
"started_at": "1970-01-01T00:00:00Z",
"completed_at": "1970-01-01T00:00:00Z",
"labels": [
"jobtracker-mariadb-isolated"
]
}
]
},
{
"runId": 856,
"head_sha": "22ef8d003c8afcab7b901060a224e1434a7a761c",
"jobs": [
{
"id": 1746,
"name": "mariadb",
"status": "queued",
"conclusion": null,
"runner_id": 0,
"runner_name": null,
"started_at": "1970-01-01T00:00:00Z",
"completed_at": "1970-01-01T00:00:00Z",
"labels": [
"jobtracker-mariadb-isolated"
]
}
]
}
],
"newHostConfigInspected": false,
"newLogsDownloaded": false,
"baselinePushCommit": "30e251a593849649173badd45ffd7615cda1f85e",
"hostedVerdict": "BLOCKED",
"isolationProof": false,
"limits": "One bounded branch metadata query; no logs, dispatch, cancel, host or production access. Queue/assignment is not isolation proof.",
"workflow": {
"path": ".gitea/workflows/mariadb-integration.yml",
"sha256": "5fb3d4294a7b375b8883f618bbb87ae4028ff87ce623b38910c5898c44902287"
}
}
@@ -0,0 +1,32 @@
{
"status": "PASS",
"observedUtc": "2026-10-25T12:36:44.738264+00:00",
"context": "desktop-linux",
"removedContainer": "jobtracker-it-p9-requal-mariadb-test-1",
"removedContainerId": "21968d49cb7eb10282ada8b12e96ac350b720c922c0b8cac415ae3222472803b",
"generatedSchemasAbsentBeforeRemoval": true,
"containerAbsent": true,
"labelledModelContainersAbsent": true,
"qualificationApiContainersAbsent": true,
"developmentContainer": {
"name": "jobtracker-local-mariadb-dev-1",
"id": "9586dffa6f909794a8bd35a6239c03f969de9a530eea75cd01323584630b0f4c",
"status": "exited",
"stateAndMountsUnchanged": true
},
"developmentVolume": {
"name": "jobtracker-local_mariadb_dev",
"metadataUnchanged": true
},
"serverLogs": {
"server.stdout.log": {
"bytes": 1045,
"sha256": "c1c082248ea7c6226964605932624177d2581373190fd13794f0881177402f1a"
},
"server.stderr.log": {
"bytes": 9485,
"sha256": "3176e9695c2b231c473e2f0e15b169bbe71d81af6f4b7aac88d83147d8f0fc29"
}
},
"scope": "Only the exact owned tmpfs test service removed. No volume deletion, broad prune/down, historical user data, production operation or unrelated-container change."
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,57 @@
{
"weights-only": {
"fixture": "actual-distilbart-cnn-12-6",
"sourceRevision": "a4f8f3ea906ed274767e9906dbaede7531d660ff",
"license": "Apache-2.0 pinned model card",
"files": [
{
"file": "pytorch_model.bin",
"bytes": 1222317369,
"sha256": "3bac65d18c99463302d12ca75c2220ea714f9c81ce235f205fa818efe71df6ea",
"source": "https://huggingface.co/sshleifer/distilbart-cnn-12-6/resolve/a4f8f3ea906ed274767e9906dbaede7531d660ff/pytorch_model.bin",
"license": "Apache-2.0 pinned upstream model card"
},
{
"file": "README.md",
"url": "https://huggingface.co/sshleifer/distilbart-cnn-12-6/resolve/a4f8f3ea906ed274767e9906dbaede7531d660ff/README.md",
"gitBlobId": "ab24d89a622b44fba741e4383213ad300fc2345a",
"bytes": 1705,
"sha256": "e6114f9ddddd7aec5e9858b9849d1b53dc42b596420888b82fbf3f8defb64bf7",
"license": "Apache-2.0, pinned upstream model-card declaration"
},
{
"file": "config.json",
"url": "https://huggingface.co/sshleifer/distilbart-cnn-12-6/resolve/a4f8f3ea906ed274767e9906dbaede7531d660ff/config.json",
"gitBlobId": "fade82e22ec4f4b61f6f2eb3986ce4a64a8e23df",
"bytes": 1802,
"sha256": "028d72a28b90a369eff3f99ceb585fbd2ababf070e8577d72c315757a49b8917",
"license": "Apache-2.0, pinned upstream model-card declaration"
},
{
"file": "vocab.json",
"url": "https://huggingface.co/sshleifer/distilbart-cnn-12-6/resolve/a4f8f3ea906ed274767e9906dbaede7531d660ff/vocab.json",
"gitBlobId": "0a39732b2d8be8e493cab3da68b68cc3e28221de",
"bytes": 898822,
"sha256": "06b4d46c8e752d410213d9548eb27a54db70fda0319b6271fb8d59dead5e1cab",
"license": "Apache-2.0, pinned upstream model-card declaration"
},
{
"file": "merges.txt",
"url": "https://huggingface.co/sshleifer/distilbart-cnn-12-6/resolve/a4f8f3ea906ed274767e9906dbaede7531d660ff/merges.txt",
"gitBlobId": "226b0752cac7789c48f0cb3ec53eda48b7be36cc",
"bytes": 456318,
"sha256": "1ce1664773c50f3e0cc8842619a93edc4624525b728b188a9e0be33b7726adc5",
"license": "Apache-2.0, pinned upstream model-card declaration"
},
{
"file": "tokenizer_config.json",
"url": "https://huggingface.co/sshleifer/distilbart-cnn-12-6/resolve/a4f8f3ea906ed274767e9906dbaede7531d660ff/tokenizer_config.json",
"gitBlobId": "be4d21d94f3b4687e5a54d84bf6ab46ed0f8defd",
"bytes": 26,
"sha256": "5e04eb606e3a1583530a42e36c2a6b6615c86f34fe77e44d9ddeb43ff940931f",
"license": "Apache-2.0, pinned upstream model-card declaration"
}
],
"scope": "Actual trained configured checkpoint. CPU loading/generation/API compatibility only; no human semantic acceptance, GPU, production filesystem/cache or deployment."
}
}
@@ -0,0 +1,9 @@
{
"status": "ASSESSED_NOT_A_FAILURE",
"warning": "Please make sure the generation config includes forced_bos_token_id=0",
"wheelSha256": "eae143e46d8e521da604bc4fdc45af7dd90e96eacbbc27f68d2754150aa5175a",
"member": "transformers/generation/configuration_utils.py",
"memberSha256": "fa9997a5334fa132f2911f7518163d963a706a82ade7ebca78afce69bfdc3c39",
"source": "if kwargs.get(\"force_bos_token_to_be_generated\", False):\n self.forced_bos_token_id = self.bos_token_id\n logger.warning_once(\n f\"Please make sure the generation config includes `forced_bos_token_id={self.bos_token_id}`. \"\n )\n\n # Validate the values of the attributes\n self.validate(user_set_attributes=user_set_attributes)\n\n def __hash__(se",
"assessment": "Current generation config explicitly preserves backward compatibility by assigning forced_bos_token_id=bos_token_id(0) for the pinned legacy flag. Pinned original model config already records bos/forced_bos0. Original config bytes are preserved; warning retained in actual log, not suppressed. Real CPU generation passed; no semantic-quality approval."
}
@@ -0,0 +1,11 @@
# Actual configured checkpoint follow-up
The small immutable BART fixtures passed library, native CPU, serialization and API compatibility. They do not establish that the actual older configured DistilBART checkpoint/configuration loads under the major Transformers transition. This is the remaining reason for one exact pretrained download; no unrelated or larger generative model is introduced.
The user authorises necessary trusted, licensed, size-checked downloads into an approved nonproduction environment. Local disk has over240GiB free and host memory is about32GiB; qualification is bounded to fourCPU/eightGiB/128PIDs/300seconds with network none, read-only checkpoint and no production/Ollama access. The source is the Apache-2.0 repository at immutable revisiona4f8f3ea906ed274767e9906dbaede7531d660ff. Only the1,222,317,369-byte PyTorch checkpoint with SHA2563bac65d18c99463302d12ca75c2220ea714f9c81ce235f205fa818efe71df6ea is fetched; existing verified tokenizer/config bytes are reused.
The entire size and digest must match before any model load. A partial or invalid download remains failed evidence and is never loaded. The loader is the patched actual sidecar path, with explicit weights_only and no trusted remote code. The test starts only after ordinary, provider/PDF and exclusive15minute qualification has finished. It does not compete with measured workloads.
This is a new follow-up, not a rewrite of the earlier no-full-download checkpoints. Results remain PENDING until actual execution. Full-model compatibility does not establish semantic/C11 acceptance, GPU behaviour, live cache ownership/integrity or deployment readiness.
Execution25October2026: **PASS**. The exact checkpoint size/hash matched; the actual source loader used the default pinned repository revision through a private offline Hub snapshot. CPU model/config/tokenizer loading,1024-token processing, finite logits, generation, authentication and repeat-cache contract passed in27.72seconds with peakRSS2858928KiB. The nonroot, read-only, network-none container exited0 and positive daemon evidence verified removal. The preceding PENDING statement is the preserved pre-execution plan. [validation.json](../validation.json) records the actual successor, manifest hash and remaining scope limits.
@@ -0,0 +1,45 @@
"""Prepare the reviewed trained checkpoint in a NEW nonproduction directory; never reset caches."""
from pathlib import Path
import hashlib
import json
import shutil
import sys
import time
import urllib.parse
import urllib.request
sys.path.insert(0, str(Path(__file__).resolve().parent.parent/'model'))
from verify import verify_fixture
def prepare(destination):
destination=Path(destination)
manifest=json.loads(Path(__file__).with_name('ARTIFACTS.json').read_text())['weights-only']
revision=manifest['sourceRevision']
assert revision=='a4f8f3ea906ed274767e9906dbaede7531d660ff'
assert manifest['license'].startswith('Apache-2.0')
assert not destination.exists(), 'Use a new isolated directory; existing data is never replaced.'
assert shutil.disk_usage(destination.parent).free>8*1024**3, 'Require8GiB available for bounded preparation.'
destination.mkdir(mode=0o700)
deadline=time.monotonic()+1200
for entry in manifest['files']:
name=entry['file']; assert Path(name).name==name and name not in ('.','..')
url=entry.get('url') or entry['source']
parsed=urllib.parse.urlsplit(url)
assert parsed.scheme=='https' and parsed.netloc=='huggingface.co'
assert parsed.path.startswith('/sshleifer/distilbart-cnn-12-6/resolve/'+revision+'/')
temporary=destination/(name+'.partial'); count=0; digest=hashlib.sha256()
with urllib.request.urlopen(url,timeout=60) as response, temporary.open('xb') as stream:
while block:=response.read(1024*1024):
count+=len(block)
assert count<=entry['bytes'] and time.monotonic()<deadline, 'Artifact size/deadline exceeded.'
digest.update(block); stream.write(block)
assert count==entry['bytes'] and digest.hexdigest()==entry['sha256'], 'Artifact identity mismatch; do not load partial files.'
temporary.rename(destination/name)
verify_fixture(destination,manifest)
print(json.dumps({'status':'PASS','directory':str(destination.resolve()),'revision':revision,'files':len(manifest['files'])}))
if __name__=='__main__':
assert len(sys.argv)==2, 'Usage: python prepare.py NEW_NONPRODUCTION_CACHE_DIRECTORY'
prepare(sys.argv[1])
@@ -0,0 +1,84 @@
"""Actual pinned trained-checkpoint CPU compatibility; human quality remains separate."""
from pathlib import Path
import importlib.metadata
import hashlib
import json
import os
import resource
import sys
import time
sys.path.insert(0, '/qualification')
from verify import verify_fixture
HERE = Path(__file__).resolve().parent
manifest_bytes = (HERE / 'ARTIFACTS.json').read_bytes()
manifests = json.loads(manifest_bytes)
manifest_sha256 = hashlib.sha256(manifest_bytes).hexdigest()
kind = sys.argv[1]
fixture = verify_fixture(Path(sys.argv[2]), manifests[kind])
assert os.environ['HF_HUB_OFFLINE'] == os.environ['TRANSFORMERS_OFFLINE'] == '1'
manifest = manifests[kind]
repository_name = 'sshleifer/distilbart-cnn-12-6'
assert manifest['fixture'] == 'actual-distilbart-cnn-12-6'
cache_home = Path('/tmp/qualified-hf-cache')
cache_home.mkdir(mode=0o700)
os.environ['HF_HOME'] = str(cache_home)
cache = cache_home / 'hub'
repository = cache / ('models--' + repository_name.replace('/', '--'))
snapshot = repository / 'snapshots' / manifest['sourceRevision']
snapshot.mkdir(parents=True)
(repository / 'blobs').mkdir()
for entry in manifest['files']:
identity = entry.get('gitBlobId') or entry['sha256']
blob = repository / 'blobs' / identity
blob.symlink_to(fixture / entry['file'])
(snapshot / entry['file']).symlink_to(Path('../../blobs') / identity)
os.environ.pop('AI_SERVICE_SKIP_MODEL_LOAD', None)
os.environ.pop('AI_SERVICE_EAGER_MODEL_LOAD', None)
os.environ['AI_SERVICE_TOKEN'] = 'p9-local-qualification-only'
sys.path.insert(0, '/app')
import torch
import app
from fastapi.testclient import TestClient
torch.set_num_threads(1)
started = time.monotonic()
from huggingface_hub import try_to_load_from_cache
assert app.MODEL_NAME == repository_name
assert app.MODEL_REVISION == manifest['sourceRevision']
for entry in manifest['files']:
cached = try_to_load_from_cache(app.MODEL_NAME, entry['file'], revision=app.MODEL_REVISION)
assert isinstance(cached, str) and Path(cached).resolve() == fixture / entry['file']
assert try_to_load_from_cache(app.MODEL_NAME, 'absent-qualification-file', revision=app.MODEL_REVISION) is None
assert app._ensure_runtime_loaded(), app.MODEL_LOAD_ERROR
assert app.model.__class__.__name__ == 'BartForConditionalGeneration'
assert (app.model.config.d_model, app.model.config.encoder_layers, app.model.config.decoder_layers, app.model.config.vocab_size) == (1024, 12, 6, 50264)
assert len(app.tokenizer) == 50265
assert app.model.training is False
assert str(app.device) == 'cpu' and not app.GPU_AVAILABLE
text = 'Åse Østby builds accessible Python and C# applications for reliable Norwegian career workflows.'
encoded = app.tokenizer(text, return_tensors='pt')
assert app.tokenizer.decode(encoded.input_ids[0], skip_special_tokens=True) == text
summary = app._model_summarize(text, 24, 8)
assert isinstance(summary, str) and summary
long_input = app.tokenizer(text * 400, return_tensors='pt', truncation=True, max_length=1024)
assert long_input.input_ids.shape == (1, 1024)
assert long_input.input_ids.dtype == torch.int64
with torch.no_grad():
logits = app.model(**long_input, decoder_input_ids=torch.tensor([[2, 0, 10]])).logits
assert torch.isfinite(logits).all()
assert app._model_summarize(text * 400, 24, 8)
client = TestClient(app.app)
assert client.get('/health').json()['model_loaded'] is True
assert client.post('/summarize', json={'text': text}).status_code == 401
headers = {'X-Ai-Service-Token': 'p9-local-qualification-only'}
body = {'text': text, 'max_length': 24, 'min_length': 8}
first = client.post('/summarize', json=body, headers=headers)
second = client.post('/summarize', json=body, headers=headers)
assert first.status_code == second.status_code == 200, first.text
assert first.json()['cached'] is False and second.json()['cached'] is True
assert first.json()['summary'] == second.json()['summary']
verify_fixture(fixture, manifests[kind])
elapsed = time.monotonic() - started
assert elapsed < 240
print(json.dumps({'status': 'PASS', 'kind': kind, 'scope': 'Actual pinned trained DistilBART CPU loading/tokenizer/generation and summary/auth/cache compatibility; no human semantic-quality/GPU/production claim.', 'manifestSha256': manifest_sha256, 'repositoryRevision': app.MODEL_REVISION, 'modelClass': app.model.__class__.__name__, 'device': str(app.device), 'cudaAvailable': torch.cuda.is_available(), 'seconds': elapsed, 'maxRssKiB': resource.getrusage(resource.RUSAGE_SELF).ru_maxrss, 'versions': {name: importlib.metadata.version(name) for name in ['torch','transformers','filelock','huggingface-hub','tokenizers','safetensors']}, 'summary': summary, 'bounded1024Tokens': True, 'finiteLogits': True, 'cacheRepeatedRead': True, 'fixtureUnchanged': True}), flush=True)
@@ -0,0 +1,35 @@
import hashlib
import io
import json
from pathlib import Path
import tempfile
import unittest
from unittest.mock import patch
from prepare import prepare
class PreparationBoundaryTests(unittest.TestCase):
def run_fixture(self, payload, expected=b'approved'):
revision='a4f8f3ea906ed274767e9906dbaede7531d660ff'
manifest={'weights-only':{'sourceRevision':revision,'license':'Apache-2.0 pinned card',
'files':[{'file':'config.json','url':'https://huggingface.co/sshleifer/distilbart-cnn-12-6/resolve/'+revision+'/config.json',
'bytes':len(expected),'sha256':hashlib.sha256(expected).hexdigest()}]}}
with tempfile.TemporaryDirectory() as directory:
target=Path(directory)/'new-cache'
with patch.object(Path,'read_text',return_value=json.dumps(manifest)), patch('prepare.shutil.disk_usage',return_value=type('Usage',(),{'free':10*1024**3})()), patch('prepare.urllib.request.urlopen',return_value=io.BytesIO(payload)):
if payload==expected:
prepare(target)
self.assertEqual((target/'config.json').read_bytes(),expected)
with self.assertRaises(AssertionError):prepare(target)
self.assertEqual((target/'config.json').read_bytes(),expected)
else:
with self.assertRaises(AssertionError):prepare(target)
self.assertFalse((target/'config.json').exists())
self.assertTrue((target/'config.json.partial').exists())
def test_validated_bytes_and_existing_cache_preserved(self):self.run_fixture(b'approved')
def test_corrupt_bytes_never_promoted(self):self.run_fixture(b'rejected')
def test_oversized_bytes_never_promoted(self):self.run_fixture(b'oversized payload')
if __name__=='__main__':unittest.main()
@@ -0,0 +1,26 @@
"""Reuse the qualified isolated renderer lifecycle; retain each remediation attempt separately."""
import importlib.util
import re
import subprocess
import sys
from pathlib import Path
HERE = Path(__file__).resolve().parent
spec = importlib.util.spec_from_file_location('qualified_linux_runner', HERE.parent/'p9-requal-01/linux-run.py')
runner = importlib.util.module_from_spec(spec)
spec.loader.exec_module(runner)
if len(sys.argv) != 2 or not re.fullmatch(r'[a-z0-9-]+', sys.argv[1]):
raise SystemExit('Supply a unique lowercase attempt name; prior evidence is never overwritten.')
runner.OUT = runner.ROOT/'.artifacts/p9-sec-02'/sys.argv[1]/'linux'
if sys.argv[1] != 'baseline':
expected='sha256:0d1cb44ba8f71d54de77459915a7052b894191cfeb75aa32f0c1e7ffdc21fda6'
actual=subprocess.check_output(['rtk','proxy','docker','image','inspect','--format','{{.Id}}','jobtracker-p9-remed-api:fonts'],text=True,timeout=10).strip()
if actual!=expected:raise SystemExit('Qualified local PDF image identity changed; requalification required.')
runner.IMAGE = expected # Local image ID, not a claimed pullable registry manifest.
runner.VERSION = 'p9-remed-02-fonts' # Unchanged fixture readiness token; actual image/source are verified separately.
runner.CONFIG = '../docs/redesign/phase-9/p9-remed-02/linux/playwright.config.ts'
if sys.argv[1] == 'representative-linux':
runner.CONFIG = '../docs/redesign/phase-9/p9-remed-02/representative/playwright.config.ts'
runner.COMMIT = 'e80815f8df94d26f7d35b8249b4e6e1a65922df3'
runner.main()
@@ -0,0 +1,14 @@
"""Reuse the guarded provider/browser workload lifecycle with a new evidence destination."""
import importlib.util
from pathlib import Path
HERE = Path(__file__).resolve().parent
spec = importlib.util.spec_from_file_location('qualified_mariadb_lane', HERE.parent/'p9-requal-01/mariadb-lane.py')
runner = importlib.util.module_from_spec(spec)
spec.loader.exec_module(runner)
runner.OUT = runner.ROOT/'.artifacts/p9-sec-02/final'
if __name__ == '__main__':
try:
raise SystemExit(runner.main())
except ValueError as error:
raise SystemExit(runner.scrub(str(error)))
@@ -0,0 +1,17 @@
{
"observedUtc": "2026-10-25T11:37:24.319354+00:00",
"status": "PASS",
"sourceImageId": "sha256:4a04ca68fa40b3ec61cb61187b339a4d2895b375b962999e974d75556b5b1331",
"package": "tesseract-ocr-eng",
"version": "1:4.1.0-2",
"artifact": "/usr/share/tesseract-ocr/5/tessdata/eng.traineddata",
"bytes": 4113088,
"sha256": "7d4322bd2a7749724879683fc3912cb542f19906c83bcc1a52132556427170b2",
"licenseEvidence": {
"path": "docs/redesign/phase-9/p9-sec-02/model/OCR_COPYRIGHT.txt",
"sha256": "33fb8161898e34fcf5c6b8585d6be97642d7e8f34a922e783c6c5c970d0b09ad"
},
"exitCode": 0,
"containerAbsent": true,
"scope": "Installed Debian English OCR training data in the exact qualified local runtime image; source package copyright retained. No new OCR model download."
}
@@ -0,0 +1,32 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: tessdata_fast
Upstream-Contact: Ray Smith <theraysmith@users.sourceforge.net>
Source: https://github.com/tesseract-ocr/tessdata_fast/
Files: *
Copyright: 1988-1995 Hewlett Packard Company.
2006-2022 Google Inc.
License: Apache-2.0
Files: debian/*
Copyright: 2007-2009 Jeffrey Ratcliffe <Jeffrey.Ratcliffe@gmail.com>
2017-2019 Jeff Breidenbach <jab@debian.org>
2017-2022 Alexander Pozdnyakov <almipo@mail.ru>
License: Apache-2.0
License: Apache-2.0
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the license at
.
http://www.apache.org/licenses/LICENSE-2.0
.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
.
On Debian systems, the complete text of the Apache 2.0 license can be
found in the file
`/usr/share/common-licenses/Apache-2.0`.
@@ -0,0 +1,12 @@
"""Owned local qualification cleanup evidence."""
import subprocess
def container_absent(name):
try:
query=subprocess.run(['rtk','proxy','docker','ps','--all','--no-trunc','--filter',f'name=^/{name}$','--format','{{.ID}}'],capture_output=True,text=True,timeout=5)
except (OSError,subprocess.TimeoutExpired) as error:
raise RuntimeError('Cleanup daemon query unavailable or timed out.') from error
if query.returncode != 0:
raise RuntimeError('Cleanup daemon query failed; absence is unverified.')
return not query.stdout.strip()
@@ -0,0 +1,25 @@
{
"path": ".artifacts/p9-sec-02/small-fixtures.zip",
"bytes": 9895179,
"sha256": "a1aff347e5f08f82e8ea7176d71d00e7f83ea5735acbdc4e3bf02c73deacb643",
"files": {
"safetensors/README.md": "e6114f9ddddd7aec5e9858b9849d1b53dc42b596420888b82fbf3f8defb64bf7",
"safetensors/reference-distilbart-config.json": "028d72a28b90a369eff3f99ceb585fbd2ababf070e8577d72c315757a49b8917",
"safetensors/vocab.json": "06b4d46c8e752d410213d9548eb27a54db70fda0319b6271fb8d59dead5e1cab",
"safetensors/merges.txt": "1ce1664773c50f3e0cc8842619a93edc4624525b728b188a9e0be33b7726adc5",
"safetensors/tokenizer_config.json": "5e04eb606e3a1583530a42e36c2a6b6615c86f34fe77e44d9ddeb43ff940931f",
"safetensors/config.json": "563b819e93f153a49d6364d5c90878eec01ef78f99aae0d0c8c7ccce49e517a8",
"safetensors/generation_config.json": "fdf2a5aa742aa3bd7fcf78a14d9aae0c599e55610e7856a35a4e89a38fed50f7",
"safetensors/model.safetensors": "35ca2b5d2c6a28696cadd0fd7dfe483d499497e315db28dfa5a509bf13da7a68",
"safetensors/generate.py": "006cd1354c98e72ce9a7f1f57c5b3e3fd1cf16836dcb4508ca9f9930b4777fa5",
"weights-only/config.json": "b4f823ea324a93c355ae2ae2447bed10fcdb769070eff435f175a6738f7d3c34",
"weights-only/generate-bin.py": "5d1f53ea37cc199d876b27731a29dea74b4df7fed7151f67a49b848993517052",
"weights-only/generation_config.json": "fdf2a5aa742aa3bd7fcf78a14d9aae0c599e55610e7856a35a4e89a38fed50f7",
"weights-only/merges.txt": "1ce1664773c50f3e0cc8842619a93edc4624525b728b188a9e0be33b7726adc5",
"weights-only/pytorch_model.bin": "95d578c5706c9256a2f299a4288c0cdcae0fd303fa27e4474c34300f51f195cd",
"weights-only/README.md": "e6114f9ddddd7aec5e9858b9849d1b53dc42b596420888b82fbf3f8defb64bf7",
"weights-only/tokenizer_config.json": "5e04eb606e3a1583530a42e36c2a6b6615c86f34fe77e44d9ddeb43ff940931f",
"weights-only/vocab.json": "06b4d46c8e752d410213d9548eb27a54db70fda0319b6271fb8d59dead5e1cab"
},
"scope": "Local retained replay capsule only. No model weights committed, uploaded or published. Verify archive SHA and per-file committed manifest before restoring to NEW isolated test directories. Different generator/runtime bytes require a new manifest and qualification."
}
+11 -3
View File
@@ -6,6 +6,7 @@ import subprocess
import sys
import time
import uuid
from cleanup import container_absent
ROOT=Path(__file__).resolve().parents[5]
HERE=Path(__file__).resolve().parent
@@ -37,14 +38,21 @@ with (out/'process.log').open('w',encoding='utf-8') as log:
try:code=subprocess.run(['rtk','proxy',*args],cwd=ROOT,stdout=log,stderr=subprocess.STDOUT,timeout=180).returncode
except subprocess.TimeoutExpired:
code=124
check=subprocess.run(['rtk','proxy','docker','inspect','--format','{{index .Config.Labels "jobtracker.qualification"}}',name],capture_output=True,text=True)
if check.returncode==0 and check.stdout.strip()=='p9-sec02':subprocess.run(['rtk','proxy','docker','kill',name],capture_output=True)
try:
check=subprocess.run(['rtk','proxy','docker','inspect','--format','{{index .Config.Labels "jobtracker.qualification"}}',name],capture_output=True,text=True,timeout=5)
if check.returncode==0 and check.stdout.strip()=='p9-sec02':subprocess.run(['rtk','proxy','docker','kill',name],capture_output=True,timeout=10)
except (OSError,subprocess.TimeoutExpired):pass
deadline=time.monotonic()+5
cleanup_error=None
while True:
absent=subprocess.run(['rtk','proxy','docker','inspect',name],capture_output=True).returncode!=0
try:absent=container_absent(name)
except RuntimeError as error:
absent=None;cleanup_error=str(error);break
if absent or time.monotonic()>=deadline:break
time.sleep(.1)
record={'lane':lane,'attempt':attempt,'startedUtc':started,'finishedUtc':datetime.datetime.now(datetime.timezone.utc).isoformat(),'exitCode':code,'command':args,'localImageId':image,'runtimeImageId':runtime['runtimeImageId'],'containerAbsent':absent,'network':'none','readOnly':True,'user':'65534:65534','memoryLimitBytes':2147483648,'cpuLimit':2,'pidsLimit':128,'wallClockDeadlineSeconds':180,'scope':'Actual locally built source image plus exact test-only extras; no app source mount, production cache, external network, registry push or deployment.'}
record['cleanupStatus']='ABSENT' if absent else 'UNKNOWN' if absent is None else 'PRESENT'
record['cleanupError']=cleanup_error
(out/'process.json').write_text(json.dumps(record,indent=2)+'\n')
print(json.dumps(record))
print((out/'process.log').read_text(encoding='utf-8',errors='replace')[-2500:].encode('ascii','replace').decode())
@@ -0,0 +1,39 @@
import subprocess
import unittest
from unittest.mock import patch
from cleanup import container_absent
class PositiveCleanupEvidence(unittest.TestCase):
def query(self, absent, available):
def run(args, **options):
if not available: return subprocess.CompletedProcess(args,1,'','daemon unavailable')
if 'inspect' in args: return subprocess.CompletedProcess(args,1 if absent else 0,'','no such object' if absent else '')
return subprocess.CompletedProcess(args,0,'' if absent else '0123456789abcdef\n','')
return run
def test_successful_daemon_query_proves_absence(self):
with patch('cleanup.subprocess.run',side_effect=self.query(True,True)):
self.assertTrue(container_absent('jt-sec02-owned'))
def test_present_container_is_not_removed(self):
with patch('cleanup.subprocess.run',side_effect=self.query(False,True)):
self.assertFalse(container_absent('jt-sec02-owned'))
def test_daemon_failure_cannot_certify_cleanup(self):
with patch('cleanup.subprocess.run',side_effect=self.query(True,False)):
with self.assertRaises(RuntimeError): container_absent('jt-sec02-owned')
def test_timeout_is_unknown_and_calls_are_bounded(self):
with patch('cleanup.subprocess.run',side_effect=subprocess.TimeoutExpired('docker',5)) as query:
with self.assertRaises(RuntimeError): container_absent('jt-sec02-owned')
self.assertEqual(query.call_args.kwargs['timeout'],5)
def test_exact_owned_name_filter_is_used(self):
with patch('cleanup.subprocess.run',side_effect=self.query(True,True)) as query:
self.assertTrue(container_absent('jt-sec02-owned'))
self.assertIn('name=^/jt-sec02-owned$',query.call_args.args[0])
self.assertNotIn('inspect',query.call_args.args[0])
if __name__=='__main__':unittest.main()
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,258 @@
"""Source-bound successor accounting; the one declared frontend addition never masks missing cases."""
import copy
import datetime
import importlib.util
import hashlib
import json
import sys
import xml.etree.ElementTree as ET
from pathlib import Path
HERE=Path(__file__).resolve().parent
spec=importlib.util.spec_from_file_location('qualified_reconciliation',HERE.parent/'p9-requal-01/reconcile.py')
prior=importlib.util.module_from_spec(spec)
spec.loader.exec_module(prior)
ROOT=prior.ROOT
RAW=ROOT/'.artifacts/p9-sec-02/final'
prior.RAW=RAW
ADDED_CASE='focusing a preview retry control keeps its pointer target stationary'
def require_fresh(path):
if not Path(path).resolve().is_relative_to((ROOT/'.artifacts/p9-sec-02').resolve()):
raise ValueError('Fresh execution cannot use a historical evidence directory.')
def validate_representative(proof,report):
expected={'long-skills-minimal-en','long-skills-technical-nb'}
cases=report.get('fixtures',[])
if (proof.get('status')!='PASS' or proof.get('oracleExitCode')!=0
or report.get('total')!=2 or report.get('passed')!=2 or len(cases)!=2
or {case.get('fixture') for case in cases}!=expected
or any(case.get('pass') is not True or case.get('failures')!=[] for case in cases)
or proof.get('cases')!=cases):
raise ValueError('Supplemental PDF membership, oracle outcome or retained cases differ.')
def require_unchanged(inputs):
if any(not Path(name).is_file() or hashlib.sha256(Path(name).read_bytes()).hexdigest()!=digest for name,digest in inputs.items()):
raise ValueError('Supplemental PDF input/report drift.')
def frontend_cases(report,baseline,exit_code):
reference=copy.deepcopy(baseline)
suites=[suite for suite in reference['testResults'] if suite['name'].replace('\\','/').endswith('/job-tracker-ui/src/cv-builder-deep-link.test.tsx')]
if len(suites)!=1: raise ValueError('Missing or ambiguous frontend membership reference.')
# This adds an expectation, never an execution outcome, to the old934-case multiset.
suites[0]['assertionResults'].append({'fullName':ADDED_CASE})
return prior.jest_results(report,reference,exit_code,935)
def main():
results={'backend':prior.collect_trx('backend','backend/backend.trx',1130),
'mariadb':prior.collect_trx('mariadb','mariadb/mariadb.trx',35)}
for i in range(1,5): results[f'ordinary-{i}']=prior.collect_browser(f'ordinary-{i}')
amendment=None
successor=ROOT/'.artifacts/p9-sec-02/oauth-fixture-successor'
if (successor/'result.json').exists():
predecessor=results['ordinary-3']
try:
predecessor['nativeStats']=prior.load(RAW/'ordinary-3.json').get('stats')
predecessor['report']=prior.identity(RAW/'ordinary-3.json')
amendment=prior.load(successor/'result.json')
if amendment.get('status')!='PASS' or amendment.get('exitCode')!=0: raise ValueError('Fixture successor did not pass.')
if amendment['file']!='job-tracker-ui/e2e/phase7-oauth-sender.spec.ts': raise ValueError('Unexpected amended fixture owner.')
if prior.identity(ROOT/amendment['file'])['sha256']!=amendment['after']: raise ValueError('Amended fixture source drift.')
old_discovery=prior.load(RAW/'discovery.json'); new_discovery=prior.load(successor/'discovery.json')
ids=lambda d: {s['id']+':'+t['projectName'] for s in prior.specs(d) for t in s['tests']}
if ids(old_discovery)!=ids(new_discovery) or new_discovery.get('errors'): raise ValueError('Amended fixture changed ordinary discovery.')
prior.RAW=successor
current=prior.collect_browser('ordinary-3',88)
prior.RAW=RAW
if current['status']!='PASS': raise ValueError('Complete88-case successor missing.')
current['supersededAttempt']=predecessor
current['amendment']=amendment
results['ordinary-3']=current
except (ValueError,KeyError) as error:
results['ordinary-3']={'status':'FAIL','reason':str(error),'supersededAttempt':predecessor}
finally:prior.RAW=RAW
try:
if any(results[f'ordinary-{i}']['status']!='PASS' for i in range(1,5)): raise ValueError('Incomplete ordinary shards.')
cases=prior.reconcile_ordinary(prior.load(RAW/'discovery.json'),[results[f'ordinary-{i}']['cases'] for i in range(1,5)])
if len(cases)!=362: raise ValueError('Unexpected ordinary discovery membership.')
results['ordinary']={'status':'PASS','passed':362,'discovery':prior.identity(RAW/'discovery.json')}
except (FileNotFoundError,ValueError) as error: results['ordinary']={'status':'NOT_COMPLETE','reason':str(error)}
for name,count in {'ai':2,'auth':2,'rate':9,'ingress':6,'pdf-admission':1,'preferences':3,'rd21':6,'diagnostics':18,'volume':3,'rd21-volume':3,'mariadb-browser':1,'mariadb-observations':2}.items():
results[name]=prior.collect_browser(name,count)
old_raw=prior.RAW
prior.RAW=ROOT/'.artifacts/p9-sec-02/final-linux-02'
results['linux-renderer']=prior.collect_browser('linux-renderer',5)
results['linux-renderer']['supersededAttempt']={'status':'FAIL','executedBrowserCases':0,
'reason':'New readiness label rejected by unchanged historical fixture guard before case execution; original guard token retained in source/image-verified successor.',
'process':prior.identity(ROOT/'.artifacts/p9-sec-02/final-linux/linux/process.json')}
prior.RAW=ROOT/'.artifacts/p9-sec-02/representative-linux'
representative=prior.collect_browser('linux-renderer',2)
try:
proof=prior.load(prior.RAW/'result.json')
root=prior.RAW/'linux/fidelity'
report=prior.load(root/'fidelity-results.json')
validate_representative(proof,report)
measurements=prior.load(root/'measurements.json')
if len(measurements['fixtures'])!=2 or {case['fixture'] for case in measurements['fixtures']}!={case['fixture'] for case in report['fixtures']}:
raise ValueError('Supplemental measurements membership differs.')
binding=prior.RAW/'oracle-inputs.json'
inputs=prior.load(binding)['inputs']
if proof.get('inputs')!=inputs or proof.get('reportSha256')!=hashlib.sha256((root/'fidelity-results.json').read_bytes()).hexdigest():
raise ValueError('Supplemental producer input/report binding differs.')
oracle=str((ROOT/'scripts/verify-cv-fidelity.py').resolve())
if inputs.get(oracle)!='64f82e622cc11483c33307d987e969f6cf27f82ab6bdbd72c2aeb1bfbceade87':
raise ValueError('Supplemental original oracle identity differs.')
for case in report['fixtures']:
for name in ['render.html','export.pdf','measurements.json']:
if str((root/case['fixture']/name).resolve()) not in inputs: raise ValueError('Supplemental required artifact missing.')
require_unchanged(inputs)
representative['oracle']=proof
representative['oracleEvidence']=prior.identity(prior.RAW/'result.json')
representative['inputBinding']=prior.identity(binding)
representative['report']=prior.identity(root/'fidelity-results.json')
except FileNotFoundError as error: representative.update(status='NOT_COMPLETE',reason=str(error))
except ValueError as error: representative.update(status='FAIL',reason=str(error))
results['pdf-representative']=representative
prior.RAW=old_raw
try:
path=RAW/'frontend.json';data=prior.load(path);process=prior.load(RAW/'frontend-exit.json')
reference=ROOT/'.artifacts/p9-requal-01/frontend.json'
accepted=prior.load(HERE.parent/'p9-requal-01/validation.json')['results']['frontend']['report']['sha256']
if prior.identity(reference)['sha256']!=accepted: raise ValueError('Historical frontend reference changed.')
if f"test('{ADDED_CASE}'" not in (ROOT/'job-tracker-ui/src/cv-builder-deep-link.test.tsx').read_text(encoding='utf-8'): raise ValueError('Declared added regression is absent from source.')
cases=frontend_cases(data,prior.load(reference),process['exitCode'])
expected={'numPassedTests':935,'numTotalTests':935,'numFailedTests':0,'numPendingTests':0,'numTodoTests':0,'numPassedTestSuites':105,'numTotalTestSuites':105,'numFailedTestSuites':0}
if any(data.get(k)!=v for k,v in expected.items()): raise ValueError('Frontend aggregate counts differ.')
results['frontend']={'status':'PASS','passed':935,'suites':105,'cases':cases,'report':prior.identity(path),'process':process,'membershipReference':prior.identity(reference),'declaredAddedCase':ADDED_CASE}
except FileNotFoundError as error: results['frontend']={'status':'NOT_RUN','reason':str(error)}
except ValueError as error: results['frontend']={'status':'FAIL','reason':str(error)}
for name in ['types','lint','build']:
try:
process=prior.load(RAW/(name+'-exit.json'))
result={'status':'PASS' if process['exitCode']==0 else 'FAIL','process':process,'log':prior.identity(RAW/(name+'.log'))}
results[name]=result
except FileNotFoundError as error: results[name]={'status':'NOT_RUN','reason':str(error)}
except ValueError as error: results[name]={'status':'FAIL','reason':str(error)}
for name,path in [('performance',RAW/'performance/result.json'),('windows-pdf',RAW/'native-pdf.json'),('linux-pdf',ROOT/'.artifacts/p9-sec-02/final-linux-02/linux-pdf.json')]:
try:
require_fresh(path)
data=prior.load(path)
if name.endswith('pdf'):
if hashlib.sha256((ROOT/'scripts/verify-cv-fidelity.py').read_bytes()).hexdigest()!='64f82e622cc11483c33307d987e969f6cf27f82ab6bdbd72c2aeb1bfbceade87': raise ValueError('Original PDF oracle changed.')
if data.get('inputDrift') or any(hashlib.sha256(Path(file).read_bytes()).hexdigest()!=digest for file,digest in data['inputs'].items()): raise ValueError('PDF inputs changed after qualification.')
if len(data['lanes'])!=2 or any(lane['status']!='PASS' or lane['exitCode']!=0 or hashlib.sha256(Path(lane['report']).read_bytes()).hexdigest()!=lane['reportSha256'] for lane in data['lanes']): raise ValueError('PDF lane/report failure or drift.')
results[name]={'status':data['status'],'record':data,'evidence':prior.identity(path)}
except FileNotFoundError as error: results[name]={'status':'NOT_RUN','reason':str(error)}
except ValueError as error: results[name]={'status':'FAIL','reason':str(error)}
try:
path=RAW/'security/commands.json';commands=prior.load(path)
passed,vulnerabilities=prior.security_results(commands,prior.load(RAW/'security/frontend-audit.json'),prior.load(RAW/'security/nuget-advisories.log'))
results['security-helpers']={'status':'PASS' if passed else 'FAIL','commands':commands,'evidence':prior.identity(path),'nugetVulnerabilities':vulnerabilities,'scope':'Twelve bounded helpers/audits; not Python advisory closure.'}
except FileNotFoundError as error: results['security-helpers']={'status':'NOT_RUN','reason':str(error)}
except ValueError as error: results['security-helpers']={'status':'FAIL','reason':str(error)}
for name, path in [('model-runtime', ROOT/'.artifacts/p9-sec-02/model-regression/result.json'),
('trained-model', ROOT/'.artifacts/p9-sec-02/full-model/result.json')]:
try:
data=prior.load(path)
if data['status']!='PASS': raise ValueError('Actual model qualification did not pass.')
if name=='model-runtime':
require_unchanged({str(ROOT/n):h for n,h in data['inputs'].items()})
if set(data['results'])!={'sidecar','inventory','safetensors','weights-only','cache','parsers'}: raise ValueError('Model lane membership differs.')
for lane in data['results'].values():
process=lane['process']
if lane['status']!='PASS' or process['exitCode']!=0 or process.get('containerAbsent') is not True or process.get('cleanupStatus')!='ABSENT': raise ValueError('Model lane process/positive cleanup evidence missing.')
ocr=prior.load(HERE/'model/OCR_ARTIFACT.json')
native=data['results']['inventory']['record']['englishOcrData']
if native['sha256']!=ocr['sha256'] or native['bytes']!=ocr['bytes'] or prior.identity(ROOT/ocr['licenseEvidence']['path'])['sha256']!=ocr['licenseEvidence']['sha256']:
raise ValueError('Native OCR identity/licence evidence differs.')
capsule=prior.load(HERE/'model/fixture-capsule.json')
if prior.identity(ROOT/capsule['path'])['sha256']!=capsule['sha256']: raise ValueError('Local small-fixture replay capsule changed.')
sidecar=ROOT/'.artifacts/p9-sec-02/qualified/model-regression-sidecar/sidecar.xml'
cases=prior.sidecar_results(ET.parse(sidecar).getroot(),59)
reference=ROOT/'.artifacts/p9-remed-02/final/sidecar.xml'
accepted=prior.load(HERE.parent/'p9-remed-02/validation.json')['results']['sidecar']['report']['sha256']
if prior.identity(reference)['sha256']!=accepted: raise ValueError('Historical sidecar membership reference drift.')
previous=prior.sidecar_results(ET.parse(reference).getroot(),58)
actual={(c['classname'],c['name']) for c in cases}; old={(c['classname'],c['name']) for c in previous}
added=actual-old
if not old.issubset(actual) or len(added)!=1 or next(iter(added))[1]!='test_model_load_pins_both_artifacts_and_denies_remote_code_and_unsafe_weights': raise ValueError('Sidecar membership differs from58 plus declared pin test.')
results['sidecar']={'status':'PASS','passed':59,'cases':cases,'report':prior.identity(sidecar),'membershipReference':prior.identity(reference)}
else:
if (data['exitCode']!=0 or data.get('containerAbsent') is not True
or data.get('downloadBytes')!=1222317369
or data.get('downloadSha256')!='3bac65d18c99463302d12ca75c2220ea714f9c81ce235f205fa818efe71df6ea'
or data['result'].get('status')!='PASS' or data['result'].get('modelClass')!='BartForConditionalGeneration'
or data['result'].get('device')!='cpu'
or data['result'].get('repositoryRevision')!='a4f8f3ea906ed274767e9906dbaede7531d660ff'
or data['result'].get('manifestSha256')!=prior.identity(HERE/'full-model/ARTIFACTS.json')['sha256']): raise ValueError('Full trained-checkpoint identity/process outcome differs.')
results[name]={'status':'PASS','record':data,'evidence':prior.identity(path)}
except FileNotFoundError as error: results[name]={'status':'NOT_RUN','reason':str(error)}
except (ValueError,KeyError) as error: results[name]={'status':'FAIL','reason':str(error)}
try:
scan=ROOT/'.artifacts/p9-sec-02/final-advisories/summary.json'
current=prior.load(scan)
expected_gap=[{'package':'torch','version':'2.13.0+cpu','provider':'pypi','httpStatus':404,'error':'HTTPError'}]
if current.get('packageCount')!=63 or current.get('sourceQueryCount')!=126 or current.get('errors')!=expected_gap:
raise ValueError('Installed scan membership/query coverage differs; do not convert provider errors into clean results.')
installed=results['model-runtime']['record']['results']['inventory']['record']['installedDistributions']
audited={row['name']:row['version'] for row in current['packages']}
if audited!=installed: raise ValueError('Scanned package graph differs from actual qualified installed graph.')
matrix=prior.load(HERE/'DISPOSITIONS.json')
from collections import Counter
dispositions=Counter(row['disposition'] for row in matrix['originalGroups'])
if len(matrix['originalGroups'])!=109 or len(matrix['additionalGroups'])!=1 or dispositions!={'Fixed and verified':99,'Not affected, with evidence':10}:
raise ValueError('Original109/new1 advisory accounting differs.')
results['python-advisories']={'status':'INCOMPLETE' if current['advisoryRecords']==0 else 'FINDINGS','record':current,
'scopedAssessmentEvidenceComplete':current['advisoryRecords']==0,
'scan':prior.identity(scan),'dispositions':prior.identity(HERE/'DISPOSITIONS.json'),
'coverage':'Exact installed OSV/PyPI queries; known vendor PyPI404 for CPU-local Torch retained. Official CPU wheel/vendor/source evidence supplements that unavailable query; no complete two-provider or deployed/image-wide security claim.'}
except FileNotFoundError as error: results['python-advisories']={'status':'NOT_RUN','reason':str(error)}
except (ValueError,KeyError) as error: results['python-advisories']={'status':'FAIL','reason':str(error)}
try:
path=ROOT/'.artifacts/p9-sec-02/final-guards/result.json'; guards=prior.load(path)
expected={'model-integrity-cleanup':10,'artifact-preparation':3,'fresh-evidence':3,'workflow-boundary':4}
if (guards['status']!='PASS' or guards['passed']!=20 or len(guards['results'])!=4
or {row['name']:row['expected'] for row in guards['results']}!=expected
or any(row['status']!='PASS' or row['exitCode']!=0 or prior.identity(path.parent/(row['name']+'.log'))['sha256']!=row['logSha256'] for row in guards['results'])):
raise ValueError('Supplementary harness guard membership/outcome/log identity differs.')
results['harness-guards']={'status':'PASS','passed':20,'record':guards,'evidence':prior.identity(path)}
except FileNotFoundError as error: results['harness-guards']={'status':'NOT_RUN','reason':str(error)}
except (ValueError,KeyError) as error: results['harness-guards']={'status':'FAIL','reason':str(error)}
try:
cleanup=prior.load(HERE/'cleanup.json')
if (cleanup['status']!='PASS' or any(cleanup.get(n) is not True for n in ['generatedSchemasAbsentBeforeRemoval','containerAbsent','labelledModelContainersAbsent','qualificationApiContainersAbsent'])
or cleanup['developmentContainer']['stateAndMountsUnchanged'] is not True or cleanup['developmentVolume']['metadataUnchanged'] is not True):
raise ValueError('Disposable cleanup/development preservation evidence incomplete.')
for name,record in cleanup['serverLogs'].items():
if prior.identity(ROOT/'.artifacts/p9-sec-02/database-cleanup'/name)['sha256']!=record['sha256']: raise ValueError('Retained database log stream changed.')
results['disposable-cleanup']={'status':'PASS','record':cleanup,'evidence':prior.identity(HERE/'cleanup.json')}
except FileNotFoundError as error: results['disposable-cleanup']={'status':'NOT_RUN','reason':str(error)}
except (ValueError,KeyError) as error: results['disposable-cleanup']={'status':'FAIL','reason':str(error)}
results['hosted-mariadb']={'status':'BLOCKED','executedMariaDbCases':0,'runnerIsolation':'UNVERIFIED','evidence':prior.identity(HERE/'ci-assessment.json'),'queuedEvidence':prior.identity(HERE/'ci-postpush.json'),'finalMetadata':prior.identity(HERE/'ci-final-refresh.json')}
manifest=prior.load(RAW/'source-freeze.json')
helpers=prior.load(ROOT/'.artifacts/p9-sec-02/final-helper-inputs.json')
drift=[n for n,h in manifest['inputs'].items() if not (ROOT/n).is_file() or hashlib.sha256((ROOT/n).read_bytes()).hexdigest()!=h]
if amendment and results['ordinary-3']['status']=='PASS':
name=amendment['file']
if manifest['inputs'].get(name)!=amendment['before']: raise ValueError('Fixture successor does not derive from frozen predecessor.')
drift=[n for n in drift if n!=name]
helper_drift=[n for n,h in helpers['inputs'].items() if not (ROOT/n).is_file() or hashlib.sha256((ROOT/n).read_bytes()).hexdigest()!=h]
local={k:v for k,v in results.items() if k not in ['hosted-mariadb','python-advisories']}
record={'schemaVersion':1,'observedUtc':datetime.datetime.now(datetime.timezone.utc).isoformat(),
'baseline':'f17dba2ec06ea8f53c2785eaaebd25abc515ebf8','branch':'fix/p9-model-cache-and-ci-qualification',
'applicationCheckpoint':manifest['applicationCheckpoint'],'sourceIdentity':prior.identity(RAW/'source-freeze.json'),
'frozenInputCount':len(manifest['inputs']),'runtimeDrift':drift,'helperIdentity':prior.identity(ROOT/'.artifacts/p9-sec-02/final-helper-inputs.json'),
'frozenHelperCount':len(helpers['inputs']),'helperDrift':helper_drift,
'declaredFixtureSuccessor':amendment,
'retainedReportingDryRun':{'evidence':prior.identity(ROOT/'.artifacts/p9-sec-02/collector-initial-dry-run.json'),
'scope':'Unpublished initial collector dry run exposed an inherited historical Linux PDF path. Corrected before acceptance; fresh-root negative guards prevent historical results becoming fresh passes.'},
'countPolicy':'Separate lanes. Superseded/focused runs are retained and never added to successor totals.',
'localFunctionalComplete':not drift and not helper_drift and all(v['status']=='PASS' for v in local.values()),
'automationComplete':False,'results':results}
(HERE/'validation.json').write_text(json.dumps(record,indent=2)+'\n',encoding='utf-8')
print(json.dumps({n:v['status'] for n,v in results.items()}))
if drift or helper_drift: raise SystemExit('Frozen input drift: '+str(drift+helper_drift))
if '--collect-only' not in sys.argv: prior.require_complete(results)
if __name__=='__main__':main()
@@ -0,0 +1,38 @@
from pathlib import Path
import subprocess,json,datetime,re,sys,hashlib
ROOT=Path(__file__).resolve().parents[5]
PDF="C:/Users/Connor/.cache/codex-runtimes/codex-primary-runtime/dependencies/python/python.exe" if sys.platform=='win32' else sys.executable
out=Path(sys.argv[1]).resolve()
assert out.is_relative_to(ROOT/".artifacts/p9-sec-02")
assert not (out/"result.json").exists(), "Preserve previous evidence."
root=out/'linux/fidelity'
files=[root/'long-skills-minimal-en/measurements.json',root/'long-skills-technical-nb/measurements.json']
records=[json.loads(p.read_text(encoding='utf-8')) for p in files]
assert len({r['browserVersion'] for r in records})==1
fixtures=[f for r in records for f in r['fixtures']]
assert {f['fixture'] for f in fixtures}=={'long-skills-minimal-en','long-skills-technical-nb'}
assert len(fixtures)==2
(root/'measurements.json').write_text(json.dumps({'browserVersion':records[0]['browserVersion'],'fixtures':fixtures},indent=2,ensure_ascii=False)+'\n',encoding='utf-8')
inputs={str(path.resolve()):hashlib.sha256(path.read_bytes()).hexdigest() for path in root.rglob('*') if path.is_file()}
inputs[str((ROOT/'scripts/verify-cv-fidelity.py').resolve())]='64f82e622cc11483c33307d987e969f6cf27f82ab6bdbd72c2aeb1bfbceade87'
assert all(hashlib.sha256(Path(name).read_bytes()).hexdigest()==digest for name,digest in inputs.items())
(out/'oracle-inputs.json').write_text(json.dumps({'inputs':inputs},indent=2)+'\n',encoding='utf-8')
with (out/'oracle.log').open('w',encoding='utf-8') as log:
result=subprocess.run(['rtk','proxy',PDF,'-B','scripts/verify-cv-fidelity.py',str(root)],cwd=ROOT,stdout=log,stderr=subprocess.STDOUT)
record={'oracleExitCode':result.returncode,'status':'PASS' if result.returncode==0 else 'FAIL','scope':'Two supplemental real-MariaDB/Linux long-skill fixtures, separate from original24 and ordinary362.','observedUtc':datetime.datetime.now(datetime.timezone.utc).isoformat()}
report=json.loads((root/'fidelity-results.json').read_text(encoding='utf-8'))
assert all(hashlib.sha256(Path(name).read_bytes()).hexdigest()==digest for name,digest in inputs.items()),'Oracle input drift'
record['inputs']=inputs
record['reportSha256']=hashlib.sha256((root/'fidelity-results.json').read_bytes()).hexdigest()
assert report['total']==2 and {f['fixture'] for f in report['fixtures']}=={f['fixture'] for f in fixtures}
record['cases']=report['fixtures']
for case in report['fixtures']:
text='\n'.join(p['text'] for p in case['pages'])
assert set(re.findall(r'\bS\d{2}\b',text))=={f'S{i:02}' for i in range(1,65)},case['fixture']
assert 'Åse' in text and 'Østby' in text,case['fixture']
assert text.count('Åse')==1,case['fixture']
assert all(value not in text for value in ['file://','http://localhost','document.html']),case['fixture']
assert not re.search(r'\b(?:20\d\d[-/.]\d{1,2}[-/.]\d{1,2}|\d{1,2}[-/.]\d{1,2}[-/.](?:20)?\d{2})\b',text),case['fixture']
(out/'result.json').write_text(json.dumps(record,indent=2,ensure_ascii=False)+'\n',encoding='utf-8')
print('Supplemental long-skills/header-footer proof:',record['status'],flush=True)
raise SystemExit(result.returncode)
@@ -0,0 +1,19 @@
from pathlib import Path
import unittest
import reconcile
class FreshEvidenceBoundaryTests(unittest.TestCase):
def test_historical_pdf_record_cannot_be_a_fresh_result(self):
with self.assertRaises(ValueError):
reconcile.require_fresh(reconcile.ROOT/'.artifacts/p9-remed-02/final-linux/linux-pdf.json')
def test_similar_prefix_is_not_the_current_package(self):
with self.assertRaises(ValueError):
reconcile.require_fresh(reconcile.ROOT/'.artifacts/p9-sec-02-old/result.json')
def test_current_pdf_evidence_root_is_accepted(self):
reconcile.require_fresh(reconcile.ROOT/'.artifacts/p9-sec-02/final-linux/linux-pdf.json')
if __name__=='__main__':unittest.main()
File diff suppressed because one or more lines are too long
@@ -0,0 +1,33 @@
{
"schemaVersion": 1,
"observedUtc": "2026-10-25T12:40:26.607660+00:00",
"verdicts": {
"Python Dependency Security": "CONDITIONAL PASS",
"Model/Cache Compatibility": "PASS",
"Hosted MariaDB CI": "BLOCKED",
"Hosted Runner Isolation": "UNVERIFIED",
"RD21": "RESOLVED",
"Linux PDF Fidelity": "PASS",
"Phase 9": "CONDITIONAL GO",
"CV-UX-01 Readiness": "NO-GO",
"Phase 10 Readiness": "NO-GO",
"Production": "NO-GO"
},
"securityCondition": "Exact installed OSV/PyPI review has zero advisory records but one retained vendor-PyPI404 for the CPU-local Torch version; official wheel hash/vendor ranges/current scoped source and actual model evidence supplement that unavailable response. No global package/image or deployed-security claim; no owner risk acceptance.",
"phase9Authority": [
"docs/redesign/phase-9/REQUEST.md:246-252 permits genuine unfinished human checks to remain release gates",
"docs/redesign/phase-9/REQUEST.md:426-439 requires individual disposition, never automatic PARTIAL=PASS",
"docs/redesign/phase-9/REQUEST.md:581-598 separates development/Phase10/production",
"P9-SEC-02 CI-M01 explicitly permits operator-blocked hosted CI to remain BLOCKED while independent local qualification continues"
],
"cvUxEntry": "No approved standalone CV-UX-01 entry/scope artifact was found. REQUEST.md:456 requires a separate issue and dependencies for new features. Implementation remains withheld until that scope/entry decision; unrelated production-only conditions do not prohibit separately scoped planning. This task does not start that work.",
"phase10Entry": "IMPLEMENTATION_PLAN.md:164-170 requires candidate-specific unused-route/caller proof, affected tests and satisfied functionality inventory. No deletion candidate proof or carry-forward waiver is established by this task.",
"production": "Task prohibits release. Filesystem integrity, independent off-disk backup/restore/rollback, deployed identity/configuration/security, model/cache migration, monitoring, provider and human gates remain unverified.",
"evidence": {
"validation": "validation.json",
"advisories": ".artifacts\\p9-sec-02\\final-advisories\\summary.json",
"dispositions": "DISPOSITIONS.json",
"ci": "ci-assessment.json"
},
"formalRiskAccepted": false
}