graview-port-app
Port an existing application onto Graview — deciding what is a node, what is a field and what is an edge — and proving the port with a parity test rather than an assertion.
Installed into a project by graview skills install ., and read by whichever assistant is working beside you.
The skill
Port an existing application
The hard part of a port is not the code. It is deciding what your existing schema was really saying, because a relational schema hides three different things inside a foreign key: a real relationship, an implementation detail, and a thing that should have been a node all along.
The decisions, in order
- What is a NODE? The test: does anything point at it, and does it have a life of its own? A
statusstring is a field. Arationale— a reason someone recorded, that outlives the person who recorded it and that other things refer to — is a node, and turning it into one is usually the moment a port starts paying for itself.
- What is an EDGE? A relationship a person would name out loud.
assigned-tois an edge.created_atis a field. A join table with columns on it is a node, not an edge, and pretending otherwise is the mistake that costs most later.
- What is a MUTATION? Every change, named as an act rather than as a write. Not
updateDutybut "Reassign run". The title is the label a person reads in the strip AND the instruction an agent reads in its tool schema, so an opaque one costs twice. If you find yourself writingpatch, you have skipped this step.
- What is an INVARIANT? Everything your current code validates, plus everything it was supposed to. Give each one repairs — see
graview-invariant. Rules that name their repairs are where the interface stops needing you to design it.
- What is a LENS? Your primary screen, described without your nouns. A calendar is intervals in columns. A checklist grid is a bipartite mapping. A formation is positions with domain-given coordinates. If one of the three shipped lenses fits, bind roles to your fields and write no picture at all.
Do this
- Build the domain tier first, with no UI. Get
graview checkclean before anything renders. - Load your real data through a
snapshot, not a fixture you invented. A port that works on twelve made-up nodes and falls over on the real graph has proved nothing. - Register default views, look at it, and only then write custom ones.
- Port the rules LAST, and port them as tests first.
Worked example
- The household product (now in its own repository) is a port. Its parity fixture was generated by running the ORIGINAL app's code over the same data, and its test asserts the framework's invariants reproduce every violation — 90 across 9 provocations. That fixture-and-test pair is the reason anyone should believe a port, and the shape to copy.
Then find out whether it worked
pnpm build && npx graview check ./dist/domain/app.jsAnd write the parity test. This is the one thing that makes a port trustworthy, and it is worth more than every other check here combined: run the OLD system's validation and the new invariants over the same graphs, and assert they agree.
// Generated by running the old code over N provocations, then committed.
import expected from "./fixtures/legacy-violations.json";
it("agrees with the system it replaces, violation for violation", () => {
for (const provocation of provocations) {
const store = createStore({ snapshot: provocation.graph });
const mine = store.violations().map((v) => v.message).sort();
expect(mine).toEqual(expected[provocation.name]);
}
});The framework's own the household example port does this across 90 violations and nine provocations, against a fixture generated by running the original code. If you cannot generate that fixture, say so — and say what you are relying on instead, because "I read both and they look the same" is a different claim.
What the check cannot see
- Whether you modelled the domain or transcribed the database. The symptom is edges named after columns.
- Whether behaviour the old system had is gone. Only the parity test knows.
- Whether the port is worth finishing. A port that has not made anything clearer by the third kind is telling you something.