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
14 changes: 8 additions & 6 deletions .github/workflows/quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ permissions:
contents: read
jobs:
tests:
if: ${{ !contains(github.event.head_commit.message, '[source-upload]') }}
if: ${{ !contains(github.event.head_commit.message, '[source-upload]') && !contains(github.event.head_commit.message, '[prepare]') }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
Expand All @@ -19,30 +19,32 @@ jobs:
with:
python-version: ${{ matrix.python }}
cache: pip
- run: python -m pip install -r requirements-dev.txt
- run: python -m pip install -q -r requirements-dev.txt
- run: python -m pytest -q --junitxml=test-results/results.xml
- uses: actions/upload-artifact@v4
if: always()
with:
name: tests-${{ matrix.os }}-${{ matrix.python }}
path: test-results/results.xml
browser:
if: ${{ !contains(github.event.head_commit.message, '[source-upload]') }}
if: ${{ !contains(github.event.head_commit.message, '[source-upload]') && !contains(github.event.head_commit.message, '[prepare]') }}
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: python -m pip install -r requirements-dev.txt
- run: python -m pip install -q -r requirements-dev.txt
- run: python -m playwright install --with-deps chromium
- run: python scripts/ui_smoke.py
- run: python scripts/ui_studio_smoke.py
- run: python scripts/ui_science_smoke.py
- run: python scripts/ui_graphify_smoke.py
- run: python scripts/ui_polemic_smoke.py
- run: python scripts/ui_voices_smoke.py
- uses: actions/upload-artifact@v4
if: always()
with:
name: browser-screenshots
path: test-results/ui/
name: browser-workflows
path: test-results/
26 changes: 26 additions & 0 deletions .github/workflows/voice-manifest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Refresh verified voice release manifest
on:
push:
branches: ['fix/jev-voice-graphs-v0.5']
permissions:
contents: write
jobs:
manifest:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Refresh code-only manifest; never change application source or workflows
run: |
python scripts/prepare_assets.py --manifest
git add publish-manifest.json
git diff --cached --check
if ! git diff --cached --quiet; then
git config user.name 'github-actions[bot]'
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
git commit -m 'Refresh source-only publishing manifest'
git push origin HEAD:fix/jev-voice-graphs-v0.5
fi
88 changes: 88 additions & 0 deletions .github/workflows/voices-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
name: GraphPaper 0.5 hosted Windows release
on:
push:
branches: [main]
paths: ['graphpaper/__init__.py', '.github/workflows/voices-release.yml']
workflow_dispatch:
permissions:
contents: read
concurrency:
group: graphpaper-0.5-release
cancel-in-progress: false
jobs:
validate:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: test "$(python -c 'from graphpaper import __version__; print(__version__)')" = '0.5.0'
- run: python -m pip install -q -r requirements-dev.txt
- run: python -m pytest -q --junitxml=test-results/linux.xml
- run: python scripts/docs_tool.py check
- run: python -m playwright install --with-deps chromium
- run: python scripts/ui_smoke.py
- run: python scripts/ui_studio_smoke.py
- run: python scripts/ui_science_smoke.py
- run: python scripts/ui_graphify_smoke.py
- run: python scripts/ui_polemic_smoke.py
- run: python scripts/ui_voices_smoke.py
- uses: actions/upload-artifact@v4
if: always()
with:
name: voices-linux-validation
path: test-results/
windows:
needs: validate
runs-on: windows-latest
timeout-minutes: 30
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: python -m pip install -q -r requirements-dev.txt
- run: python -m pytest -q --junitxml=test-results/windows.xml
- name: Build with public Graphify and official Codex
shell: pwsh
env:
GITHUB_TOKEN: ${{ github.token }}
run: ./scripts/build_release.ps1
- run: python scripts/native_smoke.py --science --graphify --polemic --voices --executable dist/GraphPaper/GraphPaper.exe --out test-results/native-package
- uses: actions/upload-artifact@v4
with:
name: GraphPaper-v0.5.0-Windows-x64
path: |
dist/GraphPaper-v0.5.0-Windows-x64.zip
dist/SHA256SUMS.txt
- name: Publish only the successfully tested artifact
shell: pwsh
env:
GH_TOKEN: ${{ github.token }}
run: |
$ErrorActionPreference = 'Stop'
$tag = 'v0.5.0'
$package = 'GraphPaper-v0.5.0-Windows-x64.zip'
$expected = ((Get-Content dist/SHA256SUMS.txt).Split(' ')[0]).Trim().ToLower()
$actual = (Get-FileHash "dist/$package" -Algorithm SHA256).Hash.ToLower()
if ($actual -ne $expected) { throw 'Archive checksum mismatch.' }
gh release view $tag *> $null
if ($LASTEXITCODE -eq 0) { throw 'Release already exists; refusing to overwrite it.' }
gh release create $tag "dist/$package" dist/SHA256SUMS.txt --target $env:GITHUB_SHA --title 'GraphPaper 0.5.0 - Reusable voice graphs' --notes-file docs/RELEASE-0.5.0.md --draft
if ($LASTEXITCODE -ne 0) { throw 'Release upload failed.' }
$releases = gh api "repos/$env:GITHUB_REPOSITORY/releases?per_page=100" | ConvertFrom-Json
$release = $releases | Where-Object { $_.tag_name -eq $tag }
if (-not $release) { throw 'The uploaded draft release could not be found.' }
$asset = $release.assets | Where-Object { $_.name -eq $package }
if ($asset.digest -ne "sha256:$actual") { throw 'Uploaded artifact does not match the tested ZIP.' }
gh release edit $tag --draft=false --latest
if ($LASTEXITCODE -ne 0) { throw 'Release publication failed.' }
- uses: actions/upload-artifact@v4
if: always()
with:
name: voices-windows-validation
path: test-results/
9 changes: 5 additions & 4 deletions .github/workflows/windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ jobs:
- run: python scripts/ui_science_smoke.py
- run: python scripts/ui_graphify_smoke.py
- run: python scripts/ui_polemic_smoke.py
- run: python scripts/ui_voices_smoke.py
windows:
needs: quality
runs-on: windows-latest
timeout-minutes: 25
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
Expand All @@ -37,8 +38,8 @@ jobs:
env:
GITHUB_TOKEN: ${{ github.token }}
run: ./scripts/build_release.ps1
- name: Exercise the actual Windows window, native dialogs and save-on-close
run: python scripts/native_smoke.py --science --graphify --polemic --executable dist/GraphPaper/GraphPaper.exe --out test-results/native-package
- name: Exercise the actual Windows window, voices, native dialogs and save-on-close
run: python scripts/native_smoke.py --science --graphify --polemic --voices --executable dist/GraphPaper/GraphPaper.exe --out test-results/native-package
- uses: actions/upload-artifact@v4
with:
name: GraphPaper-Windows-x64
Expand All @@ -54,7 +55,7 @@ jobs:
$version = python -c "from graphpaper import __version__; print(__version__)"
if ($env:GITHUB_REF_NAME -ne "v$version") { throw 'Tag does not match application version.' }
gh release view $env:GITHUB_REF_NAME *> $null
if ($LASTEXITCODE -ne 0) { gh release create $env:GITHUB_REF_NAME --verify-tag --title "GraphPaper $env:GITHUB_REF_NAME" --notes-file docs/RELEASE-0.4.0.md }
if ($LASTEXITCODE -ne 0) { gh release create $env:GITHUB_REF_NAME --verify-tag --title "GraphPaper $env:GITHUB_REF_NAME" --notes-file "docs/RELEASE-$version.md" }
$packageName = "GraphPaper-v$version-Windows-x64.zip"
$release = gh release view $env:GITHUB_REF_NAME --json assets | ConvertFrom-Json
if ($release.assets.name -contains $packageName) {
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Changelog

## 0.5.0

- Bound and automatically batch JEV requests by actual serialized UTF-8 size; remove voice-training prose from decision payloads.
- Add named, reusable voice graphs with independent training, graph editing, import/export and explicit application across projects.
- Compose namespaced style/evidence overlays without altering the research graph; current author instructions override saved style preferences.
- Keep unrepresentable optional decisions honestly unscored instead of aborting completed writing.
- Implement and validate the update using GitHub-hosted runners only.


## 0.4.0

- Add Polemic and a reversible writing-mode switch for existing projects.
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ Science adds a **Research** desk for scholarly search, screening and evidence ap

The portable build needs Microsoft Edge WebView2 and is currently unsigned. Existing projects live separately from the executable. [Windows setup and upgrades →](docs/WINDOWS.md)

**New: reusable voice graphs.** Save a voice once, select it in any project, and keep its training pieces separate. JEV receives compact graph context with automatic request sizing—not the article pile. [Voice graphs and author control](docs/VOICE-GRAPHS.md)

## What makes it useful

- **Explore before committing.** Inspect source-linked concepts and relationships, follow paths, pin ideas and compare competing angles. Edit a suggested thesis or write your own.
Expand Down
6 changes: 5 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

**A studio for connected thought.** GraphPaper brings source material, graph exploration and a writing desk into one local-first Windows application.

These guides describe **GraphPaper 0.4.0**. The [release page](https://github.com/AronAxe/GraphPaper/releases/latest) provides the current Windows download; [CHANGELOG](../CHANGELOG.md) records version history. The same guides are published in the [GitHub wiki](https://github.com/AronAxe/GraphPaper/wiki).
These guides describe **GraphPaper 0.5.0**. The [release page](https://github.com/AronAxe/GraphPaper/releases/latest) provides the current Windows download; [CHANGELOG](../CHANGELOG.md) records version history. The same guides are published in the [GitHub wiki](https://github.com/AronAxe/GraphPaper/wiki).

## Start here

Expand Down Expand Up @@ -46,3 +46,7 @@ These guides describe **GraphPaper 0.4.0**. The [release page](https://github.co
## Documentation maintenance

These Markdown files are the maintained source. [The documentation tooling](DEVELOPMENT.md#maintaining-the-documentation) validates links and renders the wiki with consistent navigation; screenshots are shared rather than copied into every page. Historical release notes stay available, but they are not the current setup guide.

## Reusable voices and bounded JEV decisions

[Save a voice graph once and reuse it across projects](VOICE-GRAPHS.md). Training pieces are separate from article evidence; current author instructions override saved preferences.
14 changes: 14 additions & 0 deletions docs/RELEASE-0.5.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# GraphPaper 0.5.0 — reusable voice graphs and bounded JEV

- Fix oversized JEV requests with exact UTF-8 payload preflight, automatic question/candidate batching and compact voice-graph context. Raw voice-training articles are not sent to JEV. The existing 60 KB application budget is not simply raised.
- Save and name a voice once, then apply its compact graph in any project without another model call or re-uploading the articles. Legacy learned profiles can be saved without retraining.
- Separate voice training pieces from project evidence, with upload, pasted text and article-URL inputs in the voice library.
- Edit the mini graph's habits and weights, export/import it, and view a namespaced style/evidence overlay without modifying the research graph.
- Keep author control: power language is not filtered, and current project instructions override saved style habits. Applying or updating a voice does not choose the author's opinion.
- Preserve existing profiles, source documents, graphs, settings and manuscripts. Failed/oversized optional decisions cannot destroy completed writing or fabricate a passing score.

Download the Windows ZIP, extract it fully, and run `GraphPaper.exe` with `_internal` alongside it. The package is unsigned and retains the public Graphify runtime, Codex OAuth, reasoning controls, Polemic and Science/APA features.

For an existing voice, open **Your writing voice → Save as reusable voice**. In another project, open **My voices → Use in this project**. The [voice-graph guide](https://github.com/AronAxe/GraphPaper/blob/main/docs/VOICE-GRAPHS.md) explains the graph editor, training library, overlay, precedence and request sizing.

Development, regression testing and Windows packaging for this update run on GitHub-hosted runners—not the user's computer. The release workflow and attached reports record the actual completed checks. Synthetic provider responses test routing and size handling; they are not a claim of live JEV quality evaluation.
39 changes: 39 additions & 0 deletions docs/VOICE-GRAPHS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Reusable voice graphs and compact JEV decisions

Create a voice once, name it, and apply it in any project. You do not need to upload or analyze the same writing repeatedly.

## Save the voice you already made

Open **Your writing voice**, then **Save as reusable voice**. The existing profile becomes a small node-and-edge graph without a new model call. Its training pieces are copied into the separate voice library; original project files are not deleted. Legacy voice samples are hidden from the evidence-card view, not mistaken for research.

In **My voices**, select the saved voice and choose **Use in this project**. Only the compact profile/graph is applied. No training articles are copied into the new project and no inference is run. Each project retains a snapshot, so changing or deleting the library entry does not silently alter other manuscripts. Apply the updated voice explicitly when desired.

## Build and edit a voice

Choose **New voice** in the library. Add writing by file upload, pasted text or an article URL under **Training pieces**. **Learn / rebuild graph** analyzes the samples once, with the configured extraction model. A learned graph captures rhythm, diction, structure, humor, rhetorical habits, imagery and force. Training text is stored separately in the local database and is sent for learning only; it is not put into ordinary JEV decisions.

You can instead enter style directions and convert them to nodes without a model call. Click a graph node to edit its instruction and importance. Add or remove habits, give the voice a name and save it. A saved voice can be exported/imported as a small JSON graph without the training articles or credentials.

**The voice graph is not a censor.** Strong language, profanity, ridicule, indignation and an uncompromising conclusion are valid author choices. A saved voice is a reusable default, not a rulebook: the current article brief and explicit instructions take precedence. Factual provenance and rhetorical strength are different things.

## Graph overlay

**View graph overlay** composes the saved style graph and a bounded view of the project graph. IDs are namespaced and the evidence, style and overlay layers stay distinguishable. Style edges describe how to express material, not whether an empirical claim is true. The stored evidence graph is not overwritten.

Graphify supports graph merging with namespaced IDs. This integration uses the compatible NetworkX node-link representation and graph composition already available in GraphPaper; it does not need another Graphify extraction or claim that lexical overlap proves semantic equivalence. A style directive can target a kind of project node, such as a claim, without becoming a source for that claim.

## Why JEV no longer receives the whole heap

JEV receives the compact style-graph view, the authorial contract and the material relevant to its typed questions. Raw training pieces are excluded. Candidate-specific decisions are automatically divided and combined according to the **serialized UTF-8 payload size**, with original question keys and candidate IDs retained. Questions can also be split independently. Repeated long strings can use lossless references instead of being duplicated.

The 60 KB cap is a GraphPaper transport budget, not a statement about a universal JEV model limit. The complete outgoing model/state/questions envelope is checked, including Unicode. Batches are planned before spending calls; receipts record their actual size and count. This does not raise the limit or quietly remove an author's thesis.

If a single decision genuinely cannot fit without discarding essential content, that optional decision stays **unscored**, with a job message. It does not abort the writing or pretend to approve an automatic revision. No missing result is converted into a made-up probability. API errors and invalid typed answers remain real errors, separate from local size planning.

## Storage and compatibility

The voice library is an additive table in the existing local SQLite database. Profiles, graph copies, legacy samples, project graphs and existing settings remain readable. Saved voices are not automatically synchronized to a remote service. Exporting a project includes its applied compact voice snapshot, not the whole global training library. Back up the closed application's local data directory for the complete library.

The update is implemented and built on GitHub-hosted runners. It does not access or modify the user's computer during development.

[Author voice and prose tools](VOICE-AND-PROSE.md) · [Polemic](POLEMIC.md) · [Graph and JEV](GRAPH-AND-JEV.md)
7 changes: 6 additions & 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.4.0",
"docs_version": "0.5.0",
"pages": [
{
"title": "Home",
Expand Down Expand Up @@ -96,6 +96,11 @@
"title": "Releases-and-Packaging",
"source": "docs/PUBLISHING.md",
"section": "Reference"
},
{
"title": "Reusable-Voice-Graphs",
"source": "docs/VOICE-GRAPHS.md",
"section": "Studio guides"
}
]
}
2 changes: 1 addition & 1 deletion graphpaper/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
"""GraphPaper: an evidence-aware, graph-native writing studio."""
__version__ = "0.4.0"
__version__ = "0.5.0"
Loading