@polymorphism-tech/morph-spec 8.37.0 → 8.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/CLAUDE.md +19 -6
  2. package/README.md +2 -2
  3. package/bin/morph-spec.js +16 -7
  4. package/claude-plugin.json +1 -1
  5. package/docs/CHEATSHEET.md +1 -1
  6. package/docs/QUICKSTART.md +1 -1
  7. package/framework/CLAUDE.md +3 -3
  8. package/framework/MORPH.md +25 -22
  9. package/framework/agents.json +76 -27
  10. package/framework/docs/CLI.md +55 -18
  11. package/framework/evals/rubrics/code-quality.md +5 -0
  12. package/framework/evals/rubrics/condensed.md +6 -2
  13. package/framework/evals/rubrics/contracts.md +20 -0
  14. package/framework/evals/rubrics/test-coverage.md +17 -6
  15. package/framework/hooks/README.md +9 -3
  16. package/framework/hooks/claude-code/core/graph-refresh-kick.js +52 -0
  17. package/framework/hooks/claude-code/core/telemetry-log.js +172 -87
  18. package/framework/hooks/claude-code/core/validate-completion.js +16 -90
  19. package/framework/hooks/claude-code/core/worktree-context.js +10 -0
  20. package/framework/hooks/shared/command-tokens.js +96 -0
  21. package/framework/hooks/shared/git-exclude.js +44 -0
  22. package/framework/hooks/shared/git-paths.js +52 -0
  23. package/framework/hooks/shared/graph-freshness.js +380 -0
  24. package/framework/hooks/shared/graph-refresh.js +416 -0
  25. package/framework/hooks/shared/morph-cli.js +17 -5
  26. package/framework/hooks/shared/redact-secrets.js +55 -0
  27. package/framework/hooks/shared/telemetry-logger.js +25 -2
  28. package/framework/hooks/shared/transcript-usage.js +80 -0
  29. package/framework/rubrics/backend.json +2 -2
  30. package/framework/rubrics/default.json +2 -2
  31. package/framework/rubrics/frontend.json +2 -2
  32. package/framework/rules/csharp-standards.md +1 -0
  33. package/framework/rules/morph-workflow.md +1 -0
  34. package/framework/rules/nextjs-standards.md +1 -0
  35. package/framework/schemas/config.schema.json +41 -1
  36. package/framework/schemas/feature.schema.json +5 -1
  37. package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
  38. package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
  39. package/framework/skills/core/morph-apply/SKILL.md +36 -11
  40. package/framework/skills/core/morph-brainstorming/SKILL.md +16 -7
  41. package/framework/skills/core/morph-eval/SKILL.md +1 -1
  42. package/framework/skills/core/morph-hotfix/SKILL.md +1 -1
  43. package/framework/skills/core/morph-implement/SKILL.md +39 -10
  44. package/framework/skills/core/morph-media/SKILL.md +1 -1
  45. package/framework/skills/core/morph-plan/SKILL.md +72 -15
  46. package/framework/skills/core/morph-proposal/SKILL.md +1 -1
  47. package/framework/skills/core/morph-review/SKILL.md +51 -13
  48. package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
  49. package/framework/skills/core/morph-standards/SKILL.md +1 -1
  50. package/framework/skills/core/morph-uiux/SKILL.md +34 -9
  51. package/framework/standards/STANDARDS.json +187 -12
  52. package/framework/standards/ai-agents/rag-custom-pgvector.md +7 -3
  53. package/framework/standards/ai-agents/testing-ai.md +2 -1
  54. package/framework/standards/architecture/code-comments.md +64 -0
  55. package/framework/standards/backend/dotnet/testing.md +22 -0
  56. package/framework/standards/frontend/admin-app/data-table.md +562 -0
  57. package/framework/standards/frontend/admin-app/feedback.md +236 -0
  58. package/framework/standards/frontend/admin-app/forms.md +232 -0
  59. package/framework/standards/frontend/admin-app/page-structure.md +203 -0
  60. package/framework/standards/frontend/nextjs/components.md +37 -58
  61. package/framework/standards/frontend/nextjs/data-fetching.md +1 -0
  62. package/framework/standards/frontend/nextjs/forms.md +31 -30
  63. package/framework/standards/frontend/nextjs/state-management.md +2 -1
  64. package/framework/standards/frontend/nextjs/testing.md +18 -0
  65. package/framework/templates/context/design-system.md +3 -3
  66. package/framework/templates/docs/proposal.md +11 -0
  67. package/framework/templates/docs/spec.md +15 -0
  68. package/framework/templates/docs/ui-mockups.md +115 -98
  69. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaPlan.cs +12 -6
  70. package/framework/templates/feature/decisions.md +124 -122
  71. package/package.json +1 -1
  72. package/src/commands/graph/affected.js +4 -3
  73. package/src/commands/graph/build.js +109 -18
  74. package/src/commands/graph/explain.js +8 -5
  75. package/src/commands/graph/status.js +14 -8
  76. package/src/commands/observability/cost.js +148 -18
  77. package/src/commands/project/doctor.js +82 -10
  78. package/src/commands/project/update.js +25 -0
  79. package/src/commands/project/worktree.js +73 -90
  80. package/src/commands/state/advance.js +18 -0
  81. package/src/commands/state/approve.js +15 -0
  82. package/src/commands/state/archive.js +62 -9
  83. package/src/commands/state/finish.js +62 -14
  84. package/src/commands/state/gate-check.js +8 -1
  85. package/src/commands/state/gate-decision.js +8 -4
  86. package/src/commands/state/report-check.js +90 -9
  87. package/src/commands/state/usecase.js +66 -0
  88. package/src/commands/tasks/dag.js +17 -2
  89. package/src/commands/validation/validate-feature.js +6 -1
  90. package/src/commands/validation/verify.js +20 -1
  91. package/src/dashboard/scanner/agents-scanner.js +5 -1
  92. package/src/dashboard/scanner/hooks-scanner.js +8 -1
  93. package/src/dashboard/scanner/standards-scanner.js +2 -1
  94. package/src/lib/ai/comment-stripper.js +101 -4
  95. package/src/lib/evaluator-report.js +25 -0
  96. package/src/lib/generators/handoff-generator.js +4 -18
  97. package/src/lib/git/default-branch.js +52 -0
  98. package/src/lib/git/tree-fingerprint.js +58 -0
  99. package/src/lib/git/tree-state.js +167 -0
  100. package/src/lib/graph/god-nodes.js +12 -3
  101. package/src/lib/graph/graph-health.js +48 -2
  102. package/src/lib/graph/graph-loader.js +99 -25
  103. package/src/lib/graph/graphifyignore.js +145 -28
  104. package/src/lib/graph/sanitize.js +117 -11
  105. package/src/lib/risk-detector.js +90 -0
  106. package/src/lib/specs/acervo-format.js +70 -0
  107. package/src/lib/specs/acervo-lifecycle.js +264 -0
  108. package/src/lib/specs/adr-index.js +169 -0
  109. package/src/lib/specs/revocations.js +156 -0
  110. package/src/lib/specs/screen-checklist.js +357 -0
  111. package/src/lib/specs/usecase-check.js +20 -16
  112. package/src/lib/specs/usecase-promoter.js +103 -38
  113. package/src/lib/specs/usecase-registry.js +7 -7
  114. package/src/lib/tasks/tasks-json-parser.js +2 -3
  115. package/src/lib/telemetry/metrics.js +386 -0
  116. package/src/lib/telemetry/telemetry-reader.js +161 -51
  117. package/src/lib/telemetry/verify-event.js +79 -0
  118. package/src/lib/validators/code-budget/code-budget-validator.js +172 -0
  119. package/src/lib/validators/code-budget/comment-scanner.js +75 -0
  120. package/src/lib/validators/code-budget/index.js +9 -0
  121. package/src/lib/validators/reuse/reuse-validator.js +4 -2
  122. package/src/lib/validators/reuse/symbol-scanner.js +27 -22
  123. package/src/lib/validators/validation-runner.js +21 -5
  124. package/src/lib/validators/verify-runner.js +11 -0
  125. package/src/lib/worktree/finish-backup.js +739 -0
  126. package/src/lib/worktree/ignored-triage.js +15 -8
  127. package/src/lib/worktree/worktree-audit.js +5 -0
  128. package/src/scripts/setup-infra.js +29 -18
  129. package/src/utils/agents-installer.js +281 -12
  130. package/src/utils/hooks-installer.js +75 -15
