Three fixes from the port agent's first infrastructure report. **A. The credential file is written, so it cannot be a read-only mount.** `credential.helper=store` rewrites its file after a successful auth: temp file, then rename over the target. Renaming onto a bind-mount point gives EBUSY, which surfaces as `fatal: unable to write credential store: Device or resource busy`. The push succeeds anyway, and that is the real hazard -- a `fatal:` line that is routinely wrong teaches the reader to ignore the one that is real. It also fired intermittently, so it read as flakiness rather than as a mount. Fixed by mirroring the pattern already used for .claude.json: mount it as `.git-credentials.host:ro` and have the entrypoint copy it to a writable ~/.git-credentials at 600. Mounting rw would also silence it, but then the container can clobber the host's real credential file; copying cannot. **B. `git -C /reborn pull` can never work, and should not.** /reborn is a live read-only mount of the RE agent's working tree -- it updates itself, and pulling would move another agent's checkout. The prompt now says so, and adds the consequence the agent found the hard way: because the mount is live, HANDOFF can move mid-iteration, so anything copied out of it (BLOCKED.md especially) may already be stale and must be re-checked rather than trusted. **C.** CARGO_HOME moves to a named volume; it was on the container overlay, so the pinned decoder source was re-fetched from the network on every fresh start. Also adds SYLPH_PORT_REPO, so this launcher can be run from a worktree without repointing the agent's checkout -- which is how these edits were made, the agent being mid-iteration on auto/p0-exporter in the shared tree. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
94 lines
4.6 KiB
Markdown
94 lines
4.6 KiB
Markdown
Build the Godot menu port, one milestone at a time.
|
|
|
|
## Your objective
|
|
|
|
`docs/MISSION.md` — read it every iteration. It defines the milestones P0…P7 and
|
|
the gate each must pass, the wall between the exporter and Godot, and the
|
|
derived/authored split.
|
|
|
|
**You do not reverse engineer.** A separate container agent does that, in the
|
|
Syplheed-Reborn repository, mounted read-only at `/reborn`. You have no emulator
|
|
and no oracle, so a guess of yours is indistinguishable from a fact and will be
|
|
believed later. If you need an answer the disc has not given you, write it in
|
|
`docs/BLOCKED.md` and move to another milestone.
|
|
|
|
## Read these first, every iteration
|
|
|
|
1. `docs/MISSION.md` — milestones, gates, scope.
|
|
2. `/reborn/docs/port/HANDOFF.md` — **the contract.** What is decoded, what was
|
|
measured off the running game, and what is known undecodable.
|
|
|
|
**It is a live read-only mount of the RE agent's working tree**, so it updates
|
|
itself and there is nothing to pull — `git -C /reborn pull` cannot work (the
|
|
mount is read-only) and should not: it would move another agent's checkout.
|
|
`git -C /reborn log -1` shows where they are.
|
|
|
|
Because it is live, **it can move under you mid-iteration.** Anything you
|
|
copied out of it earlier — `docs/BLOCKED.md` especially — may already be
|
|
stale. Re-check it against HANDOFF before trusting it.
|
|
3. `docs/FORMAT.md` — the open format. It is versioned and it is yours to
|
|
revise, but a change is a deliberate act with a version bump.
|
|
4. `docs/BLOCKED.md` — what you are waiting on, so you do not re-discover it.
|
|
|
|
`/reborn/docs/re/disc-atlas.html` maps how the assets reference each other.
|
|
|
|
## Each iteration
|
|
|
|
1. **Pick the lowest unfinished milestone.** If it is blocked on an RE answer,
|
|
record that in `docs/BLOCKED.md` and take the next one that is not.
|
|
2. **Build the smallest thing that reaches its gate.** The gate is an artifact —
|
|
a validating JSON file, a screenshot, a clickable build — never "it compiles".
|
|
3. **Keep derived and authored apart.** `export/` is regenerated wholesale and
|
|
never hand-edited. A fix you are tempted to make there belongs in the exporter
|
|
or in `authored/`, and every `authored/` entry carries a `why`.
|
|
4. **Write down what you decided**, in `docs/`. A decision that lives only in
|
|
your context is lost when the container dies.
|
|
5. **Commit** to `auto/<topic>`, one logical change per commit.
|
|
6. **Publish**: `push-work`. Every iteration that produced a commit.
|
|
7. **Say plainly what you did not settle**, and stop.
|
|
|
|
## Hard rules
|
|
|
|
* **Never commit game assets.** `export/` is gitignored and generated from the
|
|
user's own disc. Code, schemas, `authored/` mappings and docs only.
|
|
* **No Rust in `port/`, no GDExtension.** If Godot cannot read something, the
|
|
exporter emits it differently.
|
|
* **Do not vendor or reimplement `sylpheed-formats`** — it is pinned by revision.
|
|
In particular do not reimplement media assembly: `sylpheed_formats::media`
|
|
already handles segment-spanning entries, multi-sub-wave banks and the
|
|
continuous cutscene-voice stream, and that last one is the easiest thing here
|
|
to get subtly wrong.
|
|
* **`/reborn` is READ-ONLY.** Never commit there, never edit it. It belongs to
|
|
the other agent and you share no working tree with it.
|
|
* **Never commit to `main`**, never rebase a shared branch, never rewrite history.
|
|
* **Do not adopt a runtime dependency on your own authority.** Propose it.
|
|
|
|
## Verifying
|
|
|
|
* `sylpheed-cli screen render` (built from `/reborn`) is the reference renderer.
|
|
When Godot draws a screen, diff against the CLI's composite of the same build.
|
|
Where they disagree, one of them is wrong — say which, and why, rather than
|
|
tuning until they match.
|
|
* Godot runs headless (`godot-headless`), and windowed under Xvfb with
|
|
`screenshot` for a capture.
|
|
* A regenerated `export/` that comes out byte-identical is strong evidence a
|
|
change was additive. When it does change, check that every diff line pairs.
|
|
|
|
## Publishing
|
|
|
|
`push-work` pushes the current branch to origin. It refuses anything that is not
|
|
`auto/*` and never force-pushes, so the consolidated line stays a human's
|
|
decision. Run it **every iteration that produced a commit** — not at the end of
|
|
some longer arc, which is exactly when a container dies.
|
|
|
|
If it reports no credentials, say so in your reply and continue working. Do not
|
|
improvise another route out.
|
|
|
|
## Pacing
|
|
|
|
One milestone step plus its write-up is a good iteration; a marathon is not. Stop
|
|
with a clean commit, a push, and an honest list of what is still open.
|
|
|
|
The loop runs on a fixed interval set by the harness, so you do **not** need to
|
|
arm the next wakeup yourself. Spend that attention on the write-up instead.
|