Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
d4ac219
0.7.0 - read what the cargo cost, not only what it sold for
peans99 Aug 23, 2026
e995ad8
Retire cached sessions, or the buys land only for new installs
peans99 Aug 23, 2026
0064154
Let prices refresh themselves, once somebody says they may
peans99 Aug 23, 2026
3ffabc8
Read the party channel, the only place a 4.9 log names anyone else
peans99 Aug 23, 2026
9762068
Open a commodity in full: what it has been worth, and who wants it
peans99 Aug 23, 2026
aa6bc44
Fail the build when the parser learns something the cache will hide
peans99 Aug 23, 2026
ac4255d
Say when a signal last arrived, since a removal looks like a quiet week
peans99 Aug 23, 2026
dfbdd09
Make the waiver a trailer, so explaining it stops switching it off
peans99 Aug 23, 2026
368d707
Graph a commodity everywhere it appears, not only on its own page
peans99 Aug 23, 2026
5fe54f7
Fix five defects from review: duration, LAN, crash, race, rollback
peans99 Aug 23, 2026
880bf82
Write down what this project keeps teaching people the hard way
peans99 Aug 23, 2026
d8ad7c2
0.7.1 - test the two fixes that were only reasoned about
peans99 Aug 23, 2026
d96e546
Add actionable Now briefing
peans99 Aug 23, 2026
0b79b33
Filter map by services
peans99 Aug 23, 2026
812f039
0.7.2 - add accurate project overview
peans99 Aug 23, 2026
f17ab55
Add pinned preparation checklists
peans99 Aug 23, 2026
5956df1
Rank trade routes by reliability
peans99 Aug 24, 2026
7c3592c
Merge codex/now-brief into dev070
peans99 Aug 24, 2026
55431c3
0.7.6 - act on the review of my own six commits
peans99 Aug 24, 2026
a724d01
Separate accurate system maps from jump network
peans99 Aug 24, 2026
4b1d2cb
Make player location visible on map
peans99 Aug 24, 2026
8a1442b
Offset player map callout
peans99 Aug 24, 2026
2752bf2
Add focused map views and freshness cues
peans99 Aug 24, 2026
56594d6
Refine map symbols and service badges
peans99 Aug 24, 2026
b58e649
Make trade route evidence explicit
peans99 Aug 24, 2026
5ced12e
Let pilots hide Now cards
peans99 Aug 24, 2026
e550357
Use compact Now card controls
peans99 Aug 24, 2026
ee81552
Add session debriefs and route replay
peans99 Aug 24, 2026
b502f1e
Clarify unavailable commodity history
peans99 Aug 24, 2026
50bb2f9
0.7.7 - act on the review of the eight defects before the pull request
peans99 Aug 24, 2026
bf9816b
0.7.17 - integrate map-truth with dev070 for the release
peans99 Aug 24, 2026
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
80 changes: 80 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,83 @@ jobs:
name: test-results
path: artifacts/test
if-no-files-found: ignore

# The most expensive failure this project has is silent: the parser learns to
# read something, and nobody sees it, because backups are skipped by
# fingerprint and every existing session keeps a summary written before the
# field existed. It shipped that way once with medical beds and once with
# commodity purchases, both caught after the fact.
#
# PayloadVersion is the fix - it retires every cached row - and the release
# workflow already proves that a check is what makes "always bump the version"
# a rule rather than a habit. This is the same idea for the other version
# nobody remembers.
#
# Ubuntu on purpose: this is git and grep, and needs none of the SDK.
payload-version:
name: Cached sessions retired
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'

steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0

- name: A parser change must retire the cache
shell: bash
env:
BASE: ${{ github.event.pull_request.base.sha }}
run: |
set -euo pipefail

changed=$(git diff --name-only "$BASE"...HEAD)

