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
30 changes: 16 additions & 14 deletions .github/workflows/graph-studio-release.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
name: GraphPaper 0.7 System One release
name: GraphPaper 0.7.1 downloaded-runtime release
on:
push:
branches: [main, feat/system-one-v0.7]
branches: [main, fix/windows-runtime-v0.7.1]
paths:
- 'graphpaper/**'
- 'ui/**'
- 'scripts/**'
- 'tests/**'
- 'docs/RELEASE-0.7.0.md'
- 'docs/RELEASE-0.7.1.md'
- '.github/workflows/graph-studio-release.yml'
workflow_dispatch:
permissions:
Expand Down Expand Up @@ -97,11 +97,13 @@ jobs:
run: ./scripts/build_release.ps1
- name: Exercise the compiled System One desk and existing workspaces
run: python scripts/native_smoke.py --science --graphify --graph-studio --polemic --voices --system-one --executable dist/GraphPaper/GraphPaper.exe --out test-results/native-package
- name: Verify fresh ZIP extraction with Internet-zone DLL marks and native consent
run: python scripts/check_downloaded_release.py dist/GraphPaper-v0.7.1-Windows-x64.zip --out test-results/downloaded-package
- uses: actions/upload-artifact@v4
with:
name: GraphPaper-0.7-tested-Windows
name: GraphPaper-0.7.1-tested-Windows
path: |
dist/GraphPaper-v0.7.0-Windows-x64.zip
dist/GraphPaper-v0.7.1-Windows-x64.zip
dist/SHA256SUMS.txt
- uses: actions/upload-artifact@v4
if: always()
Expand All @@ -121,7 +123,7 @@ jobs:
ref: ${{ needs.source.outputs.revision }}
- uses: actions/download-artifact@v4
with:
name: GraphPaper-0.7-tested-Windows
name: GraphPaper-0.7.1-tested-Windows
path: release-package
- name: Publish the same tested archive, never overwrite an existing release
env:
Expand All @@ -131,13 +133,13 @@ jobs:
cd release-package
sha256sum --check SHA256SUMS.txt
cd ..
if gh release view v0.7.0 >/dev/null 2>&1; then echo 'Release already exists; refusing overwrite.'; exit 1; fi
cp docs/RELEASE-0.7.0.md release-package/notes.md
if gh release view v0.7.1 >/dev/null 2>&1; then echo 'Release already exists; refusing overwrite.'; exit 1; fi
cp docs/RELEASE-0.7.1.md release-package/notes.md
revision=$(git rev-parse HEAD)
digest=$(sha256sum release-package/GraphPaper-v0.7.0-Windows-x64.zip | cut -d' ' -f1)
printf '\n\nCompiled Windows System One, graph editing and native save-on-close checks passed. Validation: https://github.com/%s/actions/runs/%s . Source: %s . Archive SHA-256: %s .\n' "$GITHUB_REPOSITORY" "$GITHUB_RUN_ID" "$revision" "$digest" >> release-package/notes.md
gh release create v0.7.0 release-package/GraphPaper-v0.7.0-Windows-x64.zip release-package/SHA256SUMS.txt --target "$revision" --title 'GraphPaper 0.7.0 — System One decision studio' --notes-file release-package/notes.md --draft
release_id=$(gh api "repos/$GITHUB_REPOSITORY/releases?per_page=100" --jq '.[]|select(.tag_name=="v0.7.0")|.id')
uploaded=$(gh api "repos/$GITHUB_REPOSITORY/releases/$release_id/assets" --jq '.[]|select(.name=="GraphPaper-v0.7.0-Windows-x64.zip")|.digest')
digest=$(sha256sum release-package/GraphPaper-v0.7.1-Windows-x64.zip | cut -d' ' -f1)
printf '\n\nCompiled Windows, fresh downloaded-ZIP runtime consent, System One and native save-on-close checks passed. Validation: https://github.com/%s/actions/runs/%s . Source: %s . Archive SHA-256: %s .\n' "$GITHUB_REPOSITORY" "$GITHUB_RUN_ID" "$revision" "$digest" >> release-package/notes.md
gh release create v0.7.1 release-package/GraphPaper-v0.7.1-Windows-x64.zip release-package/SHA256SUMS.txt --target "$revision" --title 'GraphPaper 0.7.1 — Windows runtime startup fix' --notes-file release-package/notes.md --draft
release_id=$(gh api "repos/$GITHUB_REPOSITORY/releases?per_page=100" --jq '.[]|select(.tag_name=="v0.7.1")|.id')
uploaded=$(gh api "repos/$GITHUB_REPOSITORY/releases/$release_id/assets" --jq '.[]|select(.name=="GraphPaper-v0.7.1-Windows-x64.zip")|.digest')
test "$uploaded" = "sha256:$digest"
gh release edit v0.7.0 --draft=false --latest
gh release edit v0.7.1 --draft=false --latest
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## 0.7.1 — Downloaded Windows runtime fix

