@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.
- package/CLAUDE.md +19 -6
- package/README.md +2 -2
- package/bin/morph-spec.js +16 -7
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +1 -1
- package/docs/QUICKSTART.md +1 -1
- package/framework/CLAUDE.md +3 -3
- package/framework/MORPH.md +25 -22
- package/framework/agents.json +76 -27
- package/framework/docs/CLI.md +55 -18
- package/framework/evals/rubrics/code-quality.md +5 -0
- package/framework/evals/rubrics/condensed.md +6 -2
- package/framework/evals/rubrics/contracts.md +20 -0
- package/framework/evals/rubrics/test-coverage.md +17 -6
- package/framework/hooks/README.md +9 -3
- package/framework/hooks/claude-code/core/graph-refresh-kick.js +52 -0
- package/framework/hooks/claude-code/core/telemetry-log.js +172 -87
- package/framework/hooks/claude-code/core/validate-completion.js +16 -90
- package/framework/hooks/claude-code/core/worktree-context.js +10 -0
- package/framework/hooks/shared/command-tokens.js +96 -0
- package/framework/hooks/shared/git-exclude.js +44 -0
- package/framework/hooks/shared/git-paths.js +52 -0
- package/framework/hooks/shared/graph-freshness.js +380 -0
- package/framework/hooks/shared/graph-refresh.js +416 -0
- package/framework/hooks/shared/morph-cli.js +17 -5
- package/framework/hooks/shared/redact-secrets.js +55 -0
- package/framework/hooks/shared/telemetry-logger.js +25 -2
- package/framework/hooks/shared/transcript-usage.js +80 -0
- package/framework/rubrics/backend.json +2 -2
- package/framework/rubrics/default.json +2 -2
- package/framework/rubrics/frontend.json +2 -2
- package/framework/rules/csharp-standards.md +1 -0
- package/framework/rules/morph-workflow.md +1 -0
- package/framework/rules/nextjs-standards.md +1 -0
- package/framework/schemas/config.schema.json +41 -1
- package/framework/schemas/feature.schema.json +5 -1
- package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
- package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
- package/framework/skills/core/morph-apply/SKILL.md +36 -11
- package/framework/skills/core/morph-brainstorming/SKILL.md +16 -7
- package/framework/skills/core/morph-eval/SKILL.md +1 -1
- package/framework/skills/core/morph-hotfix/SKILL.md +1 -1
- package/framework/skills/core/morph-implement/SKILL.md +39 -10
- package/framework/skills/core/morph-media/SKILL.md +1 -1
- package/framework/skills/core/morph-plan/SKILL.md +72 -15
- package/framework/skills/core/morph-proposal/SKILL.md +1 -1
- package/framework/skills/core/morph-review/SKILL.md +51 -13
- package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
- package/framework/skills/core/morph-standards/SKILL.md +1 -1
- package/framework/skills/core/morph-uiux/SKILL.md +34 -9
- package/framework/standards/STANDARDS.json +187 -12
- package/framework/standards/ai-agents/rag-custom-pgvector.md +7 -3
- package/framework/standards/ai-agents/testing-ai.md +2 -1
- package/framework/standards/architecture/code-comments.md +64 -0
- package/framework/standards/backend/dotnet/testing.md +22 -0
- package/framework/standards/frontend/admin-app/data-table.md +562 -0
- package/framework/standards/frontend/admin-app/feedback.md +236 -0
- package/framework/standards/frontend/admin-app/forms.md +232 -0
- package/framework/standards/frontend/admin-app/page-structure.md +203 -0
- package/framework/standards/frontend/nextjs/components.md +37 -58
- package/framework/standards/frontend/nextjs/data-fetching.md +1 -0
- package/framework/standards/frontend/nextjs/forms.md +31 -30
- package/framework/standards/frontend/nextjs/state-management.md +2 -1
- package/framework/standards/frontend/nextjs/testing.md +18 -0
- package/framework/templates/context/design-system.md +3 -3
- package/framework/templates/docs/proposal.md +11 -0
- package/framework/templates/docs/spec.md +15 -0
- package/framework/templates/docs/ui-mockups.md +115 -98
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaPlan.cs +12 -6
- package/framework/templates/feature/decisions.md +124 -122
- package/package.json +1 -1
- package/src/commands/graph/affected.js +4 -3
- package/src/commands/graph/build.js +109 -18
- package/src/commands/graph/explain.js +8 -5
- package/src/commands/graph/status.js +14 -8
- package/src/commands/observability/cost.js +148 -18
- package/src/commands/project/doctor.js +82 -10
- package/src/commands/project/update.js +25 -0
- package/src/commands/project/worktree.js +73 -90
- package/src/commands/state/advance.js +18 -0
- package/src/commands/state/approve.js +15 -0
- package/src/commands/state/archive.js +62 -9
- package/src/commands/state/finish.js +62 -14
- package/src/commands/state/gate-check.js +8 -1
- package/src/commands/state/gate-decision.js +8 -4
- package/src/commands/state/report-check.js +90 -9
- package/src/commands/state/usecase.js +66 -0
- package/src/commands/tasks/dag.js +17 -2
- package/src/commands/validation/validate-feature.js +6 -1
- package/src/commands/validation/verify.js +20 -1
- package/src/dashboard/scanner/agents-scanner.js +5 -1
- package/src/dashboard/scanner/hooks-scanner.js +8 -1
- package/src/dashboard/scanner/standards-scanner.js +2 -1
- package/src/lib/ai/comment-stripper.js +101 -4
- package/src/lib/evaluator-report.js +25 -0
- package/src/lib/generators/handoff-generator.js +4 -18
- package/src/lib/git/default-branch.js +52 -0
- package/src/lib/git/tree-fingerprint.js +58 -0
- package/src/lib/git/tree-state.js +167 -0
- package/src/lib/graph/god-nodes.js +12 -3
- package/src/lib/graph/graph-health.js +48 -2
- package/src/lib/graph/graph-loader.js +99 -25
- package/src/lib/graph/graphifyignore.js +145 -28
- package/src/lib/graph/sanitize.js +117 -11
- package/src/lib/risk-detector.js +90 -0
- package/src/lib/specs/acervo-format.js +70 -0
- package/src/lib/specs/acervo-lifecycle.js +264 -0
- package/src/lib/specs/adr-index.js +169 -0
- package/src/lib/specs/revocations.js +156 -0
- package/src/lib/specs/screen-checklist.js +357 -0
- package/src/lib/specs/usecase-check.js +20 -16
- package/src/lib/specs/usecase-promoter.js +103 -38
- package/src/lib/specs/usecase-registry.js +7 -7
- package/src/lib/tasks/tasks-json-parser.js +2 -3
- package/src/lib/telemetry/metrics.js +386 -0
- package/src/lib/telemetry/telemetry-reader.js +161 -51
- package/src/lib/telemetry/verify-event.js +79 -0
- package/src/lib/validators/code-budget/code-budget-validator.js +172 -0
- package/src/lib/validators/code-budget/comment-scanner.js +75 -0
- package/src/lib/validators/code-budget/index.js +9 -0
- package/src/lib/validators/reuse/reuse-validator.js +4 -2
- package/src/lib/validators/reuse/symbol-scanner.js +27 -22
- package/src/lib/validators/validation-runner.js +21 -5
- package/src/lib/validators/verify-runner.js +11 -0
- package/src/lib/worktree/finish-backup.js +739 -0
- package/src/lib/worktree/ignored-triage.js +15 -8
- package/src/lib/worktree/worktree-audit.js +5 -0
- package/src/scripts/setup-infra.js +29 -18
- package/src/utils/agents-installer.js +281 -12
- 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
|
|
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
|
|
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/
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
|
60
|
-
const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel() });
|
|
57
|
+
export function PageHeader({ title, description, actions, className }: PageHeaderProps) {
|
|
61
58
|
return (
|
|
62
|
-
<
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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/
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
<
|
|
68
|
-
<
|
|
69
|
-
<
|
|
70
|
-
control={form.control}
|
|
67
|
+
<form onSubmit={form.handleSubmit(onSubmit)}>
|
|
68
|
+
<FieldGroup>
|
|
69
|
+
<Controller
|
|
71
70
|
name="name"
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
<
|
|
76
|
-
<
|
|
77
|
-
|
|
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
|
-
<
|
|
81
|
-
control={form.control}
|
|
80
|
+
<Controller
|
|
82
81
|
name="email"
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
<
|
|
87
|
-
<
|
|
88
|
-
|
|
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
|
-
</
|
|
98
|
-
</
|
|
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 | `<
|
|
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,
|
|
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
|
-
>
|
|
336
|
-
> Format: `- YYYY-MM-DD [agent-id]
|
|
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
|
-
##
|
|
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
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
-
|
|
87
|
-
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
|
9
|
-
/// conhecimento do GHLBrain <b>apaga
|
|
10
|
-
/// pago em embedding de
|
|
11
|
-
///
|
|
12
|
-
/// ingestao inteira escondia: quase sempre <see cref="Unchanged"/> e a lista
|
|
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
|