2f32186d22e4db7f6e6dc80577ac8f25168cc204
3 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
2f32186d22 |
Fix five defects found by running Motion rather than reading it
The markdown parser was in the eager entry chunk. `manualChunks` in its object form does not leave an unlisted vendor package to Vite's async splitting, so react-markdown was hoisted into the entry even though its only importers are lazy routes — 327.70 kB gzip against a 314 kB baseline, on the one download every route pays for. Naming it as its own chunk puts it back behind the Motion pages and takes the entry to 282.21 kB, below where it was before Motion existed. The starter library could never be improved. Seeding was insert-only, so a deployment seeded in August was frozen on August's wording for ever with no upgrade path short of editing production rows by hand — for a feature whose entire premise is that the library gets better. A second run now refreshes a starter row, but only while it is still ours: `is_system`, `usage_count = 0` and no owner. That is the same condition §7a already enforces on the API, so a template an engagement was cut from is left alone and reported by name rather than silently overwritten. The refresh was not idempotent, and the seed lied about it. `jsonb` does not preserve key order — Postgres sorts keys by length then bytewise — so comparing `JSON.stringify(stored)` against `JSON.stringify(authored)` marked every template as changed on every run, and the seed rewrote nine rows each time while reporting itself clean. Comparison is now canonical. Found by running the seed three times and reading the counts. `motion-overflow-check.mjs` measured less than it claimed. It seeded `pig.sidebar` and `pig.piggy.dock`, neither of which anything reads (the keys are `pig.sidebarOpen` and `pig.piggyDockOpen`), so the layout it pinned was whatever the last run left. Its dark pass set `colorScheme` only, and the appearance preference is stored server-side and adopted after hydration, so the dark pass measured the light palette a beat after first paint. It now rewrites the profile response as `screenshots.mjs` does, asserts the rendered `data-theme`, and fails a page that renders almost no text — a page that throws inside its own body otherwise measures zero overflow and passes. The stage rail rendered "1 templates", in the visible label and in every aria-label. Singular and plural are now both passed. Also normalised `artifact` to `artefact` in the seeded prose, which had drifted American in the playbook. The `artifacts` field key is untouched: FieldsView reads it, and already labels it in British. |
||
|
|
15c72ade1c |
Fix twenty findings from the Motion review
Each was raised by a reviewer and then survived an independent attempt to refute it. The four that mattered most: - A third of the starter library was invisible. Three templates authored `fields` shapes no renderer read — decisions, blockingSet, checks, steps and the rest — so about forty records rendered as no DOM at all, in the library and again on the engagement that instantiated them. Nothing failed: a renderer returns null for a key set it does not recognise, and a header-plus-body page looks like a template written that way. FieldsView now reads every key the seeds carry. - "Add a framework" opened a picker that could never match, because the dialog was seeded with both the forced kind and the deal's stage, and qualification serves only the qualification stage. The stage is now dropped when MOTION_KIND_STAGES says the pair is incoherent. - Piggy reported the promotion count as an exact figure capped at 8, against a tile showing the true count beside it. It is now counted in SQL, and all three motion tools carry a ResultScope whose denominator is shared lineages — never rows, never private drafts. - No Motion test went through createApp, so the whole feature could be unmounted with a green suite. That is the AGENTS.md §5 trap that already cost this project read-guards.ts and learn.ts. Also: both sides of the instantiate/edit race now lock, so a template cannot be rewritten under an artefact that has copied it; concurrent engagement opens queue on the deal row and get the 409 the handler already promised rather than a 500; latestScore uses DISTINCT ON instead of losing engagements past a 200-row cap; the migration adds the scored_by_user_id foreign key the schema declares; and the demo clear refunds usage_count for engagements it reaches by cascade, which otherwise left starter templates permanently un-editable. Verified on a fresh database: 16 migrations apply and re-apply as a no-op, both seeds idempotent, usage_count back to zero after --clear. 564 unit tests pass. Every Motion route measures zero horizontal overflow at 393 and 1440 in both themes, and all twelve seeded field trees are asserted onto the screen by scripts/motion-fields-check.mjs. One thing left open deliberately: the shipped qualification scorecard's five bands and MOTION_BANDS' four are calibrated differently. The framework's table is now titled as its own guidance rather than the product's verdict, which removes the contradiction on screen. Making the framework's calibration authoritative over the persisted band column is a product decision nobody has made. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
516685526c |
Add Motion: the go-to-market operating system on top of the ledger
The ledger answers which contracted capacity is sold, to whom, at what margin. It says nothing about the motion — the repeatable practice that turns a customer conversation into a scoped deployment, and turns that deployment into something the next one reuses. Motion is deliberately not a parallel entity tree. DEMAND_STAGES already is the motion, so Motion binds reusable artefacts to the stages of a demand deal that already exists: an engagement hangs off one deal, cascade deleted, one per deal by unique constraint. Nine closed kinds, each declaring which stages it serves, and a starter library of twelve templates covering all eight open stages. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |