Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .github/workflows/LinuxInstall.yml
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,27 @@ jobs:
--output "$evidence_dir/evidence.json" \
--report "$evidence_dir/inspection.txt" 2>&1 | tee "$evidence_dir/inspector.txt"

- name: Generate final-artifact SBOM and notices
working-directory: loop
run: |
evidence_dir="$RUNNER_TEMP/loop-package-boundary-linux"
python3 scripts/ci/generate_package_sbom.py \
--evidence "$evidence_dir/evidence.json" \
--output "$evidence_dir/components.spdx.json"
python3 scripts/ci/generate_package_third_party_notices.py \
--evidence "$evidence_dir/evidence.json" \
--output "$evidence_dir/THIRD_PARTY_NOTICES.txt"

- name: Run Qt LGPL relink test
working-directory: loop
env:
QT_QPA_PLATFORM: offscreen
run: |
evidence_dir="$RUNNER_TEMP/loop-package-boundary-linux"
bash scripts/ci/run_qt_relink_test.sh \
"build/${{ env.appimagefilename }}" \
--output "$evidence_dir/qt-relink.txt"

- name: Upload Linux package boundary evidence
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
Expand Down
22 changes: 22 additions & 0 deletions .github/workflows/WindowsInstall.yml
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,18 @@ jobs:
$inspectorOutput | Tee-Object -FilePath (Join-Path $evidenceDir "inspector.txt")
if ($LASTEXITCODE -ne 0) { throw "MSI package boundary inspection failed." }

- name: Generate final-artifact SBOM and notices
shell: pwsh
run: |
$evidenceDir = Join-Path $env:RUNNER_TEMP "loop-package-boundary-windows"
python ".\loop\scripts\ci\generate_package_sbom.py" `
--evidence (Join-Path $evidenceDir "evidence.json") `
--output (Join-Path $evidenceDir "components.spdx.json")
python ".\loop\scripts\ci\generate_package_third_party_notices.py" `
--evidence (Join-Path $evidenceDir "evidence.json") `
--output (Join-Path $evidenceDir "THIRD_PARTY_NOTICES.txt")
if ($LASTEXITCODE -ne 0) { throw "Final-artifact notices generation failed." }

- name: Run MSI lifecycle smoke test
shell: pwsh
run: |
Expand All @@ -460,6 +472,16 @@ jobs:
-SourceSha $env:LOOP_SOURCE_SHA `
-SkipEditorLaunch

- name: Run Qt LGPL relink test
shell: pwsh
run: |
$evidenceDir = Join-Path $env:RUNNER_TEMP "loop-package-boundary-windows"
$installDir = Join-Path ([Environment]::GetFolderPath("ProgramFiles")) "LOOP"
& ".\loop\scripts\ci\run_qt_relink_test.ps1" `
-InstallDir $installDir `
-SourceSha $env:LOOP_SOURCE_SHA `
-OutputPath (Join-Path $evidenceDir "qt-relink.txt")


- name: Upload Windows package boundary evidence
if: always()
Expand Down
4 changes: 4 additions & 0 deletions changes/cursor-session-13-package-licensing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Category: internal
Audience: Release engineering and maintainers
Breaking-Change: no
Summary: Add final-artifact SBOM and third-party-notices generators, Qt LGPL relink test scripts, Session 13 package-licensing procedure and evidence scaffolding, and wire package workflows to emit licensing artifacts from packaged payloads.
6 changes: 3 additions & 3 deletions docs/0.2.0-closeout-matrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