@@ -5,7 +5,7 @@
5
5
  > **Keywords:** component, shadcn, reusable, shared, ui, three-tier
6
6
  > **Load When:** creating or editing React components
7
7
 
8
- **Verified against:** Next.js 15 + shadcn/ui CLI + TanStack Table 8. Last-verified: 2026-05-20.
8
+ **Verified against:** Next.js 16 + shadcn 4 CLI (the code blocks typecheck under `tsc --strict`). Last-verified: 2026-09-24.
9
9
 
10
10
  ---
11
11
 
@@ -33,83 +33,62 @@ Tier 3: features/*/components/ ← feature-scoped (knows about users, billing, e
33
33
 
34
34
  ```bash
35
35
  # Add shadcn components via CLI — never write them manually
36
- npx shadcn@latest add button card dialog form input table
36
+ npx shadcn@latest add button card dialog field input table
37
37
  ```
38
38
 
39
39
  If you need to change a shadcn component's behavior, wrap it — do not edit the source file.
40
40
 
41
41
  ## Tier 2 — Shared Composed Components
42
42
 
43
+ Composes shadcn primitives and knows nothing about the domain.
44
+
43
45
  ```tsx
44
- // components/data-table.tsx — composes shadcn Table + TanStack Table
45
- 'use client';
46
-
47
- import {
48
- Table, TableBody, TableCell, TableHead, TableHeader, TableRow
49
- } from '@/components/ui/table';
50
- import {
51
- type ColumnDef, flexRender, getCoreRowModel, useReactTable
52
- } from '@tanstack/react-table';
53
-
54
- interface DataTableProps<TData> {
55
- columns: ColumnDef<TData>[];
56
- data: TData[];
46
+ // components/page-header.tsx
47
+ import type { ReactNode } from 'react';
48
+ import { cn } from '@/lib/utils';
49
+
50
+ interface PageHeaderProps {
51
+ title: string;
52
+ description?: string;
53
+ actions?: ReactNode;
54
+ className?: string;
57
55
  }
58
56
 
59
- export function DataTable<TData>({ columns, data }: DataTableProps<TData>) {
60
- const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel() });
57
+ export function PageHeader({ title, description, actions, className }: PageHeaderProps) {
61
58
  return (
62
- <Table>
63
- <TableHeader>
64
- {table.getHeaderGroups().map((hg) => (
65
- <TableRow key={hg.id}>
66
- {hg.headers.map((h) => (
67
- <TableHead key={h.id}>
68
- {flexRender(h.column.columnDef.header, h.getContext())}
69
- </TableHead>
70
- ))}
71
- </TableRow>
72
- ))}
73
- </TableHeader>
74
- <TableBody>
75
- {table.getRowModel().rows.map((row) => (
76
- <TableRow key={row.id}>
77
- {row.getVisibleCells().map((cell) => (
78
- <TableCell key={cell.id}>
79
- {flexRender(cell.column.columnDef.cell, cell.getContext())}
80
- </TableCell>
81
- ))}
82
- </TableRow>
83
- ))}
84
- </TableBody>
85
- </Table>
59
+ <div className={cn('flex items-start justify-between gap-4', className)}>
60
+ <div>
61
+ <h1 className="text-2xl font-semibold tracking-tight">{title}</h1>
62
+ {description && <p className="text-sm text-muted-foreground">{description}</p>}
63
+ </div>
64
+ {actions && <div className="flex gap-2">{actions}</div>}
65
+ </div>
86
66
  );
87
67
  }
88
68
  ```
89
69
 
70
+ **The shared data table has one home: `admin-app/data-table.md`.** It is the Tier 2 component with the most rules — pagination, sorting and filtering on the server, the three states, selection — so it is specified there, once. Do not write a second `components/data-table.tsx` from this page.
71
+
90
72
  ## Tier 3 — Feature Components
91
73
 
92
74
  ```tsx
93
- // features/users/components/user-list.tsx
94
- 'use client';
95
-
96
- import { DataTable } from '@/components/data-table';
97
- import { useUsers } from '@/features/users/hooks/use-users';
98
- import type { ColumnDef } from '@tanstack/react-table';
99
- import type { User } from '@/features/users/types/user.types';
100
-
101
- const columns: ColumnDef<User>[] = [
102
- { accessorKey: 'name', header: 'Name' },
103
- { accessorKey: 'email', header: 'Email' },
104
- ];
105
-
106
- export function UserList() {
107
- const { data: users = [], isLoading } = useUsers();
108
- if (isLoading) return <div>Loading...</div>;
109
- return <DataTable columns={columns} data={users} />;
75
+ // features/users/components/users-page-header.tsx
76
+ import { PageHeader } from '@/components/page-header';
77
+ import { Button } from '@/components/ui/button';
78
+
79
+ export function UsersPageHeader({ canInvite }: { canInvite: boolean }) {
80
+ return (
81
+ <PageHeader
82
+ title="Users"
83
+ description="People with access to this workspace."
84
+ actions={canInvite ? <Button>Invite user</Button> : null}
85
+ />
86
+ );
110
87
  }
111
88
  ```
112
89
 
90
+ A feature **list** is a Tier 3 component too: the feature owns the columns and the URL ⇄ table mapping, the shared table owns the rendering — `admin-app/data-table.md` → "The Feature Table".
91
+
113
92
  ## Component Props Conventions
114
93
 
115
94
  ```tsx
@@ -18,6 +18,7 @@ Server Components for initial page load. TanStack Query for client mutations and
18
18
  - NEVER use `useEffect(() => { fetch(...) }, [])` — this is the old pattern
19
19
  - ALWAYS validate API responses with Zod before using them
20
20
  - ALWAYS use query key factories for consistent cache invalidation
21
+ - NEVER fetch a whole collection to page, sort or filter it in the browser — a list is paged on the server, with the query in the URL (`admin-app/data-table.md`)
21
22
 
22
23
  ## TanStack Query Setup
23
24
 
@@ -2,20 +2,22 @@
2
2
 
3
3
  > **Scope:** frontend/nextjs/forms
4
4
  > **Layer:** 2 (on keyword)
5
- > **Keywords:** form, react-hook-form, zod, validation, input, submit, zodResolver
5
+ > **Keywords:** form, react-hook-form, zod, validation, input, submit, zodResolver, Controller, Field, FieldError
6
6
  > **Load When:** implementing any form in Next.js
7
7
 
8
- **Verified against:** Next.js 15 + react-hook-form 7 + Zod 4 + @hookform/resolvers 3. Last-verified: 2026-05-20.
8
+ **Verified against:** Next.js 16 + react-hook-form 7 + Zod 4 + @hookform/resolvers 5 + shadcn 4 `Field` (the code blocks typecheck under `tsc --strict`). Last-verified: 2026-09-24.
9
9
 
10
10
  ---
11
11
 
12
- react-hook-form + Zod + shadcn Form components. Schema defines both validation rules and TypeScript types.
12
+ react-hook-form + Zod + shadcn `Field` components, wired through react-hook-form's `Controller`. The schema defines both the validation rules and the TypeScript types.
13
+
14
+ **Admin app / CRUD screen?** This is the base pattern; `admin-app/forms.md` adds what a CRUD form needs on top of it — server validation errors on the field, where the form lives (dialog, sheet, page), validation timing and the unsaved-changes guard.
13
15
 
14
16
  ## Core Rules
15
17
 
16
- - ALWAYS define the Zod schema first — derive the TypeScript type from it with `z.infer<>`
18
+ - ALWAYS define the Zod schema first — derive the TypeScript type from it with `z.infer<>` (or `z.input<>`/`z.output<>` when the schema coerces)
17
19
  - ALWAYS use `zodResolver` to connect schema to react-hook-form
18
- - ALWAYS use shadcn `<Form>`, `<FormField>`, `<FormItem>`, `<FormMessage>` for consistent UI
20
+ - ALWAYS render fields with `Controller` + shadcn `<Field>`, `<FieldLabel>`, `<FieldError>` for consistent UI and accessible errors
19
21
  - NEVER use `useState` for form field values — react-hook-form handles this
20
22
  - ALWAYS use `useMutation` from TanStack Query for form submission
21
23
 
@@ -38,11 +40,9 @@ export type CreateUserInput = z.infer<typeof createUserSchema>;
38
40
  // features/users/components/create-user-form.tsx
39
41
  'use client';
40
42
 
41
- import { useForm } from 'react-hook-form';
43
+ import { Controller, useForm } from 'react-hook-form';
42
44
  import { zodResolver } from '@hookform/resolvers/zod';
43
- import {
44
- Form, FormControl, FormField, FormItem, FormLabel, FormMessage
45
- } from '@/components/ui/form';
45
+ import { Field, FieldError, FieldGroup, FieldLabel } from '@/components/ui/field';
46
46
  import { Input } from '@/components/ui/input';
47
47
  import { Button } from '@/components/ui/button';
48
48
  import { useCreateUser } from '@/features/users/hooks/use-create-user';
@@ -64,28 +64,28 @@ export function CreateUserForm({ onSuccess }: { onSuccess?: () => void }) {
64
64
  }
65
65
 
66
66
  return (
67
- <Form {...form}>
68
- <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
69
- <FormField
70
- control={form.control}
67
+ <form onSubmit={form.handleSubmit(onSubmit)}>
68
+ <FieldGroup>
69
+ <Controller
71
70
  name="name"
72
- render={({ field }) => (
73
- <FormItem>
74
- <FormLabel>Name</FormLabel>
75
- <FormControl><Input placeholder="John Doe" {...field} /></FormControl>
76
- <FormMessage />
77
- </FormItem>
71
+ control={form.control}
72
+ render={({ field, fieldState }) => (
73
+ <Field data-invalid={fieldState.invalid}>
74
+ <FieldLabel htmlFor={field.name}>Name</FieldLabel>
75
+ <Input {...field} id={field.name} aria-invalid={fieldState.invalid} placeholder="John Doe" />
76
+ {fieldState.invalid && <FieldError errors={[fieldState.error]} />}
77
+ </Field>
78
78
  )}
79
79
  />
80
- <FormField
81
- control={form.control}
80
+ <Controller
82
81
  name="email"
83
- render={({ field }) => (
84
- <FormItem>
85
- <FormLabel>Email</FormLabel>
86
- <FormControl><Input type="email" {...field} /></FormControl>
87
- <FormMessage />
88
- </FormItem>
82
+ control={form.control}
83
+ render={({ field, fieldState }) => (
84
+ <Field data-invalid={fieldState.invalid}>
85
+ <FieldLabel htmlFor={field.name}>Email</FieldLabel>
86
+ <Input {...field} id={field.name} type="email" aria-invalid={fieldState.invalid} />
87
+ {fieldState.invalid && <FieldError errors={[fieldState.error]} />}
88
+ </Field>
89
89
  )}
90
90
  />
91
91
  {form.formState.errors.root && (
@@ -94,8 +94,8 @@ export function CreateUserForm({ onSuccess }: { onSuccess?: () => void }) {
94
94
  <Button type="submit" disabled={isPending}>
95
95
  {isPending ? 'Creating...' : 'Create User'}
96
96
  </Button>
97
- </form>
98
- </Form>
97
+ </FieldGroup>
98
+ </form>
99
99
  );
100
100
  }
101
101
  ```
@@ -123,11 +123,12 @@ export const updateUserSchema = createUserSchema.partial();
123
123
  | Wrong | Right | Why |
124
124
  |-------|-------|-----|
125
125
  | `useState` for each field | `useForm` | Unnecessary re-renders on every keystroke |
126
- | Manual error display | `<FormMessage />` | Consistent UI, auto-connects to field errors |
126
+ | Manual error display | `<FieldError errors={[fieldState.error]} />` | Consistent UI, wired to the field's own error |
127
127
  | `fetch` in submit handler | `useMutation` | Loading state, error handling, cache invalidation |
128
128
  | Type written manually | `z.infer<typeof schema>` | Single source of truth |
129
129
  | `z.string().email()` | `z.email()` | Zod 4 moved format checks to top-level functions |
130
130
  | `{ required_error: '...' }` | `{ error: '...' }` | Zod 4 unified error customization on one `error` param |
131
+ | Legacy shadcn `<Form>`/`<FormField>`/`<FormMessage>` in a new screen | `Controller` + `<Field>`/`<FieldError>` | shadcn's forms docs are written around `Field`; a screen still on the legacy wrapper is migrated when it is next touched, never extended |
131
132
 
132
133
  ---
133
134
 
@@ -14,7 +14,8 @@ Server state (API data) lives in TanStack Query. UI state lives in React. No glo
14
14
  ## Core Rules
15
15
 
16
16
  - ALWAYS use TanStack Query for anything that comes from the .NET API
17
- - ALWAYS use `useState` for local UI state (modal open, selected tab, form step)
17
+ - ALWAYS use `useState` for local UI state (modal open, form step)
18
+ - ALWAYS keep a list's page, sort and filters, and a page's active tab, in the URL (`searchParams`) — never in `useState`: a refresh or a shared link must reopen the same view (`admin-app/data-table.md`, `admin-app/page-structure.md`)
18
19
  - NEVER install Zustand or Redux without first exhausting Server Components + TanStack Query
19
20
  - NEVER use React Context for server state — Context does not cache or deduplicate
20
21
  - ALWAYS derive state from server data rather than syncing it to local state
@@ -101,6 +101,24 @@ export function QueryClientWrapper({ children }: { children: React.ReactNode })
101
101
  }
102
102
  ```
103
103
 
104
+ ## Test Budget
105
+
106
+ The plan (`morph-plan`) gives each task a budget: **one test per postcondition, plus one
107
+ regression test per bug fixed**. Going above it takes a one-line justification in the task. The
108
+ happy path + one error path per component above is that budget applied to a component.
109
+
110
+ - **Table before copy.** Scenarios of the same behavior — edge cases included — are rows of one
111
+ `it.each`/`test.each`, never N `it()` blocks that differ by one value.
112
+ - **No test that only pins text.** Finding an element by its text to assert what the user can do
113
+ is fine; a test whose only assertion is the presence or absence of a copy string (a dash, a
114
+ word, a tenant name) proves the file's version, not behavior. That rule belongs in a lint rule or
115
+ a publish-time validation, outside the suite count.
116
+ - **Shared helpers by default.** Reuse the existing wrappers (`test/helpers.tsx`), MSW handlers and
117
+ factories. Before writing a new one, look for it (`morph-spec graph explain <Name>`; fallback
118
+ without a graph: `grep -rn`).
119
+ - **TDD where it pays:** a bug gets its regression test first, and so does pure logic (formatters,
120
+ reducers, schema). Component and integration tests may come after the code.
121
+
104
122
  ## Common Mistakes
105
123
 
106
124
  | Wrong | Right | Why |
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **Template** — copy to `.morph/context/design-system.md` and fill in sections marked `/* CUSTOMIZE */`.
4
4
 
5
- Living document. All agents read this before any UI work. All design decisions land here.
5
+ Living document. All agents read this before any UI work. All design decisions land here — **rewritten in place, never stacked**: a decision that changes rewrites the section that described the old one (a value that still holds somewhere says where), so an agent reading only the body gets today's answer.
6
6
 
7
7
  ---
8
8
 
@@ -332,8 +332,8 @@ Choose patterns based on the project domain:
332
332
 
333
333
  ## Changelog
334
334
 
335
- > Living record — every agent that adds tokens or design decisions registers here.
336
- > Format: `- YYYY-MM-DD [agent-id] Description of addition/change`
335
+ > When and why the body changed — never the new value itself: that lives in the section it rewrote.
336
+ > Format: `- YYYY-MM-DD [agent-id] reason (section rewritten)`
337
337
 
338
338
  <!-- Entries below this line, newest first -->
339
339
 
@@ -136,6 +136,17 @@ How will we know this feature is successful?
136
136
 
137
137
  ---
138
138
 
139
+ ## Conflitos com o acervo
140
+
141
+ UCs (`.morph/specs/usecases/`), ADRs ativos (`.morph/specs/adrs/`) and `.morph/context/*.md` that
142
+ this request contradicts. `Nenhum conflito encontrado.` when there is none — the section is always present.
143
+
144
+ | Fonte | O que diz hoje | O que o pedido muda | Decisão |
145
+ |-------|----------------|---------------------|---------|
146
+ | {UC-133} | {Public Sans + Lora em toda a interface} | {admin passa a Geist} | {vale o novo no admin; a vitrine mantém o antigo — decisions.md ADR-001} |
147
+
148
+ ---
149
+
139
150
  ## Dependencies
140
151
 
141
152
  - [ ] {Dependency 1} - {status}
@@ -204,6 +204,21 @@ public interface I{{pascalCase FEATURE_NAME}}Service
204
204
 
205
205
  ---
206
206
 
207
+ ## UCs e ADRs que esta feature altera ou revoga
208
+
209
+ > Read by `morph-spec finish`: in the archive commit, each row marks the project acervo — a UC turns
210
+ > `status: superseded` + `superseded_by` (+ `scope` when partial); an ADR leaves `.morph/specs/adrs/`
211
+ > (total) or keeps its file with the scope where it still holds (partial). Columns are positional.
212
+ > `morph-spec usecase check {feature}` reports a bad row while this file can still change (it freezes at Gate 2).
213
+ > Nothing revoked → replace the table with `Nenhum.`
214
+
215
+ | Id | Mudança | Substituto | Escopo em que o antigo ainda vale |
216
+ |----|---------|------------|-----------------------------------|
217
+ | UC-{nn} | parcial | UC-{nn} | {where the old one still holds} |
218
+ | {feature}/ADR-{nnn} | total | — | — |
219
+
220
+ ---
221
+
207
222
  ## Security
208
223
 
209
224
  | Action | Required Policy |
@@ -1,98 +1,115 @@
1
- # UI Mockups & Wireframes: {{titleCase FEATURE_NAME}}
2
-
3
- | Field | Value |
4
- |-------|-------|
5
- | **Feature** | {{FEATURE_NAME}} |
6
- | **Created** | {{DATE}} |
7
-
8
- ---
9
-
10
- ## Screen Inventory
11
-
12
- | Screen ID | Name | Route | Priority |
13
- |-----------|------|-------|----------|
14
- | **S001** | {Screen Name} | /path | High |
15
- | **S002** | {Screen Name} | /path | Medium |
16
-
17
- ---
18
-
19
- ## S001: {Primary Screen}
20
-
21
- ### Desktop Layout
22
-
23
- ```
24
- ┌─────────────────────────────────────┐
25
- │ Header [User ▼] │
26
- ├─────────────────────────────────────┤
27
- │ │
28
- │ [Title] │
29
- │ │
30
- │ ┌──────────────────────────────┐ │
31
- │ │ Main Content Area │ │
32
- │ │ │ │
33
- │ │ [Card 1] [Card 2] │ │
34
- │ │ │ │
35
- │ │ ┌────────────────────────┐ │ │
36
- │ │ │ Data Table │ │ │
37
- │ │ │ ... │ │ │
38
- │ │ └────────────────────────┘ │ │
39
- │ └──────────────────────────────┘ │
40
- │ │
41
- └─────────────────────────────────────┘
42
- ```
43
-
44
- ### Mobile Layout
45
-
46
- ```
47
- ┌──────────────────────┐
48
- │ ☰ Title [User ▼]│
49
- ├──────────────────────┤
50
- │ │
51
- │ [Card 1] │
52
- │ │
53
- │ [Card 2] │
54
- │ │
55
- │ [View All Items] │
56
- │ │
57
- └──────────────────────┘
58
- ```
59
-
60
- ---
61
-
62
- ## States
63
-
64
- ### Loading
65
- - Show skeleton placeholders
66
- - Spinner for primary content
67
-
68
- ### Empty
69
- - Icon + message
70
- - Clear call-to-action button
71
-
72
- ### Error
73
- - Warning icon
74
- - User-friendly message
75
- - Retry button
76
-
77
- ### Success (After Action)
78
- - Toast notification
79
- - Auto-dismiss after 3s
80
-
81
- ---
82
-
83
- ## Interactions
84
-
85
- - **Hover**: Subtle elevation increase
86
- - **Click**: Scale down (0.98)
87
- - **Transitions**: Fade-in 200ms
88
-
89
- ---
90
-
91
- ## Accessibility
92
- - [ ] 44x44px minimum touch targets
93
- - [ ] Focus indicators visible
94
- - [ ] Proper heading hierarchy (H1 → H2 → H3)
95
-
96
- ---
97
-
98
- *Generated with MORPH Framework*
1
+ # UI Mockups & Wireframes: {{titleCase FEATURE_NAME}}
2
+
3
+ | Field | Value |
4
+ |-------|-------|
5
+ | **Feature** | {{FEATURE_NAME}} |
6
+ | **Created** | {{DATE}} |
7
+
8
+ ---
9
+
10
+ ## Screen Inventory
11
+
12
+ | Screen ID | Name | Route | Priority |
13
+ |-----------|------|-------|----------|
14
+ | **S001** | {Screen Name} | /path | High |
15
+ | **S002** | {Screen Name} | /path | Medium |
16
+
17
+ ---
18
+
19
+ ## Tela: {Primary Screen}
20
+
21
+ ### Desktop Layout
22
+
23
+ ```
24
+ ┌─────────────────────────────────────┐
25
+ │ Header [User ▼] │
26
+ ├─────────────────────────────────────┤
27
+ │ │
28
+ │ [Title] │
29
+ │ │
30
+ │ ┌──────────────────────────────┐ │
31
+ │ │ Main Content Area │ │
32
+ │ │ │ │
33
+ │ │ [Card 1] [Card 2] │ │
34
+ │ │ │ │
35
+ │ │ ┌────────────────────────┐ │ │
36
+ │ │ │ Data Table │ │ │
37
+ │ │ │ ... │ │ │
38
+ │ │ └────────────────────────┘ │ │
39
+ │ └──────────────────────────────┘ │
40
+ │ │
41
+ └─────────────────────────────────────┘
42
+ ```
43
+
44
+ ### Mobile Layout
45
+
46
+ ```
47
+ ┌──────────────────────┐
48
+ │ ☰ Title [User ▼]│
49
+ ├──────────────────────┤
50
+ │ │
51
+ │ [Card 1] │
52
+ │ │
53
+ │ [Card 2] │
54
+ │ │
55
+ │ [View All Items] │
56
+ │ │
57
+ └──────────────────────┘
58
+ ```
59
+
60
+ ### Checklist de tela
61
+
62
+ Troque cada `…` pela decisão — "não se aplica" vale se escrito; `…`, vazio ou "a definir" reprovam o Gate uiux.
63
+
64
+ | Item | Decisão |
65
+ |---|---|
66
+ | Superfície | … |
67
+ | Volume esperado | … |
68
+ | Paginação | … |
69
+ | Ordenação | … |
70
+ | Filtro | … |
71
+ | Estado vazio | … |
72
+ | Estado carregando | … |
73
+ | Estado de erro | … |
74
+ | Mobile | … |
75
+ | Abas | … |
76
+
77
+ ---
78
+
79
+ ## States
80
+
81
+ ### Loading
82
+ - Show skeleton placeholders
83
+ - Spinner for primary content
84
+
85
+ ### Empty
86
+ - Icon + message
87
+ - Clear call-to-action button
88
+
89
+ ### Error
90
+ - Warning icon
91
+ - User-friendly message
92
+ - Retry button
93
+
94
+ ### Success (After Action)
95
+ - Toast notification
96
+ - Auto-dismiss after 3s
97
+
98
+ ---
99
+
100
+ ## Interactions
101
+
102
+ - **Hover**: Subtle elevation increase
103
+ - **Click**: Scale down (0.98)
104
+ - **Transitions**: Fade-in 200ms
105
+
106
+ ---
107
+
108
+ ## Accessibility
109
+ - [ ] 44x44px minimum touch targets
110
+ - [ ] Focus indicators visible
111
+ - [ ] Proper heading hierarchy (H1 → H2 → H3)
112
+
113
+ ---
114
+
115
+ *Generated with MORPH Framework*
@@ -5,12 +5,18 @@ namespace Morph.AiKit.Rag;
5
5
  /// </summary>
6
6
  /// <remarks>
7
7
  /// <para>
8
- /// <b>O defeito que este tipo existe para matar</b> e concreto e esta em producao: a base de
9
- /// conhecimento do GHLBrain <b>apaga tudo e re-embeda tudo</b> a cada ingestao. O custo e
10
- /// pago em embedding de documento que nao mudou, e a janela entre o apagar e o gravar e uma
11
- /// janela em que a busca nao acha nada. Um plano em quatro baldes torna visivel o que a
12
- /// ingestao inteira escondia: quase sempre <see cref="Unchanged"/> e a lista grande e as
13
- /// outras tres sao curtas.
8
+ /// <b>O defeito que este tipo existe para matar</b> e o apaga-e-regrava: a base de
9
+ /// conhecimento do GHLBrain <b>apaga e re-embeda o documento inteiro</b> a cada ingestao,
10
+ /// mudou ou nao. O custo e pago em embedding de trecho que nao mudou e em latencia (uma
11
+ /// chamada de embedding por item no reindex em massa). Um plano em quatro baldes torna
12
+ /// visivel o que a ingestao inteira escondia: quase sempre <see cref="Unchanged"/> e a lista
13
+ /// grande e as outras tres sao curtas.
14
+ /// </para>
15
+ /// <para>
16
+ /// Errata (2026-09-15, Morph.GHLBrain#96): a versao anterior deste comentario citava tambem
17
+ /// uma janela entre o apagar e o gravar em que a busca nao acha nada. No GHLBrain o apagar e
18
+ /// o gravar ja rodam numa transacao so, com o embedding antes dela, entao essa janela nao
19
+ /// existe la. Ela existe em quem apaga fora da transacao que grava.
14
20
  /// </para>
15
21
  /// <para>
16
22
  /// <b>E um plano, nao uma execucao.</b> Nada aqui toca banco, vetor ou arquivo: quem aplica