merge: drop the local copy after a successful push

# Conflicts:
#	AGENTS.md
#	agents/tea-runner.md
This commit is contained in:
naudachu
2026-08-10 16:40:21 +05:00
14 changed files with 1410 additions and 118 deletions
+37 -13
View File
@@ -113,9 +113,14 @@ developer's own store out of the blast radius.
## Local issue store
`tmp/issues/` (gitignored) is **the store, not a cache of Gitea**. One flat
markdown file per issue, named by its slug, with one metadata field per line so
plain grep works without a parser.
`tmp/issues/` (gitignored) holds **two kinds of file, and only one of them is a
store.** An `origin: local` issue lives here and nowhere else — this file *is*
the issue, and losing it loses the work. Anything with `origin: gitea` is a
**cache**: the tracker has it, this copy is a working copy, and it is deleted
the moment a push confirms the tracker is up to date.
One flat markdown file per issue, named by its slug, with one metadata field per
line so plain grep works without a parser.
- **The path is `<repo root>/tmp/issues`, resolved from `issue.py`'s own
location, not from cwd.** `issue.store_root()` walks up from `__file__` to the
@@ -127,13 +132,30 @@ plain grep works without a parser.
and they say so on stderr.
- Identity is the slug (`wire-sqlc-appclick.md`), never a tracker number.
Numbers live in the `gitea:` field.
- `origin: local` is a durable state. An issue that never leaves this machine is
complete and valid, not a draft.
- Pushing is additive: the file is never deleted, it gains `gitea:` / `url:` /
`synced:`.
- Pulling overwrites the body — a fetch, not a merge.
- No drift tracking. `synced:` tells you how old your copy is; re-pull when it
matters.
- `origin: local` is a complete state, not a draft: an issue that never leaves
this machine is valid and finished. It is not a *durable* state, though —
pushing ends it, and the local file goes with it.
- **A successful push deletes the local file** (`<id>.md` and
`<id>.comments.md`), and prints the number and URL the issue now lives at.
`--update` too: one rule, no exception. What is in the store is what has not
left. Get it back with `pull.py <n>`.
- Deletion happens only after a confirmed tracker response and only after
`.remote.json` has been written. Network down, non-2xx, an answer that does
not carry the right number: the file stays and the run stops. A never-pushed
`origin: local` issue is never touched by any of this.
- The slug survives the round trip because it goes up in the body as
`<!-- tea:id … -->` (`map.with_id_marker`) and is indexed by number in
`tmp/issues/.remote.json`. A rename in the web UI, a lost `.remote.json`, a
fresh clone, another machine — the file comes back under the same name and
every `depends:` that points at it still resolves.
- `.remote.json` is therefore no longer "an index over the files": it is the
local number → slug ledger, its entries outlive the files they name, and
nothing prunes them. It is still recoverable — from the markers in Gitea, not
from the files.
- Pulling overwrites the body — a fetch, not a merge. It is also how a pushed
issue comes back at all.
- No drift tracking, and now nothing to track: there is no second copy to
diverge from. `synced:` tells you how old your working copy is.
## Local wiki cache
@@ -153,9 +175,11 @@ organized. Same stance as the issue store, resolved the same way from
- A title is a decision, not a derivation. A re-import replaces bodies and
keeps titles, so editing a heading cannot silently rename a published page.
`--retitle` opts in, and the rename reaches the wiki on the next push.
- A page with no `sub_url` has never been published — a durable state, exactly
as `origin: local` is for an issue.
- A page with no `sub_url` has never been published — a complete state, the way
`origin: local` is for an issue. **The parallel stops at the push**: a pushed
page stays on disk, a pushed issue does not.
- Change detection is one hash (`pushed`). Pulling overwrites; pushing is
additive and never deletes.
additive and never deletes — the one place the two domains deliberately
disagree, because a page tree is worked on locally and an issue is not.
- The `tea` CLI has no wiki subcommand. `tea api` is the only route, through
`_gitea.py`.