**Status:** Phase 5 Sessions 01–09 terminalized on `stable` (PR #534); Session 09 ledger commits await backport to `dev` before qualification lanes 10–13 start; E-01 awaits hosted Release Gate on a merged SHA
**Owner:** 0.2.0
**Updated:** 2026-09-06
**Updated:** 2026-09-06 (Session 11 resource-envelope candidate on `cursor/session-11-resource-envelope`) (Session 10 trust qualification candidate on `cursor/session-10-trust-qualification`)

This matrix is the working acceptance ledger for the 0.2.0 closeout. It keeps
implementation, static, automated, integrated runtime, independent/platform,
Expand Down Expand Up @@ -36,7 +36,7 @@ own sessions prove them.
| T-01 | Trust contract | `add-bleed` real-path reproduction and fix or typed pre-mutation rejection | Open (not Phase 5 scope) |
| T-02 | Async/cancellation | Linux/Windows governed sites, terminal cancellation, stale-result rejection | Open (not Phase 5 scope) |
| T-03 | Independent validation | Independent parser/signature validator and conversion fixture provenance | Open (not Phase 5 scope) |
| R-01 | Resource envelope | 10,000-page/image-heavy/pathological workloads | Partial — `UnitTestsHugeDocumentEnvelope::tenThousandPageDocumentCompilesFirstPageWithoutTouchingTheRest` (2026-08-30) proves the literal 10,000-page open-to-first-view case against `PDFDocumentSession`'s bounded compile cache, on blank synthetic pages. The 500 MB image-heavy and pathological (many spots/transparency groups) fixtures, and the per-fixture RSS/timing measurement matrix issue #242 asks for, are still open and need real fixtures plus a hosted run, not a synthetic in-process test. Not Phase 5 scope |
| R-01 | Resource envelope | 10,000-page/image-heavy/pathological workloads | **Partial (Session 11)** — fail-closed manifest/matrix frozen on `6e65be48…` in `docs/evidence/session-11-resource-envelope/` (`disposition: incomplete`). Local Windows strict run: 0 measured, identity commit enforced, `-1` preflight/cancel/recovery not promoted. Missing `image-heavy-500mb`, `ten-thousand-page` (DIV2K), Linux hosted matrix, and candidate-SHA PdfTool rebuild |
| L-01 | Lifecycle model | Seeded bounded command traces, replay, shrinking | Open (not Phase 5 scope) |
| Q-01 | Interaction boundary | Typed facades, revision/generation-fenced requests, bounded cache/scheduler | Implemented; `verify-interaction-boundary.py` |
| Q-02 | Direct canvas | Direct `QQuickItem`, scene-graph lifecycle, fidelity/color, backends | Implemented P4-S5–S6; CI on branch |
Expand All @@ -45,7 +45,7 @@ own sessions prove them.
| Q-05 | Interaction regression traces | Replayable scenario corpus, two lanes, and a report that names the first violated contract and the phase responsible | **Partial** — issue #146. The corpus, both schemas, and `scripts/ci/check_interaction_traces.py` are in place and gated in CI (`--corpus-only`, no build). Nine scenarios are tracked; one is marked `blocked_on: gh-488`. The C++ replay harness (`UnitTestsInteractionTraces`), the report writer, and the desktop/GPU present lane are still open, so no verified latency measurement is recorded for this candidate. Not Phase 5 scope |
| W-01 | No Widgets on installed editor | Installed `LoopEditor` must not link or ship Widgets | **Closed (static + configure; Phase 5 terminal graph)** — `verify-installed-product-graph.py`, `verify-widgets-free-release-profile.py` (static + configure probe) in CI, package smoke scans; E-01 hosted Release Gate proof still open |
| P-01 | Cross-platform/package | Linux/Windows native/software smoke, clean-machine package, QML deployment | **Closed (0.2.0)** — same-SHA pair qualified on `b47c62b2…` via workflows `34050834332`/`34050832684`; inspector + paired comparator green; Linux clean-machine AppImage smoke passed in disposable Ubuntu 24.04 container. Windows Server 2022 pristine-VM run **deferred** to release-hardening (required before 1.0) — non-blocking for 0.2.0. See `docs/SESSION_07_PACKAGE_BOUNDARY.md` |
| P-02 | Supply chain/licensing | SBOM, notices, LGPL relink evidence | Open — `docs/quick-runtime-manifest.json` release_gates (not Phase 5 scope) |
| P-02 | Supply chain/licensing | SBOM, notices, LGPL relink evidence | **Open (Session 13 scaffolding)** — artifact-derived generators in `scripts/ci/generate_package_sbom.py`, `generate_package_third_party_notices.py`, `run_qt_relink_test.*`; evidence `docs/evidence/session-13-package-licensing/` status `incomplete` until hosted package builds on candidate SHA. See `docs/SESSION_13_PACKAGE_LICENSING.md` |
| E-01 | Exact-SHA hosted gate | Full Release Gate green on one merged candidate SHA | Open — requires merge + hosted CI (not Phase 5 scope) |
| E-02 | Independent audit | No-fix audit passes after implementation is frozen | Open (not Phase 5 scope) |
| E-03 | Release promotion | Issues updated from merged evidence, package identity, tag/promotion | Open (not Phase 5 scope) |
Expand Down
76 changes: 76 additions & 0 deletions docs/SESSION_13_HANDOFF.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Session 13 — package and licensing qualification handoff

## Scope

Session 13 implements final-artifact SBOM, third-party notices, LGPL relink
evidence tooling, and the package identity / clean-machine procedure for P-02
and P-01 SHA re-proof. Session 07 evidence on `b47c62b2…` does **not**
transfer.

## Baseline

| Field | Value |
| --- | --- |
| Branch | `cursor/session-13-package-licensing` |
| Session 09 baseline | `1c3f9d6d2312045264134f07b4d00e26de2058bf` on `cursor/session-09-ledger-closeout` |
| Candidate SHA (branch HEAD) | `a505a80244b35244cf083872a4b88ea72e4cba1a` (Session 09 baseline + Session 13 scaffolding; uncommitted until PR) |

## Implementation

### Issue 40 — final-artifact SBOM, notices, LGPL evidence

- `scripts/ci/package_licensing_common.py` — shared component/license mapping
- `scripts/ci/generate_package_sbom.py` — SPDX 2.3 from package-boundary evidence
- `scripts/ci/generate_package_third_party_notices.py` — notices from shipped payload
- `scripts/ci/run_qt_relink_test.sh` / `run_qt_relink_test.ps1` — LGPL relink proofs
- Package workflows extended to emit SBOM, notices, and relink transcripts into
evidence artifacts

### Issue 41 — package identity and clean-machine lifecycle

- `docs/SESSION_13_PACKAGE_LICENSING.md` — exact-SHA dispatch, pairing, smoke, and
clean-machine procedure (Ubuntu 24.04 required; Server 2022 deferred)
- Reuses `inspect_package_dependencies.py` and `compare_package_boundary_evidence.py`

### Issue 42 — evidence freeze and gate bookkeeping

- `docs/evidence/session-13-package-licensing/` — evidence home (status `incomplete`
until hosted package builds on candidate SHA)
- `scripts/ci/collect_package_licensing_evidence.py` — manifest assembler
- Closeout matrix P-01/P-02 updated; `quick-runtime-manifest.json` tooling pointers

## Verification record

Local verifier stack:

```
python -m unittest scripts.ci.test_generate_package_licensing -v
python scripts/ci/test_generate_package_licensing.py
python scripts/verify-quick-runtime-contract.py
```

## Gate status (honest)

| Gate | State | Blocker |
| --- | --- | --- |
| P-02 final-artifact SBOM | **Open** | Hosted `Linux_AppImage` + `Windows_MSI` on candidate SHA |
| P-02 third-party notices | **Partial** | Artifact generator implemented; final-artifact proof pending |
| P-02 Qt relink | **Open** | Hosted relink transcripts not yet archived |
| P-01 package identity | **Open** | Must re-prove on candidate SHA (Session 07 `b47c62b2…` invalid) |
| P-01 clean-machine smoke | **Open** | Linux container + Windows hosted MSI smoke on candidate SHA |

## Hosted package build blockers

1. **Approval required** per AGENTS.md for hosted packaging workflow dispatch.
2. Dispatch both workflows with `source_sha=<candidate_sha>` after this branch merges
or from the branch head for qualification.
3. Copy workflow evidence artifacts into `docs/evidence/session-13-package-licensing/`
and run `collect_package_licensing_evidence.py`.
4. Windows Server 2022 pristine VM remains **deferred to 1.0** (non-blocking).

## Next gate

After hosted package evidence is frozen with `status: passed`, update
`quick-runtime-manifest.json` release_gates to `complete` and mark P-02
`acceptance verified` in the closeout matrix. Session 14 requires all lanes
green on the **same** `candidate_sha`.
163 changes: 163 additions & 0 deletions docs/SESSION_13_PACKAGE_LICENSING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
# Session 13 — package and licensing qualification

Session 13 closes P-02 (supply chain/licensing) and re-proves P-01 package
identity on the **exact candidate SHA**. Session 07 evidence on
`b47c62b263a3fd7fb36940856866e589bbc8be10` does **not** transfer.

## Exit gate

- P-02 complete for exact final artifacts: artifact-derived SBOM,
`THIRD_PARTY_NOTICES.txt`, LGPL relink/replace evidence, and archived
corresponding-source or written-offer record.
- P-01 re-proof on the same candidate SHA via paired package-boundary evidence
and clean-machine smoke (Linux required; Windows Server 2022 pristine VM
remains deferred per Session 07).

Do not mark gates `complete` without hosted package artifacts built from the
candidate SHA.

## Candidate SHA discipline

1. Record the Session 09+ merged `candidate_sha` (40-char lowercase hex).
2. Dispatch **both** package workflows with `source_sha=<candidate_sha>`:
- `Linux_AppImage`
- `Windows_MSI`
3. Download evidence artifacts and run the pairing/comparator steps below.
4. If any qualification lane lands code after packaging, **re-run Session 13**
on the new SHA before Session 14.

## Package identity workflow

Follow `docs/SESSION_07_PACKAGE_BOUNDARY.md` for the inspector contract.
Session 13 adds final-artifact licensing outputs on top of the same boundary
evidence.

### 1. Dispatch exact-SHA package builds

```text
workflow: Linux_AppImage
input: source_sha=<candidate_sha>

workflow: Windows_MSI
input: source_sha=<candidate_sha>
```

Both workflows verify checkout SHA, record `LOOP_SOURCE_SHA`, run package-boundary
inspection, and (after this session) emit SBOM, notices, and Qt relink
transcripts into the evidence artifact bundle.

### 2. Pair Linux and Windows boundary evidence

```text
python3 scripts/ci/compare_package_boundary_evidence.py \
--linux package-evidence/linux/evidence.json \
--windows package-evidence/windows/evidence.json \
--source-sha <candidate_sha> \
--output docs/evidence/session-13-package-licensing/paired-evidence.json
```

### 3. Generate artifact-derived SBOM and notices

From each platform's `evidence.json` (final packaged payload, not vcpkg tree):

```text
python3 scripts/ci/generate_package_sbom.py \
--evidence package-evidence/linux/evidence.json \
--output docs/evidence/session-13-package-licensing/linux-components.spdx.json

python3 scripts/ci/generate_package_third_party_notices.py \
--evidence package-evidence/linux/evidence.json \
--output docs/evidence/session-13-package-licensing/linux-THIRD_PARTY_NOTICES.txt
```

Repeat for Windows with `windows-evidence.json` and `windows-*` output names.

### 4. LGPL Qt relink/replace test

Linux AppImage payload:

```text
bash scripts/ci/run_qt_relink_test.sh \
/path/to/Loop-pdf-VERSION-x86_64.AppImage \
--output docs/evidence/session-13-package-licensing/linux-qt-relink.txt
```

Windows installed tree (after MSI install under 64-bit Program Files):

```powershell
.\scripts\ci\run_qt_relink_test.ps1 `
-InstallDir "C:\Program Files\LOOP" `
-SourceSha <candidate_sha> `
-OutputPath docs\evidence\session-13-package-licensing\windows-qt-relink.txt
```

### 5. Clean-machine smoke

| Platform | 0.2.0 requirement | Procedure |
| --- | --- | --- |
| Linux | **Required** | Disposable Ubuntu 24.04 container with no Qt/MSVC/Python/dev paths. Run `scripts/smoke-test-appimage.sh <AppImage> --operator`. Archive transcript to `linux-clean-machine-smoke.txt`. |
| Windows hosted MSI | **Required** | `Invoke-MsiSmokeTest.ps1` on the workflow runner against the exact-SHA MSI (packaged launch outside build tree). Evidence uploaded by `Windows_MSI`. |
| Windows Server 2022 pristine VM | **Deferred to 1.0** | Document as known limitation; not a 0.2.0 blocker. |

Example Linux clean-machine container pattern (from Session 07):

```text
docker run --rm -v "$PWD:/work" -w /work ubuntu:24.04 bash -lc '
apt-get update && apt-get install -y libxcb-cursor0 libfontconfig1 libglib2.0-0 libdbus-1-3
LOOP_SOURCE_SHA=<candidate_sha> bash scripts/smoke-test-appimage.sh /work/Loop-pdf-*.AppImage --operator
'
```

### 6. Freeze Session 13 evidence manifest

```text
python3 scripts/ci/collect_package_licensing_evidence.py \
--linux-evidence docs/evidence/session-13-package-licensing/linux-evidence.json \
--windows-evidence docs/evidence/session-13-package-licensing/windows-evidence.json \
--source-sha <candidate_sha> \
--linux-sbom docs/evidence/session-13-package-licensing/linux-components.spdx.json \
--linux-notices docs/evidence/session-13-package-licensing/linux-THIRD_PARTY_NOTICES.txt \
--windows-sbom docs/evidence/session-13-package-licensing/windows-components.spdx.json \
--windows-notices docs/evidence/session-13-package-licensing/windows-THIRD_PARTY_NOTICES.txt \
--linux-relink docs/evidence/session-13-package-licensing/linux-qt-relink.txt \
--windows-relink docs/evidence/session-13-package-licensing/windows-qt-relink.txt \
--linux-clean-machine docs/evidence/session-13-package-licensing/linux-clean-machine-smoke.txt \
--output docs/evidence/session-13-package-licensing/evidence.json
```

`collect_package_licensing_evidence.py` exits `0` only when `status` is
`passed` (all required artifacts present and boundary evidence passed).

### 7. Update release gates and closeout matrix

When `evidence.json` reports `status: passed`:

- Set `docs/quick-runtime-manifest.json` `release_gates` to `complete` with
evidence pointers (or `partial` until all lanes are green).
- Update `docs/0.2.0-closeout-matrix.md` P-02 to `acceptance verified` and
refresh P-01 SHA binding to `<candidate_sha>`.

## Corresponding source / written offer

Per `docs/PACKAGING_LICENSING.md`, archive the Qt corresponding-source archive
or valid written offer under Berry Studio control. Record the location in the
Session 13 evidence bundle (`written-offer.txt` or equivalent) — not in release
assets.

## Tooling map

| Tool | Purpose |
| --- | --- |
| `scripts/ci/inspect_package_dependencies.py` | Final-artifact dependency graph |
| `scripts/ci/compare_package_boundary_evidence.py` | Paired Linux/Windows SHA proof |
| `scripts/ci/generate_package_sbom.py` | SPDX 2.3 SBOM from boundary evidence |
| `scripts/ci/generate_package_third_party_notices.py` | Notices from shipped payload |
| `scripts/ci/run_qt_relink_test.sh` / `.ps1` | LGPL relink evidence |
| `scripts/ci/collect_package_licensing_evidence.py` | Session evidence manifest |
| `scripts/generate-third-party-notices.ps1` | Legacy vcpkg-tree notices (partial only) |

## Related issues

- Issue 40 — final-artifact SBOM, notices, LGPL evidence
- Issue 41 — package identity and clean-machine lifecycle
- Issue 42 — close P-01/P-02 with final-artifact evidence
30 changes: 30 additions & 0 deletions docs/evidence/session-13-package-licensing/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Session 13 package-licensing evidence

Frozen evidence for Issues 40–42 (P-02 + P-01 SHA re-proof).

**Status:** `incomplete` until hosted package workflows run on the exact candidate
SHA and all required artifacts are copied here.

## Required artifacts (per platform)

| Artifact | Linux | Windows |
| --- | --- | --- |
| Package-boundary evidence | `linux-evidence.json` | `windows-evidence.json` |
| SPDX SBOM | `linux-components.spdx.json` | `windows-components.spdx.json` |
| Third-party notices | `linux-THIRD_PARTY_NOTICES.txt` | `windows-THIRD_PARTY_NOTICES.txt` |
| Qt relink transcript | `linux-qt-relink.txt` | `windows-qt-relink.txt` |
| Clean-machine smoke | `linux-clean-machine-smoke.txt` | workflow transcript (hosted MSI smoke) |

## Paired proof

- `paired-evidence.json` — output of `compare_package_boundary_evidence.py`
- `evidence.json` — Session 13 manifest from `collect_package_licensing_evidence.py`

## Procedure

See `docs/SESSION_13_PACKAGE_LICENSING.md`.

## Session 07 note

Evidence under `docs/evidence/session-07-package-boundary/` remains historical
qualification on `b47c62b2…` and does **not** satisfy Session 13.
Loading
Loading