# What can widen a stored summary: the parser that reads events, the
# events themselves, the builder that folds them up, and the record it
# produces. Anything else may change freely.
shaping=$(echo "$changed" | grep -E \
'^src/Quantumwake\.Core/(Parsing/|Events/|State/Session\.cs|State/SessionBuilder\.cs)' \
|| true)

if [ -z "$shaping" ]; then
echo "No payload-shaping file touched; nothing to retire."
exit 0
fi

echo "Payload-shaping files in this change:"
echo "$shaping" | sed 's/^/ /'

# Touching SessionStore.cs is not enough - the constant has to move.
if git diff "$BASE"...HEAD -- src/Quantumwake.Data/SessionStore.cs \
| grep -qE '^\+.*PayloadVersion = [0-9]+'; then
echo
echo "PayloadVersion moves in this change. Caches will be retired."
exit 0
fi

# A comment fix or a rename genuinely changes nothing stored, and a
# check that cannot be answered is a check people learn to ignore.
#
# A trailer, anchored to the start of a line, rather than a bare word
# anywhere in the message: the commit that first documented this
# waiver waived the check by explaining it, which is a poor way for a
# guard to fail. Prose can now name the trailer without invoking it.
if git log "$BASE"..HEAD --format='%B' | grep -qiE '^No-payload-bump:[[:space:]]*[^[:space:]]'; then
echo
echo "Waived by a commit trailer:"
git log "$BASE"..HEAD --format='%B' | grep -iE '^No-payload-bump:' | sed 's/^/ /'
exit 0
fi

echo
echo "::error::This change touches the parser or the session summary, but"
echo "::error::PayloadVersion in src/Quantumwake.Data/SessionStore.cs does not move."
echo "::error::"
echo "::error::Sessions already on disk are skipped by fingerprint, so whatever"
echo "::error::this now reads will be invisible to every install that has run"
echo "::error::before - the ones with the most history. Bump the constant, or, if"
echo "::error::nothing stored actually changed, add a commit trailer on its own line:"
echo "::error::"
echo "::error:: No-payload-bump: renamed a private field, nothing new is read"
exit 1
7 changes: 4 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,10 @@ jobs:
### What it does not do

Reads ``Game.log`` only. Nothing is written to the game directory, no memory is
touched, and nothing is injected. The app connects to the internet only when
you ask it to - the optional community dataset, from the Settings page - and
never on its own.
touched, and nothing is injected. The app connects to the internet only where
you have said it may, from the Settings page - the optional datasets, and the
two that can go out unattended: the version check and the market-price
refresh, both off until you turn them on.

Star Citizen must run in Borderless Windowed for the overlay to be visible.
"@
Expand Down
72 changes: 72 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Agents

**Read [CLAUDE.md](CLAUDE.md) first.** It is the standing agreement for anyone
working here — human or otherwise — and it is not Claude-specific despite the
name. This file exists so agents that look for `AGENTS.md` find it.

Nothing below replaces that document. It is the short list of what goes wrong
most often, for an agent that is about to start writing.

## Before you write anything

- **`C:\Quantumwake` is the repository.** `C:\claude` is a convincing stale
snapshot, dozens of commits behind. Check `git log --oneline -1`.
- The main checkout usually has work in progress. Do not switch its branch;
take a detached worktree and remove it when you are done.
- Branches are pushed freely. Pull requests and merges to `main` happen only
when Nicolas asks.

## Versioning

Raise the **patch** in `Directory.Build.props` with every change, in the same
commit as the work, and rename the release-notes heading in `README.md` to match
rather than opening a second one. Major and minor move only when Nicolas says
so.

## The three things that fail silently

1. **`PayloadVersion`.** Change the parser, the events, `Session.cs` or
`SessionBuilder.cs`, and bump it in `src/Quantumwake.Data/SessionStore.cs` in
the same change. Cached sessions are skipped by fingerprint, so without it
the new field is invisible to every install that has run before — and nothing
goes red. CI now catches it; `No-payload-bump: <reason>` waives it when
nothing stored changed.

