I1401 — The identity of a projected record is what the record carries, not what its title says
Make the adapter find a remote record by an identity the record itself carries, so that a person may rename an issue on GitHub without the projection losing it or creating a second one, and make reconciliation provable without a network.
DONE wave 0 · p0 · implementation profile · runs alone
Objective
Make the adapter find a remote record by an identity the record itself carries, so that a person may rename an issue on GitHub without the projection losing it or creating a second one, and make reconciliation provable without a network.
Why
Matching on a title is the one mistake a projection may not make. `remote_issue_number()` matched an `I0001 — ` prefix in the remote title, and every other question about a remote record was answered by the same prefix scan. Rename an issue on GitHub and the adapter reports it missing; run --apply and it creates a duplicate for a canonical record that already exists. The remedy must not be to write the GitHub number into the canonical file, because the adapter's own contract is that nothing here ever writes a GitHub value back into a canonical record.
Current state
The adapter resolved five separate questions by scanning the remote title for a canonical prefix, and recovered the number of a freshly created issue by searching GitHub for that title again. The generated region carried the hash of the record it came from and nothing that said which record that was.
Desired state
The generated region carries `<!-- majordomus:record <id> -->` beside its hash, so identity travels with the record and a splice rewrites it. Resolution is by that marker; a title matches once, for an issue projected before the marker existed, and that adoption is reported as its own state rather than passing as a projection that is current. A created issue takes its number from the creation itself. The remote can be a file, so which record is which is provable offline.
Scope
- scripts/github-sync
- test/cases/45_github_projection.sh
Out of scope
- Writing a GitHub number into a canonical record
- Any change to what the projection renders
Dependencies
None. This issue is a root of the graph.
What waits on this
- I1402DONE A finding says which of six states it found, and the state that could hide a person's edit is no longer one of them
- I1403READY Backfill the projection once, deliberately, and record what it created
- I1405DONE A pull request names the issue it realises, and the edge is derived rather than remembered
Acceptance criteria
- A record is resolved by the identity it carries, and a renamed title neither loses it nor duplicates it
- An issue carrying no identity marker is adopted by its title once, reported as an adoption, and given a marker by --apply
- A title that merely looks canonical never captures a record that carries a different identity
- A created issue takes its number from the creation, with no title search anywhere in the adapter
- Reconciliation is provable against a fixture remote with no network and no token, and a fixture is refused for --apply
Validation
- bash test/run.sh 45_github_projection
- scripts/github-sync --plan
- scripts/github-sync --check
Evidence required
- identity_stable
- offline_provable
Evidence
| covers | type | command | result | at commit |
|---|---|---|---|---|
| identity_stable | test | bash test/run.sh 45_github_projection | a record under a fully rewritten remote title is resolved by its marker and reported as body drift, not as missing; an issue with no marker is adopted by title once and reported as adopt; a canonical-looking title does not capture a record carrying a different identity | 209a82c |
| offline_provable | test | MJ_GH_FIXTURE_ISSUES=<tsv> MJ_GH_FIXTURE_MILESTONES=<tsv> scripts/github-sync --check | reconciliation runs against a fixture remote with no network and no token; --apply refuses a fixture with exit 15 | 209a82c |
Risk
The 19 issues projected before the marker existed must be adopted, never re-created; the adoption path is the acceptance criterion that guards it.
Timeline
- started
- 2026-09-09T17:10:06Z
- verified
- 2026-09-09T17:10:21Z
- completed
- 2026-09-09T17:10:28Z
Those three fields, the evidence above and the state of the dependencies are all the status is made of. There is no status field to disagree with them.
Canonical record: .ai/repo/project/issues/I1401.yaml. Read it back with majordomus plan show I1401.