- Detect Internet-blocked bundled window DLLs before Python.NET initialization.
- Verify per-build DLL hashes; ask native consent for narrowly scoped unblocking.
- Replace blanket WebView2 advice with error-specific diagnostics.
- Gate releases on fresh ZIP extraction and native consent/marked-DLL regression, including existing System One, graph and writing workflows.


## 0.6.0

- Replace the green wash with ink-blue/charcoal surfaces and a licensed scan of real graph paper in the sidebar.
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ Use **Codex / ChatGPT sign-in** or your own model API. Keep control of the argum

**The spatial graph studio.** Orbit or flatten your graph, focus its neighborhoods, and edit nodes and connections directly. Ink-blue surfaces and a real scanned graph-paper sidebar. [Explore the graph controls](docs/GRAPH-STUDIO.md).

**Windows startup fix in 0.7.1:** downloaded runtime files are checked against this build and unblocked only after your permission. The complete ZIP is now tested with simulated Internet download marks. [Startup help](docs/WINDOWS.md#downloaded-runtime-permission).

## How GraphPaper works

![GraphPaper workflow: sources to graph, angles, outline, draft, review and export, guided by your brief and reusable voice with optional Science research and JEV decision support](docs/images/graphpaper-workflow.svg)
Expand Down
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

**Connect your sources. Find your angle. Write in your own voice.**

These guides cover **GraphPaper 0.7.0**: the System One decision studio, ink-blue interface, real graph-paper sidebar, spatial graph editor, four writing modes and reusable voice graphs. [Download for Windows](https://github.com/AronAxe/GraphPaper/releases/latest) · [System One guide](SYSTEM-ONE.md) · [See the interface](VISUAL-TOUR.md) · [Version history](../CHANGELOG.md).
These guides cover **GraphPaper 0.7.1**: the System One decision studio, ink-blue interface, real graph-paper sidebar, spatial graph editor, four writing modes and reusable voice graphs. [Download for Windows](https://github.com/AronAxe/GraphPaper/releases/latest) · [System One guide](SYSTEM-ONE.md) · [See the interface](VISUAL-TOUR.md) · [Version history](../CHANGELOG.md).

## Start here

Expand Down
17 changes: 17 additions & 0 deletions docs/RELEASE-0.7.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# GraphPaper 0.7.1 — Windows downloaded-runtime startup fix

Addresses the reproduced **Failed to resolve Python.Runtime.Loader.Initialize** startup failure caused by Windows Internet-zone marks on bundled DLLs. The previous native tests exercised build files, not this downloaded-file condition.

- Checks exact bundled DLL paths and embedded per-build hashes before loading the Python/.NET bridge.
- Shows **GraphPaper runtime permission** only when affected files carry an Internet/Restricted-zone mark. Choose Yes only if you trust your downloaded release; No leaves the marks in place and cancels startup.
- Removes only the listed runtime DLL marks, never project files, unrelated DLLs, or system-wide security policy. Incorrect or mixed DLLs are not unblocked.
- Gives error-specific startup advice rather than recommending WebView2 for every error.
- Tests a fresh extraction of the actual release ZIP with simulated DLL Internet-zone marks, both native consent choices, and the full native graph, Science, Polemic, voice and System One workflows. This does not simulate SmartScreen or all antivirus/policy configurations.

## Install

Extract the complete ZIP into a **new folder** and open **GraphPaper.exe** with `_internal` beside it. Approve the scoped runtime dialog when shown and when you trust the release. Keep the existing project data directory. No graph rebuild or voice retraining is needed.

The System One decision studio from v0.7.0 is retained. This patch changes startup/distribution handling, not your writing policy, models, prompts or project data. All release tests use isolated GitHub-hosted machines and synthetic project/model fixtures, not a user's computer or private manuscripts.

[Windows startup details](https://github.com/AronAxe/GraphPaper/blob/main/docs/WINDOWS.md#downloaded-runtime-permission)
4 changes: 4 additions & 0 deletions docs/SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,7 @@ The Windows release bundles an official Codex runtime with version and checksum
Before sharing a log, screenshot or project, remove credentials, confidential writing and personal data. Report ordinary reproducible defects through [Issues](https://github.com/AronAxe/GraphPaper/issues). Use an established private contact route to the repository maintainer for a security-sensitive report; do not publish active credentials or an exploit against someone’s live installation.

This documentation describes implemented safeguards and their limits, not a formal penetration-test certification. [Validation scope →](QUALITY.md)

## Downloaded Windows runtime files

The v0.7.1 frozen build embeds an allowlist of exact DLL paths and SHA-256 hashes for Python.NET, clr-loader and pywebview. The desktop startup checks files against it and asks explicit native consent before removing Internet/Restricted-zone alternate-stream marks. It rejects missing, changed, traversing, linked or junction-backed runtime paths and rechecks after the dialog. It never recursively unblocks the application directory, changes global .NET trust, disables antivirus, or unblocks project sources. Checksums establish consistency with the already-launched executable, not publisher authentication. The unsigned-release trust decision remains with the user.
4 changes: 4 additions & 0 deletions docs/TROUBLESHOOTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,7 @@ Review diagnostics before sharing them. Never attach `credentials.dpapi`, Codex
## Angles are too cautious or ignore my voice

Use v0.6.0 or newer. The authorial-intent changes introduced in v0.4 remove forced counterbalancing and supplies voice context to the early editorial stages. In an existing project, choose **current mode · Change -> Polemic**, then edit **Core thesis** and **Rhetorical force**. In Angles, choose **Refresh angles with my voice**; old saved angles do not rewrite themselves when a slider changes. The existing graph is reused. Evidence detail is a separate control and never sets how moderate your position must be. Ordinary Nonfiction can also **Develop and defend my position**.

## Python.Runtime.Loader.Initialize failure

This identifies Python.NET assembly loading, not by itself a missing WebView2 installation. A Windows Internet-download mark on `Python.Runtime.dll` reproduces this exact failure. Use the scoped v0.7.1 runtime-permission dialog or follow [downloaded-runtime permission](WINDOWS.md#downloaded-runtime-permission) for an older ZIP. Mismatched files, missing .NET dependencies and restrictive machine policy require inspecting the actual log rather than repeatedly reinstalling WebView2.
8 changes: 8 additions & 0 deletions docs/WINDOWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,11 @@ For model, import and manuscript problems, continue with [Troubleshooting](TROUB
## External Graphify

The current Windows package includes the public Graphify runtime and its dependencies. No separate Graphify installation is required. Clear an old custom executable path to select the included runtime; custom paths are never silently overridden. [Detailed setup and distribution](UPDATE-0.3.1.md).

## Downloaded runtime permission

In v0.7.1, GraphPaper checks its packaged window DLLs before loading Python.NET. Windows may mark files extracted from a downloaded ZIP as Internet files, preventing .NET from loading them. When needed, a native **GraphPaper runtime permission** dialog lists the affected, checksum-matched DLLs. Choose **Yes** only when you trust the release you downloaded. **No** cancels startup without changing files or opening the project database. This repair changes only the download marks on the listed bundled runtime files, not their bytes, your projects, unrelated files, antivirus settings, or global Windows security policy. Per-build hashes prevent mixed/corrupt runtimes being unblocked; they are not a substitute for trusting the release's publisher.

For an older release reporting **Failed to resolve Python.Runtime.Loader.Initialize**, close the app. In Explorer, right-click the original release ZIP, choose **Properties → Unblock → Apply**, then extract the complete ZIP into a fresh folder. Keep `_internal` beside `GraphPaper.exe`; your project data directory stays separate. This is a repair for a downloaded-file block, not every possible .NET initialization failure. If there is no Unblock checkbox or the failure persists, retain `%LOCALAPPDATA%\GraphPaper\desktop.log` (or the log in your configured data directory) for diagnosis. Do not disable antivirus or change system-wide .NET trust settings.

The release test now extracts the actual ZIP, simulates Internet-zone marks on DLLs, exercises both native consent choices, and checks the full native workflow. It does not claim to simulate SmartScreen or every managed Windows policy.
23 changes: 23 additions & 0 deletions docs/validation/v0.7.1/download-mark-reproduction.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"versions": {
"pywebview": "6.2.1",
"pythonnet": "3.2.1",
"clr_loader": "0.3.1"
},
"plain": {
"returncode": 0,
"stdout": "Python.NET initialized\n",
"stderr": ""
},
"internet_marked": {
"returncode": 1,
"stdout": "",
"stderr": "Traceback (most recent call last):\n File \"<string>\", line 1, in <module>\n File \"C:\\hostedtoolcache\\windows\\Python\\3.12.10\\x64\\Lib\\site-packages\\clr.py\", line 6, in <module>\n load()\n File \"C:\\hostedtoolcache\\windows\\Python\\3.12.10\\x64\\Lib\\site-packages\\pythonnet\\__init__.py\", line 143, in load\n func = assembly.get_function(\"Python.Runtime.Loader.Initialize\")\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"C:\\hostedtoolcache\\windows\\Python\\3.12.10\\x64\\Lib\\site-packages\\clr_loader\\types.py\", line 95, in get_function\n return ClrFunction(self._runtime, self._path, name, func)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"C:\\hostedtoolcache\\windows\\Python\\3.12.10\\x64\\Lib\\site-packages\\clr_loader\\types.py\", line 59, in __init__\n self._callable = runtime._get_callable(assembly, typename, func_name)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"C:\\hostedtoolcache\\windows\\Python\\3.12.10\\x64\\Lib\\site-packages\\clr_loader\\netfx.py\", line 47, in _get_callable\n raise RuntimeError(\nRuntimeError: Failed to resolve Python.Runtime.Loader.Initialize from C:\\hostedtoolcache\\windows\\Python\\3.12.10\\x64\\Lib\\site-packages\\pythonnet\\runtime\\Python.Runtime.dll\n"
},
"unblocked": {
"returncode": 0,
"stdout": "Python.NET initialized\n",
"stderr": ""
},
"reproduced": true
}
2 changes: 1 addition & 1 deletion docs/wiki-pages.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"repository": "AronAxe/GraphPaper",
"docs_version": "0.7.0",
"docs_version": "0.7.1",
"pages": [
{"title":"Home","source":"docs/README.md","section":"Start here"},
{"title":"Visual-Tour","source":"docs/VISUAL-TOUR.md","section":"Start here"},
Expand Down
2 changes: 1 addition & 1 deletion graphpaper/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.7.0"
__version__ = "0.7.1"
2 changes: 2 additions & 0 deletions graphpaper/_runtime_hashes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
"""Filled by scripts/runtime_manifest.py immediately before the Windows build."""
FILES = {}
8 changes: 7 additions & 1 deletion graphpaper/desktop.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ def run(browser: bool = False):
root = data_directory()
root.mkdir(parents=True, exist_ok=True)
logging.basicConfig(filename=str(root / "desktop.log"), level=logging.WARNING)
if not browser:
from .windows_runtime import prepare
prepare()
app = create_app(root)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Keep the ephemeral listener open until handed to uvicorn (no port-selection race).
Expand Down Expand Up @@ -225,15 +228,18 @@ def main():
if args.self_test:
self_test(args.self_test)
return
from .windows_runtime import RepairDeclined, startup_advice
try:
run(args.browser)
except RepairDeclined:
return
except Exception as e:
logging.exception("GraphPaper could not start")
try:
import tkinter as tk
from tkinter import messagebox
root = tk.Tk(); root.withdraw()
messagebox.showerror("GraphPaper could not open", f"{e}\n\nOn Windows, install Microsoft Edge WebView2 Runtime.\nDetails are in GraphPaper's local desktop.log.")
messagebox.showerror("GraphPaper could not open", f"{e}\n\n{startup_advice(e)}\nDetails: {data_directory() / 'desktop.log'}")
root.destroy()
except Exception:
print(f"GraphPaper could not start: {e}", file=sys.stderr)
Expand Down
Loading