Skip to content

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

Part of work-graph-github — The projection to GitHub is gated, identified and traversable, and a merged pull request leads back to the outcome it served.

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

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

coverstypecommandresultat commit
identity_stabletestbash test/run.sh 45_github_projectiona 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 identity209a82c
offline_provabletestMJ_GH_FIXTURE_ISSUES=<tsv> MJ_GH_FIXTURE_MILESTONES=<tsv> scripts/github-sync --checkreconciliation runs against a fixture remote with no network and no token; --apply refuses a fixture with exit 15209a82c

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.