@crvouga/atlas 1.21.0 → 1.22.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 (96) hide show
  1. package/CHANGELOG.md +9 -1
  2. package/dist/core/src/cli.d.ts +2 -2
  3. package/dist/core/src/cli.js +4 -1
  4. package/dist/critics/src/catalog-client.d.ts +91 -0
  5. package/dist/critics/src/catalog-client.js +194 -0
  6. package/dist/critics/src/cli-calibrate.d.ts +4 -0
  7. package/dist/critics/src/cli-calibrate.js +211 -0
  8. package/dist/critics/src/cli-common.d.ts +108 -0
  9. package/dist/critics/src/cli-common.js +155 -0
  10. package/dist/critics/src/cli-review.d.ts +4 -0
  11. package/dist/critics/src/cli-review.js +174 -0
  12. package/dist/critics/src/cli-watch.d.ts +4 -0
  13. package/dist/critics/src/cli-watch.js +191 -0
  14. package/dist/critics/src/cli.d.ts +13 -0
  15. package/dist/critics/src/cli.js +490 -0
  16. package/dist/critics/src/index.d.ts +3 -0
  17. package/dist/critics/src/index.js +3 -0
  18. package/dist/critics/src/judging.d.ts +8 -0
  19. package/dist/critics/src/llm.d.ts +120 -0
  20. package/dist/critics/src/llm.js +266 -0
  21. package/dist/critics/src/marks.d.ts +74 -0
  22. package/dist/critics/src/marks.js +76 -0
  23. package/dist/critics/src/registry.d.ts +125 -0
  24. package/dist/critics/src/registry.js +203 -0
  25. package/dist/critics/src/spool.d.ts +32 -0
  26. package/dist/critics/src/spool.js +129 -0
  27. package/dist/critics/src/uiclip.d.ts +82 -0
  28. package/dist/critics/src/uiclip.js +167 -0
  29. package/dist/reports/src/critique-review.d.ts +111 -0
  30. package/dist/reports/src/critique-review.js +123 -0
  31. package/dist/reports/src/critique-row.d.ts +24 -0
  32. package/dist/reports/src/critique-row.js +39 -0
  33. package/dist/reports/src/evidence-types.d.ts +5 -0
  34. package/dist/reports/src/layer-merge.js +5 -0
  35. package/dist/reports/src/report-index.d.ts +6 -0
  36. package/dist/reports/src/report-index.js +12 -0
  37. package/dist/reports/src/ui-catalog-cli.d.ts +1 -1
  38. package/dist/reports/src/ui-catalog-cli.js +3 -3
  39. package/dist/reports/src/ui-catalog-entries.d.ts +147 -0
  40. package/dist/reports/src/ui-catalog-entries.js +190 -0
  41. package/dist/reports/src/ui-catalog-publish.js +2 -2
  42. package/dist/reports/src/ui-catalog.d.ts +2 -0
  43. package/dist/reports/src/ui-catalog.js +1 -1
  44. package/dist/reports/src/ui-state.d.ts +2 -0
  45. package/dist/reports/src/ui-state.js +2 -2
  46. package/dist/schema/src/api.d.ts +653 -1
  47. package/dist/schema/src/api.js +44 -0
  48. package/dist/schema/src/cli-results.d.ts +674 -1
  49. package/dist/schema/src/cli-results.js +177 -1
  50. package/dist/schema/src/critique.d.ts +31 -0
  51. package/dist/schema/src/critique.js +26 -0
  52. package/dist/schema/src/server-config.d.ts +3 -3
  53. package/dist/server/src/app.js +28 -1
  54. package/dist/server/src/openapi.js +19 -2
  55. package/docs/agents.md +11 -2
  56. package/docs/critics.md +273 -9
  57. package/docs/extending.md +1 -1
  58. package/docs/reference/cli.md +73 -3
  59. package/docs/reference/core.md +1 -1
  60. package/docs/reference/critics.md +1131 -29
  61. package/docs/reference/http-api.md +40 -0
  62. package/docs/reference/reports.md +463 -0
  63. package/docs/reference/schema.md +157 -1
  64. package/docs/report-contract.md +2 -1
  65. package/docs/server.md +2 -0
  66. package/docs/ui-catalog.md +4 -1
  67. package/docs/ui.md +63 -1
  68. package/llms-full.txt +469 -18
  69. package/llms.txt +1 -1
  70. package/package.json +9 -1
  71. package/packages/critics/README.md +1 -0
  72. package/packages/schema/schemas/critic-calibrate-result.schema.json +274 -0
  73. package/packages/schema/schemas/critic-doctor-result.schema.json +74 -0
  74. package/packages/schema/schemas/critic-list-result.schema.json +90 -0
  75. package/packages/schema/schemas/critic-review-result.schema.json +397 -0
  76. package/packages/schema/schemas/critic-run-result.schema.json +249 -0
  77. package/packages/schema/schemas/critic-setup-result.schema.json +34 -0
  78. package/packages/schema/schemas/critic-watch-result.schema.json +211 -0
  79. package/packages/schema/schemas/critique-mark.schema.json +81 -0
  80. package/packages/schema/schemas/effective-delta.schema.json +337 -0
  81. package/packages/schema/schemas/effective-evidence.schema.json +337 -0
  82. package/packages/schema/schemas/layer-rows.schema.json +337 -0
  83. package/packages/server/openapi.json +6755 -4738
  84. package/packages/visualizer/src/app/AppShell.tsx +3 -1
  85. package/packages/visualizer/src/app/router.tsx +20 -7
  86. package/packages/visualizer/src/components/Header.tsx +16 -4
  87. package/packages/visualizer/src/critiques/CritiquesPage.tsx +402 -0
  88. package/packages/visualizer/src/critiques/FindingOverlay.tsx +50 -0
  89. package/packages/visualizer/src/critiques/ranking.ts +54 -0
  90. package/packages/visualizer/src/critiques/search.ts +41 -0
  91. package/packages/visualizer/src/evidence/applicability-view.tsx +11 -7
  92. package/packages/visualizer/src/evidence/behaviors-page.tsx +22 -15
  93. package/packages/visualizer/src/explorer/Explorer.tsx +5 -0
  94. package/packages/visualizer/src/explorer/TestDetail.tsx +4 -1
  95. package/packages/visualizer/src/explorer/parts.tsx +19 -1
  96. package/packages/visualizer/src/explorer/playlist.tsx +11 -7