2. **The release-notes section.** The workflow lifts only the `###` section
matching the version being tagged. Anything under a different heading ships
unmentioned.

3. **A parser that passes its tests and does not read the install.** Run the CLI
over the real backups and check `! unmatched known tags` is 0.

## Prove it, then say it

Every number in a comment, doc, release note or commit message came from running
something. Not "this should now handle purchases" — "13 purchases parse,
unmatched tags drop to zero, and each one's aUEC-per-SCU agrees with the field
the game printed beside it." Where a claim cannot be checked, it is not made.

The strongest check is one the code did not use: a unit conversion verified
against a field the parser never reads catches a hundredfold error that still
looks like a plausible integer.

## Do not disturb the machine you are working on

The app is usually running against `%LOCALAPPDATA%\Quantumwake`, and that is
Nicolas's real data. Copy it and set `QUANTUMWAKE_DATA` to the copy. If a build
fails because the Overlay DLLs are locked, build the individual projects — do
not close his app to unblock yourself.

## Look at the thing you built

Tests do not show a clipped button, a control that only appears on hover, or a
page that renders blank because a local variable shadowed `window.history`. All
three happened here and all three were caught by taking a screenshot and reading
it. CLAUDE.md has the headless-Chrome recipe and its two timing traps.

## House style, in one line each

- Comments explain the constraint that made the obvious approach wrong.
- A missing signal gets an explanation, never a bare zero.
- A number that is a floor is called a floor.
- Negative results get written down so nobody investigates them twice.
88 changes: 87 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,60 @@ In this order, no steps skipped:
`Directory.Build.props`, merge, tag, push the tag. The pipeline refuses to
build when the tag and the version disagree.

## Two version numbers, not one

`Directory.Build.props` is the release version, and the release workflow refuses
to build when the tag disagrees with it. That one is enforced and hard to
forget.

**Raise the patch with every change** — 0.7.1, 0.7.2, 0.7.3 — as part of the
same commit as the work. Major and minor move only when Nicolas says so; never
decide on your own that something is big enough to be 0.8.

Rename the release-notes heading in `README.md` as you go rather than opening a
second one, so there is always exactly one section and it always matches the
version in the props file. That is what keeps the workflow able to find it: it
lifts the section matching the tag and nothing else, and a version that quietly
grew its own heading is a feature nobody reads about.

`PayloadVersion` in `src/Quantumwake.Data/SessionStore.cs` is the one that gets
forgotten, and forgetting it fails **silently**. Backups are skipped by
fingerprint, so a session summarised before a field existed keeps that summary
for ever: the parser reads the new thing, the page asks for it, and every
install that has run before shows nothing. The installs with the most history
see the least. It has shipped that way twice — medical beds in 0.6, commodity
purchases in 0.7.

Touch the parser, the events, `Session.cs` or `SessionBuilder.cs`, and move
`PayloadVersion` in the same change. CI fails the pull request otherwise. When
nothing stored actually changed — a rename, a comment — waive it with a commit
trailer on its own line:

```
No-payload-bump: renamed a private field, nothing new is read
```

`SchemaVersion` beside it answers a different question: bump that only when a
stored payload can no longer be *read*, because a mismatch drops the table
rather than merely re-reading the logs.

## Release notes

Written for someone deciding whether to update, not for the commit log. What
changed and what it means for them; nothing about refactors they cannot see.
The newest version goes directly under the `## Release notes` heading at the
bottom of `README.md`, and the release workflow lifts that section verbatim.

**It lifts only the section matching the version being tagged.** Everything
shipping in a release has to be in that one section — a separate `### 0.6.13`
heading once meant a whole feature shipped unmentioned, because 0.6.13 never got
a tag of its own.

`README.md` is byte-sensitive: it carries em dashes and middots, and a
byte-level `sed` repair once mangled 64 of them. Splice whole lines with
`head`/`tail` rather than running regex over punctuation in place, and check
afterwards — `grep -c $'\xef\xbf\xbd' README.md` must print 0.