@@ -14,6 +14,7 @@
14
14
  * @see docs/server.md
15
15
  */
16
16
  import { z } from 'zod/v4';
17
+ import { CritiqueMarkSchema, CritiqueSchema } from './critique.js';
17
18
  import { CheckSchema, EvidenceScopeSchema, LayerRunSchema, MeasurementSchema } from './layer.js';
18
19
  /** One of the statuses a check has in a report: `passed`, `failed`, `running` (not finished) or `not-run`. Closed. */
19
20
  export const EvidenceStatusSchema = z.enum(['passed', 'failed', 'running', 'not-run']);
@@ -136,6 +137,7 @@ export const LayerRowSchema = z.looseObject({
136
137
  evidence: EvidenceSummarySchema.optional(),
137
138
  state: z.looseObject({
138
139
  route: z.string().optional(), fixture: z.string().optional(), cohort: z.string().optional(), area: z.string().optional(),
140
+ kind: z.string().optional().describe('The kind of UI state the producer declared: `screen`, `overlay`, `loading`, `error`, `empty`… Open vocabulary'),
139
141
  flags: z.array(z.string()).optional(), covers: z.array(z.string()).optional(),
140
142
  inventory: z.boolean().optional().describe('A `ui-plan` entry that names a surface of the product\'s inventory, not a state'),
141
143
  screenshot: z.looseObject({
@@ -144,6 +146,8 @@ export const LayerRowSchema = z.looseObject({
144
146
  omitted: z.string().optional().describe('Why the producer left the bytes out')
145
147
  }).optional().describe('The check\'s picture: its `screenshot` attachment, else its first image')
146
148
  }).optional().describe('Only for a check of a `ui-state` or `ui-plan` part: its picture and the facts its producer declared under the `atlas.ui-state` extension. See the UI catalog guide. Never decides a result'),
149
+ critique: CritiqueSchema.optional().describe('Only for a check of a `critique` part whose `atlas.critique` extension can be read: the opinion of an automated reviewer. An opinion, never a result: it does not decide `status`, a slot or the gate. See the critics guide'),
150
+ critiqueMark: CritiqueMarkSchema.optional().describe('Only for a check of a `critique` part whose `atlas.critique-mark` extension can be read: a person\'s accept or dismiss of a critic\'s opinion. Evidence, never a result: it does not decide `status`, a slot or the gate. See the critics guide'),
147
151
  recording: z.looseObject({ state: z.string(), reason: z.string().optional() }).optional().describe('What became of the check\'s expected recording: uploaded, referenced, skipped, unresolved or not-applicable. Independent of `status`')
148
152
  });
149
153
  /** A layer with its checks: the rows of one layer, read apart from its header. */
@@ -788,6 +792,7 @@ export const UiCatalogSchema = z.looseObject({
788
792
  states: z.array(z.looseObject({
789
793
  id: z.string(), title: z.string(),
790
794
  route: z.string().nullable(), fixture: z.string().nullable(), cohort: z.string().nullable(), area: z.string().nullable(),
795
+ kind: z.string().nullable().optional().describe('The kind of UI state the producers declared (`screen`, `overlay`, `loading`…), or null. Absent from an older server'),
791
796
  flags: z.array(z.string()), covers: z.array(z.string()).describe('The surfaces it covers'), producers: z.array(z.string()),
792
797
  cells: z.array(UiCellSchema)
793
798
  })),
@@ -801,3 +806,42 @@ export const UiCatalogSchema = z.looseObject({
801
806
  total: z.number().int().nonnegative().optional().describe('States that matched, before `offset` and `limit`'),
802
807
  offset: z.number().int().nonnegative().optional(), limit: z.number().int().nonnegative().optional()
803
808
  });
809
+ /** An entry of the catalog as a critic reads it: one captured state in one profile, with the hash of its stored picture and the critiques already made of it. */
810
+ export const CatalogEntrySchema = z.looseObject({
811
+ key: z.string().describe('Stable identity, unique in the catalog: the state id, then `@` and the profile when it has one. A critique names it as `subject.entryKey`'),
812
+ stateId: z.string(), title: z.string(), route: z.string().nullable(), area: z.string().nullable(),
813
+ state: z.string().describe('The kind of UI state the producers declared: `screen`, `overlay`, `loading`, `error`, `empty`… or `unknown` when none did. Open vocabulary'),
814
+ profile: UiProfileSchema,
815
+ image: z.looseObject({
816
+ sha256: z.string().describe('The hash of the exact stored bytes. A critique is anchored to it'),
817
+ path: z.string().describe('Where the bytes are, relative to the reports API root (`/api/reports`): `/layers/<layer>/blobs/attachments/<sha256>`. Served by the safe attachment path'),
818
+ contentType: z.string().optional(), width: z.number().optional(), height: z.number().optional(), bytes: z.number().optional()
819
+ }),
820
+ origin: z.looseObject({
821
+ layer: z.string(), backend: z.string(), producer: z.string(), recordedAtMs: z.number(), sha: z.string().nullable(), branch: z.string().nullable(), runUrl: z.string().nullable(),
822
+ freshness: z.enum(['unknown', 'modified']).optional()
823
+ }),
824
+ critiques: z.array(z.looseObject({
825
+ layer: z.string(), producer: z.string(), recordedAtMs: z.number(), status: EvidenceStatusSchema.describe('Whether the critic ran, never what it thought'),
826
+ currency: z.enum(['current', 'earlier-image']).describe('`earlier-image`: the picture changed since, so the entry counts as not yet judged by that critic'),
827
+ critique: CritiqueSchema
828
+ })).describe('The critiques of this entry that win their slot, newest first. Opinions: they never decide a result'),
829
+ marks: z.array(z.looseObject({
830
+ layer: z.string(), producer: z.string().describe('`critic.review.<reviewer>`'), recordedAtMs: z.number(),
831
+ currency: z.enum(['current', 'earlier-image']).describe('`earlier-image`: the mark was made about a picture the entry no longer has, so it counts for nothing now'),
832
+ mark: CritiqueMarkSchema
833
+ })).optional().describe('People\'s accept or dismiss marks of those critiques that win their slot, newest first. Evidence: they never decide a result. Absent from a server that predates marks, which means none')
834
+ });
835
+ /**
836
+ * `GET /api/reports/ui-catalog/entries`: the UI catalog as a flat, cursor-paged list of captured states for a critic.
837
+ */
838
+ export const CatalogEntriesSchema = z.looseObject({
839
+ schemaVersion: z.literal(1),
840
+ version: z.string().describe('The report version this page was read at. Keep the first page\'s: reading `since` it later finds whatever changed while the rest was read'),
841
+ entries: z.array(CatalogEntrySchema),
842
+ total: z.number().int().nonnegative().describe('Entries that match the query, across all pages'),
843
+ nextCursor: z.string().optional().describe('Pass as `cursor` to read the next page. Absent on the last page'),
844
+ since: z.looseObject({ requested: z.string(), honored: z.boolean().describe('False when the server does not remember that version: the answer is then the whole catalog') }).optional().describe('Present when `since` was asked'),
845
+ unjudgeable: z.number().int().nonnegative().describe('Captured cells that are not entries because no stored picture of a known hash backs them (given only by address, left out, or not archived yet)'),
846
+ sources: z.looseObject({ backends: z.array(BackendInfoSchema), notices: z.array(z.string()) }).describe('What could not be read; what depended on it is not offered')
847
+ });