## Running the tests

```powershell
Expand All @@ -68,6 +115,25 @@ document, so the dashboard's own logic is tested rather than eyeballed. Add to
the second one when changing `web/` — it is the only thing standing between a
broken panel and a screenshot nobody took.

## Then check it against the real logs

Green tests mean the fixtures still parse. They do not mean the app reads *this*
install. The CLI is the harness for that:

```powershell
dotnet run --project src\Quantumwake.Cli -c Release
```

It parses every backup — 151 files, ~420 MB, a few seconds — and prints
per-event counts and any unmatched tags. **`! unmatched known tags` should read
0.** A parser change is not finished until it has run against that corpus.

Then check the number it produced against something it did not use. When
commodity buying started parsing, the give-away was that price ÷ SCU matched
`shopPricePerCentiSCU`, a field the parser never reads — which is what caught
the centi-SCU unit and would have caught a hundredfold error that still looked
like a plausible integer.

## Seeing it actually run

The browser automation tools cannot reach this machine's localhost, and there is
Expand All @@ -88,12 +154,26 @@ Two traps. The server serves `bin\Release\net10.0\web`, **not** the repo's
is locked. And stub `window.EventSource` in any throwaway page you drive, or it
never settles.

Two more traps once a page has to be *driven* rather than merely loaded. Chrome's
virtual clock stalls while the live stream holds a request open, so `setTimeout`
never fires — hang the harness off a `MutationObserver` instead. And a table that
re-renders when its data lands will discard a panel you opened a moment earlier,
so reopen until it sticks rather than clicking once.

Rendering earns its keep. It has caught a button clipped off-screen by
`margin-left:auto` inside a table wider than its panel, a control left invisible
because it only appeared on hover, and a page that rendered completely blank
because a local named `history` shadowed `window.history` for a whole function.
None of those show up in a diff.

### Driving it against real data without touching Nicolas's

The most useful screenshots come from the real install, and the real install is
his: the app is usually running on 31337 against
`%LOCALAPPDATA%\Quantumwake`, and anything written there is his data, not a
fixture. So copy it and point a second server at the copy:
fixture. Do not stop it to get a build through either — when the Overlay DLLs
are locked, build the individual projects rather than the solution. So copy the
data and point a second server at the copy:

```powershell
Copy-Item "$env:LOCALAPPDATA\Quantumwake\*" "$env:TEMP\claude\qw-data" -Recurse
Expand All @@ -119,3 +199,9 @@ click path gets tested without writing anything anywhere.
- The app says what it cannot support: inferred locations carry a confidence,
estimates are labelled, and a missing signal gets an explanation rather than a
bare zero. Keep that up in anything new.
- A number that is a floor is called a floor. The Crew page leads with the fact
that it cannot see anyone who never disconnected, because the alternative is a
count that looks complete and is not.
- A negative result is worth writing down. Freight looked like six thousand
lines of cargo tracking and turned out to be loading-platform noise; that is
recorded in `docs/untapped-signals.md` so nobody spends the day again.
6 changes: 3 additions & 3 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
<Copyright>Copyright © nekron</Copyright>
<Description>A pilot's logbook for Star Citizen: second-screen dashboard, in-game overlay, and flight-log analysis for Star Citizen, driven by Game.log.</Description>

<Version>0.6.17</Version>
<AssemblyVersion>0.6.17.0</AssemblyVersion>
<FileVersion>0.6.17.0</FileVersion>
<Version>0.7.17</Version>
<AssemblyVersion>0.7.17.0</AssemblyVersion>
<FileVersion>0.7.17.0</FileVersion>

<RepositoryUrl>https://github.com/peans99/QuantumWake</RepositoryUrl>
<PackageProjectUrl>https://github.com/peans99/QuantumWake</PackageProjectUrl>
Expand Down
Loading
Loading