@cat-factory/app 0.282.2 → 0.283.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/app/components/panels/inspector/TaskEstimateBadge.vue +63 -7
- package/app/composables/usePipelineDraftWarnings.ts +6 -4
- package/app/composables/usePipelineHealth.spec.ts +13 -1
- package/app/composables/usePipelineHealth.ts +8 -9
- package/app/utils/catalog.spec.ts +1 -0
- package/app/utils/catalog.ts +18 -0
- package/app/utils/estimateGating.spec.ts +22 -0
- package/app/utils/estimateGating.ts +32 -0
- package/app/utils/pipelineRender.ts +2 -0
- package/i18n/locales/de.json +10 -2
- package/i18n/locales/en.json +10 -2
- package/i18n/locales/es.json +10 -2
- package/i18n/locales/fr.json +10 -2
- package/i18n/locales/he.json +10 -2
- package/i18n/locales/it.json +10 -2
- package/i18n/locales/ja.json +10 -2
- package/i18n/locales/pl.json +10 -2
- package/i18n/locales/tr.json +10 -2
- package/i18n/locales/uk.json +10 -2
- package/package.json +2 -2
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
// Compact display of a task's
|
|
3
|
-
//
|
|
4
|
-
//
|
|
2
|
+
// Compact display of a task's triage scores (Complexity / Risk / Impact), shown on the inspector
|
|
3
|
+
// once a step has produced them. Read-only: a `task-estimator` step FORECASTS them before the work
|
|
4
|
+
// starts and a `task-reassessor` step MEASURES them afterwards from the change that landed, so the
|
|
5
|
+
// section says which reading it is showing, names the reading it corrected, and shows the earlier
|
|
6
|
+
// number beside each axis that actually moved. Hidden when no estimate exists.
|
|
5
7
|
import { computed } from 'vue'
|
|
6
8
|
import type { Block } from '~/types/domain'
|
|
9
|
+
import { estimateBasisLabelKey } from '~/utils/estimateGating'
|
|
7
10
|
import InspectorSection from '~/components/panels/inspector/InspectorSection.vue'
|
|
8
11
|
|
|
9
12
|
const props = defineProps<{ block: Block }>()
|
|
@@ -11,14 +14,53 @@ const { t, n } = useI18n()
|
|
|
11
14
|
|
|
12
15
|
const estimate = computed(() => props.block.estimate ?? null)
|
|
13
16
|
|
|
14
|
-
|
|
15
|
-
|
|
17
|
+
/**
|
|
18
|
+
* The three axes with both readings, so the template asks nothing about which one to show.
|
|
19
|
+
*
|
|
20
|
+
* `was` is present only where the superseded reading DIFFERS. An axis whose score did not move
|
|
21
|
+
* renders "was 40% 40%", which reads as a correction that did not happen; and the interesting
|
|
22
|
+
* thing about a re-measurement is exactly which axes it moved.
|
|
23
|
+
*/
|
|
24
|
+
const AXES = computed(() => {
|
|
25
|
+
const current = estimate.value
|
|
26
|
+
const prior = current?.supersedes ?? null
|
|
27
|
+
return (
|
|
16
28
|
[
|
|
17
29
|
{ key: 'complexity', label: t('inspector.estimate.complexity') },
|
|
18
30
|
{ key: 'risk', label: t('inspector.estimate.risk') },
|
|
19
31
|
{ key: 'impact', label: t('inspector.estimate.impact') },
|
|
20
|
-
] as const
|
|
21
|
-
)
|
|
32
|
+
] as const
|
|
33
|
+
).map((axis) => ({
|
|
34
|
+
...axis,
|
|
35
|
+
was:
|
|
36
|
+
prior && current && prior[axis.key] !== current[axis.key]
|
|
37
|
+
? n(prior[axis.key], { key: 'percent' })
|
|
38
|
+
: null,
|
|
39
|
+
}))
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* What this reading is, in one line. Which key that is lives in `utils/estimateGating`, beside the
|
|
44
|
+
* rest of the estimate presentation vocabulary and under test: `basis` is PERSISTED and read back
|
|
45
|
+
* without a schema pass, so absent, known and unrecognised are three distinct answers.
|
|
46
|
+
*/
|
|
47
|
+
const basisLabel = computed(() => t(estimateBasisLabelKey(estimate.value?.basis)))
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* What the current reading REPLACED, named by ITS basis rather than left implicit.
|
|
51
|
+
*
|
|
52
|
+
* A "was 80%" chip beside a header reading "Forecast before the work started" says the earlier
|
|
53
|
+
* number was an earlier forecast, and after a re-run of the estimator on a measured task that is
|
|
54
|
+
* the wrong way round: the superseded reading is the MEASUREMENT. The backend summary prefixes the
|
|
55
|
+
* same movement with the same label for the same reason.
|
|
56
|
+
*/
|
|
57
|
+
const supersededLabel = computed(() => {
|
|
58
|
+
const prior = estimate.value?.supersedes
|
|
59
|
+
if (!prior) return null
|
|
60
|
+
return t('inspector.estimate.supersededBasis', {
|
|
61
|
+
basis: t(estimateBasisLabelKey(prior.basis)),
|
|
62
|
+
})
|
|
63
|
+
})
|
|
22
64
|
|
|
23
65
|
/** Cool→hot bar colour by severity (low = sky, mid = amber, high = rose). */
|
|
24
66
|
function barClass(n: number): string {
|
|
@@ -37,6 +79,14 @@ function barClass(n: number): string {
|
|
|
37
79
|
default-open
|
|
38
80
|
>
|
|
39
81
|
<div class="space-y-1.5 rounded-lg border border-slate-800 bg-slate-900/40 p-2.5">
|
|
82
|
+
<p class="text-[11px] text-slate-500" data-testid="task-estimate-basis">{{ basisLabel }}</p>
|
|
83
|
+
<p
|
|
84
|
+
v-if="supersededLabel"
|
|
85
|
+
class="text-[11px] text-slate-500"
|
|
86
|
+
data-testid="task-estimate-superseded"
|
|
87
|
+
>
|
|
88
|
+
{{ supersededLabel }}
|
|
89
|
+
</p>
|
|
40
90
|
<div v-for="axis in AXES" :key="axis.key" class="flex items-center gap-2">
|
|
41
91
|
<span class="w-20 shrink-0 text-xs text-slate-400">{{ axis.label }}</span>
|
|
42
92
|
<div class="h-1.5 flex-1 overflow-hidden rounded-full bg-slate-800">
|
|
@@ -46,6 +96,12 @@ function barClass(n: number): string {
|
|
|
46
96
|
:style="{ width: `${Math.round(estimate[axis.key] * 100)}%` }"
|
|
47
97
|
/>
|
|
48
98
|
</div>
|
|
99
|
+
<span
|
|
100
|
+
v-if="axis.was"
|
|
101
|
+
class="shrink-0 text-[11px] tabular-nums text-slate-500"
|
|
102
|
+
:data-testid="`task-estimate-was-${axis.key}`"
|
|
103
|
+
>{{ t('inspector.estimate.was', { value: axis.was }) }}</span
|
|
104
|
+
>
|
|
49
105
|
<span class="w-9 shrink-0 text-end text-xs tabular-nums text-slate-300">{{
|
|
50
106
|
n(estimate[axis.key], { key: 'percent' })
|
|
51
107
|
}}</span>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { computed, type ComputedRef } from 'vue'
|
|
2
2
|
import {
|
|
3
3
|
pipelineEnvironmentProblems,
|
|
4
|
+
producesTaskEstimate,
|
|
4
5
|
purposeAllowsAgentCategory,
|
|
5
6
|
type PipelineEnvironmentProblemReason,
|
|
6
7
|
} from '@cat-factory/contracts'
|
|
@@ -60,13 +61,14 @@ export function usePipelineDraftWarnings(
|
|
|
60
61
|
|
|
61
62
|
const enabled = (i: number) => pipelines.draftEnabled[i] !== false
|
|
62
63
|
|
|
63
|
-
// A gated step with no
|
|
64
|
-
// save and the start). Both the step's own estimate gate (`draftGating`) and the Tester QC
|
|
65
|
-
// companion's (`draftTesterQuality[i].gating`) count
|
|
64
|
+
// A gated step with no estimate PRODUCER before it (mirrors `assertValidGating`, which rejects
|
|
65
|
+
// the save and the start). Both the step's own estimate gate (`draftGating`) and the Tester QC
|
|
66
|
+
// companion's (`draftTesterQuality[i].gating`) count, and either producer satisfies it: the
|
|
67
|
+
// estimator forecasts the estimate up front, the reassessor measures it once the change lands.
|
|
66
68
|
const gatingNeedsEstimator = computed(() => {
|
|
67
69
|
const kinds = pipelines.draft
|
|
68
70
|
const hasEstimatorBefore = (i: number) =>
|
|
69
|
-
kinds.slice(0, i).some((k, j) => k
|
|
71
|
+
kinds.slice(0, i).some((k, j) => producesTaskEstimate(k) && enabled(j))
|
|
70
72
|
return kinds.some((_, i) => {
|
|
71
73
|
if (!enabled(i)) return false
|
|
72
74
|
const gated =
|
|
@@ -133,7 +133,7 @@ describe('usePipelineHealth', () => {
|
|
|
133
133
|
expect(invalid.value[0]!.problems.some((p) => p.type === 'shape')).toBe(true)
|
|
134
134
|
})
|
|
135
135
|
|
|
136
|
-
it('flags an estimate-gated companion with no
|
|
136
|
+
it('flags an estimate-gated companion with no estimate producer before it (shape)', () => {
|
|
137
137
|
const gated = builtin(['coder', 'reviewer'], {
|
|
138
138
|
gating: [null, { enabled: true, minComplexity: 0.5, onMissingEstimate: 'run' }],
|
|
139
139
|
})
|
|
@@ -142,6 +142,18 @@ describe('usePipelineHealth', () => {
|
|
|
142
142
|
expect(invalid.value[0]!.problems.some((p) => p.type === 'shape')).toBe(true)
|
|
143
143
|
})
|
|
144
144
|
|
|
145
|
+
// The estimate has two producers, at opposite ends of a run, and this advisory reads the SAME
|
|
146
|
+
// `producesTaskEstimate` predicate the engine's `assertValidGating` does. A copy that knew only
|
|
147
|
+
// the estimator would call a perfectly saveable pipeline invalid, in the surface that auto-opens
|
|
148
|
+
// a modal over the board.
|
|
149
|
+
it('accepts a gated step preceded by a task-reassessor instead of an estimator', () => {
|
|
150
|
+
const measured = builtin(['coder', 'task-reassessor', 'human-review'], {
|
|
151
|
+
gating: [null, null, { enabled: true, minRisk: 0.6, onMissingEstimate: 'run' }],
|
|
152
|
+
})
|
|
153
|
+
const { hasIssues } = scan([measured])
|
|
154
|
+
expect(hasIssues.value).toBe(false)
|
|
155
|
+
})
|
|
156
|
+
|
|
145
157
|
// The regression this pins: the advisory carried its own "only a companion may be gated" rule,
|
|
146
158
|
// so when the engine generalised gating to `BUILTIN_GATABLE_KINDS` the shipped `pl_simple`
|
|
147
159
|
// ("Adaptive build" — an estimate-gated `architect`) was reported invalid in EVERY workspace.
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import { computed } from 'vue'
|
|
2
2
|
import type { Pipeline } from '~/types/domain'
|
|
3
3
|
import type { StepGating } from '~/types/consensus'
|
|
4
|
-
import { isBuiltinGatableKind } from '@cat-factory/contracts'
|
|
4
|
+
import { isBuiltinGatableKind, producesTaskEstimate } from '@cat-factory/contracts'
|
|
5
5
|
import { COMPANION_FOR_PRODUCER, isKnownAgentKind, isProducerCompanion } from '~/utils/catalog'
|
|
6
6
|
import { usePipelinesStore } from '~/stores/pipelines'
|
|
7
7
|
|
|
8
|
-
/** Estimate-gating consults a `task-estimator` step (mirrors the backend constant). */
|
|
9
|
-
const TASK_ESTIMATOR_KIND = 'task-estimator'
|
|
10
|
-
|
|
11
8
|
export type PipelineProblemType = 'unknown-kind' | 'shape' | 'outdated' | 'retired'
|
|
12
9
|
|
|
13
10
|
export interface PipelineProblem {
|
|
@@ -137,9 +134,11 @@ function skipAxisProblem(
|
|
|
137
134
|
}
|
|
138
135
|
|
|
139
136
|
/**
|
|
140
|
-
* Estimate gating: the shared skip-axis rules, plus the two specific to an estimate
|
|
141
|
-
* axis threshold (with none the step would ALWAYS skip) and an enabled
|
|
142
|
-
* the chain (or the gate has nothing to consult). Mirrors `assertValidGating
|
|
137
|
+
* Estimate gating: the shared skip-axis rules, plus the two specific to an estimate: at least one
|
|
138
|
+
* axis threshold (with none the step would ALWAYS skip) and an enabled step that PRODUCES an
|
|
139
|
+
* estimate earlier in the chain (or the gate has nothing to consult). Mirrors `assertValidGating`,
|
|
140
|
+
* through the same `producesTaskEstimate` predicate, so neither surface can drift from the other
|
|
141
|
+
* about which kinds count.
|
|
143
142
|
*/
|
|
144
143
|
function gatingProblem(p: Pipeline): string | null {
|
|
145
144
|
const gating = p.gating
|
|
@@ -161,9 +160,9 @@ function gatingProblem(p: Pipeline): string | null {
|
|
|
161
160
|
}
|
|
162
161
|
const hasEstimator = kinds
|
|
163
162
|
.slice(0, i)
|
|
164
|
-
.some((k, j) => k
|
|
163
|
+
.some((k, j) => producesTaskEstimate(k) && isEnabledAt(p, j))
|
|
165
164
|
if (!hasEstimator) {
|
|
166
|
-
return `Step '${kind}' is gated on the estimate but no
|
|
165
|
+
return `Step '${kind}' is gated on the estimate but no step that produces one runs before it.`
|
|
167
166
|
}
|
|
168
167
|
}
|
|
169
168
|
return null
|
package/app/utils/catalog.ts
CHANGED
|
@@ -126,6 +126,24 @@ export const AGENT_ARCHETYPES: AgentArchetype[] = [
|
|
|
126
126
|
description:
|
|
127
127
|
'Triages the task after requirements are clarified — rates Complexity, Risk and Impact (0..1). Used to gate consensus and conditional companion steps, and shown as ratings on the task.',
|
|
128
128
|
},
|
|
129
|
+
{
|
|
130
|
+
// The estimator's retrospective twin: it reads the change that actually landed (read-only, in a
|
|
131
|
+
// container, on the run's pull request) and re-scores the same three axes. `advanced` rather
|
|
132
|
+
// than `intermediate`: an extra container run per task is not part of the everyday delivery
|
|
133
|
+
// loop, and the everyday reader wants the forecast, not the calibration.
|
|
134
|
+
kind: 'task-reassessor',
|
|
135
|
+
tier: 'advanced',
|
|
136
|
+
label: 'Task Reassessor',
|
|
137
|
+
icon: 'i-lucide-gauge-circle',
|
|
138
|
+
color: '#f59e0b',
|
|
139
|
+
category: 'review',
|
|
140
|
+
// Reads the pull request the run opened, so it only belongs where a pipeline ships code. A
|
|
141
|
+
// document, research, planning or review pipeline opens none, and the step would be offered
|
|
142
|
+
// only to be skipped for want of a change to measure.
|
|
143
|
+
purposes: ['build'],
|
|
144
|
+
description:
|
|
145
|
+
'Re-rates Complexity, Risk and Impact after the implementation lands, from the change that was actually made. Place it after the coder: it corrects the estimator’s forecast, or produces the ratings for the first time in a pipeline that has no estimator.',
|
|
146
|
+
},
|
|
129
147
|
{
|
|
130
148
|
kind: 'requirements-brainstorm',
|
|
131
149
|
tier: 'intermediate',
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
ESTIMATE_AXIS_FIELD,
|
|
5
5
|
ESTIMATE_AXIS_HINT_KEYS,
|
|
6
6
|
ESTIMATE_AXIS_LABEL_KEYS,
|
|
7
|
+
estimateBasisLabelKey,
|
|
7
8
|
parseAxisThreshold,
|
|
8
9
|
} from './estimateGating'
|
|
9
10
|
|
|
@@ -42,3 +43,24 @@ describe('estimate axis vocabulary', () => {
|
|
|
42
43
|
expect(new Set(hints).size).toBe(ESTIMATE_AXES.length)
|
|
43
44
|
})
|
|
44
45
|
})
|
|
46
|
+
|
|
47
|
+
describe('estimate basis labels', () => {
|
|
48
|
+
it('labels a stored basis this build knows', () => {
|
|
49
|
+
expect(estimateBasisLabelKey('predicted')).toBe('inspector.estimate.basis.predicted')
|
|
50
|
+
expect(estimateBasisLabelKey('observed')).toBe('inspector.estimate.basis.observed')
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('reads an ABSENT basis as the forecast it was', () => {
|
|
54
|
+
// Every estimate written before the vocabulary existed came from the estimator, and those rows
|
|
55
|
+
// are read back with a plain `JSON.parse`, so the field is genuinely missing rather than
|
|
56
|
+
// defaulted on the way in.
|
|
57
|
+
expect(estimateBasisLabelKey(undefined)).toBe('inspector.estimate.basis.predicted')
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('says so for a basis this bundle cannot name, instead of guessing', () => {
|
|
61
|
+
// A browser holds a bundle older than the member it reads. Guessing onto a current member would
|
|
62
|
+
// relabel a measurement as a forecast with nothing on screen to say so.
|
|
63
|
+
expect(estimateBasisLabelKey('sampled')).toBe('inspector.estimate.basis.unknown')
|
|
64
|
+
expect(estimateBasisLabelKey('')).toBe('inspector.estimate.basis.unknown')
|
|
65
|
+
})
|
|
66
|
+
})
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { isTaskEstimateBasis, type TaskEstimateBasis } from '@cat-factory/contracts'
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* The three axes a `task-estimator` step scores a task on, and the presentation vocabulary every
|
|
3
5
|
* surface that lets a human gate work on them shares.
|
|
@@ -58,3 +60,33 @@ export function parseAxisThreshold(raw: string): number | undefined {
|
|
|
58
60
|
if (!Number.isFinite(parsed)) return undefined
|
|
59
61
|
return Math.min(1, Math.max(0, parsed))
|
|
60
62
|
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Basis → the label key saying what a stored estimate's scores were formed ON. Three cases, and
|
|
66
|
+
* they are three because each states a different fact:
|
|
67
|
+
*
|
|
68
|
+
* - ABSENT: a row written before the basis vocabulary existed. Every one of those came from the
|
|
69
|
+
* estimator, so calling it a forecast is a fact about the row rather than a default standing in
|
|
70
|
+
* for one. `null` is the same case: the field is optional on the schema, but the record travels
|
|
71
|
+
* as JSON and an absent value is routinely written back as `null`, so reading that as
|
|
72
|
+
* unrecognised would relabel an ordinary old forecast.
|
|
73
|
+
* - a member this bundle KNOWS: its own label.
|
|
74
|
+
* - anything else: said out loud. `basis` is persisted and read back with no schema pass, and a
|
|
75
|
+
* browser holds a bundle older than the member it reads, so guessing onto a current member would
|
|
76
|
+
* relabel a measurement as a forecast (or the reverse) with nothing on screen to say so.
|
|
77
|
+
*
|
|
78
|
+
* The keys are LITERAL so the typed-message-key check sees them, and the map is exhaustive over the
|
|
79
|
+
* contracts union, so a third basis fails the typecheck here rather than rendering a raw key.
|
|
80
|
+
*/
|
|
81
|
+
const ESTIMATE_BASIS_LABEL_KEYS: Record<TaskEstimateBasis, string> = {
|
|
82
|
+
predicted: 'inspector.estimate.basis.predicted',
|
|
83
|
+
observed: 'inspector.estimate.basis.observed',
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const ESTIMATE_BASIS_UNKNOWN_KEY = 'inspector.estimate.basis.unknown'
|
|
87
|
+
|
|
88
|
+
/** The label key for a stored basis: see {@link ESTIMATE_BASIS_LABEL_KEYS} for the three cases. */
|
|
89
|
+
export function estimateBasisLabelKey(basis: string | null | undefined): string {
|
|
90
|
+
if (basis === undefined || basis === null) return ESTIMATE_BASIS_LABEL_KEYS.predicted
|
|
91
|
+
return isTaskEstimateBasis(basis) ? ESTIMATE_BASIS_LABEL_KEYS[basis] : ESTIMATE_BASIS_UNKNOWN_KEY
|
|
92
|
+
}
|
|
@@ -319,6 +319,8 @@ export function stepSkipReasonKey(step: PipelineStep): string | null {
|
|
|
319
319
|
return 'pipeline.progress.skipped.producerSkipped'
|
|
320
320
|
case 'run_complete':
|
|
321
321
|
return 'pipeline.progress.skipped.runComplete'
|
|
322
|
+
case 'no_pull_request':
|
|
323
|
+
return 'pipeline.progress.skipped.noPullRequest'
|
|
322
324
|
case 'condition':
|
|
323
325
|
return step.stepOptions?.condition?.serviceScope === 'frontend'
|
|
324
326
|
? 'pipeline.progress.skipped.conditionFrontend'
|
package/i18n/locales/de.json
CHANGED
|
@@ -1724,10 +1724,17 @@
|
|
|
1724
1724
|
},
|
|
1725
1725
|
"estimate": {
|
|
1726
1726
|
"title": "Schätzung",
|
|
1727
|
-
"hint": "
|
|
1727
|
+
"hint": "Wie komplex, riskant und wirkungsvoll diese Aufgabe ist. Ein Task Estimator prognostiziert das vor Beginn der Arbeit, ein Task Reassessor misst es danach an der tatsächlich erfolgten Änderung. Wird verwendet, um zu entscheiden, ob Konsens-Schritte (Mehrfachläufe) und andere bedingte Schritte sich lohnen.",
|
|
1728
1728
|
"complexity": "Komplexität",
|
|
1729
1729
|
"risk": "Risiko",
|
|
1730
|
-
"impact": "Wirkung"
|
|
1730
|
+
"impact": "Wirkung",
|
|
1731
|
+
"basis": {
|
|
1732
|
+
"predicted": "Prognose vor Beginn der Arbeit",
|
|
1733
|
+
"observed": "Gemessen an der erfolgten Änderung",
|
|
1734
|
+
"unknown": "Von einer anderen App-Version erfasst"
|
|
1735
|
+
},
|
|
1736
|
+
"was": "vorher {value}",
|
|
1737
|
+
"supersededBasis": "Ersetzt: {basis}"
|
|
1731
1738
|
},
|
|
1732
1739
|
"reviewTarget": {
|
|
1733
1740
|
"title": "Geprüfter Pull Request",
|
|
@@ -4739,6 +4746,7 @@
|
|
|
4739
4746
|
"conditionBackend": "Übersprungen: Diese Aufgabe ändert nur einen Frontend-Dienst, es gibt also keine API dahinter zu prüfen.",
|
|
4740
4747
|
"producerSkipped": "Übersprungen: Der geprüfte Schritt wurde übersprungen, es gibt nichts zu bewerten.",
|
|
4741
4748
|
"runComplete": "Übersprungen: Der Lauf endete vor diesem Schritt, es blieb nichts zu tun.",
|
|
4749
|
+
"noPullRequest": "Übersprungen: Dieser Lauf hat keinen Pull Request eröffnet, also gibt es für diesen Schritt keine Änderung zu lesen.",
|
|
4742
4750
|
"unknown": "Übersprungen: Dieser Schritt wurde nicht ausgeführt."
|
|
4743
4751
|
}
|
|
4744
4752
|
},
|
package/i18n/locales/en.json
CHANGED
|
@@ -1231,10 +1231,17 @@
|
|
|
1231
1231
|
},
|
|
1232
1232
|
"estimate": {
|
|
1233
1233
|
"title": "Estimate",
|
|
1234
|
-
"hint": "
|
|
1234
|
+
"hint": "How complex, risky and impactful this task is. A Task Estimator forecasts it before the work starts; a Task Reassessor measures it afterwards from the change that landed. Used to decide whether consensus (multi-run) steps and other conditional steps are worth running.",
|
|
1235
1235
|
"complexity": "Complexity",
|
|
1236
1236
|
"risk": "Risk",
|
|
1237
|
-
"impact": "Impact"
|
|
1237
|
+
"impact": "Impact",
|
|
1238
|
+
"basis": {
|
|
1239
|
+
"predicted": "Forecast before the work started",
|
|
1240
|
+
"observed": "Measured from the change that landed",
|
|
1241
|
+
"unknown": "Recorded by another version of the app"
|
|
1242
|
+
},
|
|
1243
|
+
"was": "was {value}",
|
|
1244
|
+
"supersededBasis": "Replaces: {basis}"
|
|
1238
1245
|
},
|
|
1239
1246
|
"reviewTarget": {
|
|
1240
1247
|
"title": "Under review",
|
|
@@ -5391,6 +5398,7 @@
|
|
|
5391
5398
|
"conditionBackend": "Skipped: this task changes only a frontend service, so there is no API behind it to exercise.",
|
|
5392
5399
|
"producerSkipped": "Skipped: the step it reviews was skipped, so there is nothing to grade.",
|
|
5393
5400
|
"runComplete": "Skipped: the run finished before this step, with nothing left to do.",
|
|
5401
|
+
"noPullRequest": "Skipped: this run opened no pull request, so there is no change for this step to read.",
|
|
5394
5402
|
"unknown": "Skipped: this step did not run."
|
|
5395
5403
|
}
|
|
5396
5404
|
},
|
package/i18n/locales/es.json
CHANGED
|
@@ -1138,10 +1138,17 @@
|
|
|
1138
1138
|
},
|
|
1139
1139
|
"estimate": {
|
|
1140
1140
|
"title": "Estimación",
|
|
1141
|
-
"hint": "
|
|
1141
|
+
"hint": "Lo compleja, arriesgada e impactante que es esta tarea. Un Task Estimator la pronostica antes de empezar el trabajo y un Task Reassessor la mide después a partir del cambio realizado. Se usa para decidir si merecen la pena los pasos de consenso (multiejecución) y otros pasos condicionales.",
|
|
1142
1142
|
"complexity": "Complejidad",
|
|
1143
1143
|
"risk": "Riesgo",
|
|
1144
|
-
"impact": "Impacto"
|
|
1144
|
+
"impact": "Impacto",
|
|
1145
|
+
"basis": {
|
|
1146
|
+
"predicted": "Pronóstico previo al inicio del trabajo",
|
|
1147
|
+
"observed": "Medido a partir del cambio realizado",
|
|
1148
|
+
"unknown": "Registrado por otra versión de la aplicación"
|
|
1149
|
+
},
|
|
1150
|
+
"was": "antes {value}",
|
|
1151
|
+
"supersededBasis": "Reemplaza: {basis}"
|
|
1145
1152
|
},
|
|
1146
1153
|
"reviewTarget": {
|
|
1147
1154
|
"title": "Pull request en revisión",
|
|
@@ -5215,6 +5222,7 @@
|
|
|
5215
5222
|
"conditionBackend": "Omitido: esta tarea solo modifica un servicio de frontend, así que no hay API detrás que probar.",
|
|
5216
5223
|
"producerSkipped": "Omitido: el paso que revisa fue omitido, así que no hay nada que evaluar.",
|
|
5217
5224
|
"runComplete": "Omitido: la ejecución terminó antes de este paso y no quedaba nada que hacer.",
|
|
5225
|
+
"noPullRequest": "Omitido: esta ejecución no abrió ningún pull request, así que este paso no tiene ningún cambio que leer.",
|
|
5218
5226
|
"unknown": "Omitido: este paso no se ejecutó."
|
|
5219
5227
|
}
|
|
5220
5228
|
},
|
package/i18n/locales/fr.json
CHANGED
|
@@ -1138,10 +1138,17 @@
|
|
|
1138
1138
|
},
|
|
1139
1139
|
"estimate": {
|
|
1140
1140
|
"title": "Estimation",
|
|
1141
|
-
"hint": "
|
|
1141
|
+
"hint": "La complexité, le risque et l'impact de cette tâche. Un Task Estimator les prévoit avant le début du travail, un Task Reassessor les mesure ensuite d'après la modification réellement livrée. Sert à décider si les étapes de consensus (multi-exécutions) et les autres étapes conditionnelles en valent la peine.",
|
|
1142
1142
|
"complexity": "Complexité",
|
|
1143
1143
|
"risk": "Risque",
|
|
1144
|
-
"impact": "Impact"
|
|
1144
|
+
"impact": "Impact",
|
|
1145
|
+
"basis": {
|
|
1146
|
+
"predicted": "Prévision avant le début du travail",
|
|
1147
|
+
"observed": "Mesuré d'après la modification livrée",
|
|
1148
|
+
"unknown": "Enregistré par une autre version de l'application"
|
|
1149
|
+
},
|
|
1150
|
+
"was": "avant {value}",
|
|
1151
|
+
"supersededBasis": "Remplace : {basis}"
|
|
1145
1152
|
},
|
|
1146
1153
|
"reviewTarget": {
|
|
1147
1154
|
"title": "Pull request en revue",
|
|
@@ -5215,6 +5222,7 @@
|
|
|
5215
5222
|
"conditionBackend": "Étape ignorée : cette tâche ne modifie qu’un service frontend, il n’y a donc pas d’API derrière à tester.",
|
|
5216
5223
|
"producerSkipped": "Étape ignorée : l’étape qu’elle relit a été ignorée, il n’y a rien à évaluer.",
|
|
5217
5224
|
"runComplete": "Étape ignorée : l’exécution s’est terminée avant elle, sans rien à faire.",
|
|
5225
|
+
"noPullRequest": "Étape ignorée : cette exécution n’a ouvert aucune pull request, il n’y a donc aucune modification à lire.",
|
|
5218
5226
|
"unknown": "Étape ignorée : elle n’a pas été exécutée."
|
|
5219
5227
|
}
|
|
5220
5228
|
},
|
package/i18n/locales/he.json
CHANGED
|
@@ -1138,10 +1138,17 @@
|
|
|
1138
1138
|
},
|
|
1139
1139
|
"estimate": {
|
|
1140
1140
|
"title": "הערכה",
|
|
1141
|
-
"hint": "
|
|
1141
|
+
"hint": "עד כמה המשימה הזו מורכבת, מסוכנת ומשפיעה. מעריך משימות חוזה זאת לפני תחילת העבודה, וסוכן ההערכה מחדש מודד זאת לאחר מכן מהשינוי שבוצע בפועל. משמש להחלטה אם שלבי קונצנזוס (ריצות מרובות) ושלבים מותנים אחרים שווים את המחיר.",
|
|
1142
1142
|
"complexity": "מורכבות",
|
|
1143
1143
|
"risk": "סיכון",
|
|
1144
|
-
"impact": "השפעה"
|
|
1144
|
+
"impact": "השפעה",
|
|
1145
|
+
"basis": {
|
|
1146
|
+
"predicted": "תחזית לפני תחילת העבודה",
|
|
1147
|
+
"observed": "נמדד מהשינוי שבוצע",
|
|
1148
|
+
"unknown": "נרשם בגרסה אחרת של האפליקציה"
|
|
1149
|
+
},
|
|
1150
|
+
"was": "היה {value}",
|
|
1151
|
+
"supersededBasis": "מחליף: {basis}"
|
|
1145
1152
|
},
|
|
1146
1153
|
"reviewTarget": {
|
|
1147
1154
|
"title": "בקשת משיכה בסקירה",
|
|
@@ -5215,6 +5222,7 @@
|
|
|
5215
5222
|
"conditionBackend": "דולג: המשימה משנה רק שירות צד-לקוח, לכן אין מאחוריו API לבדיקה.",
|
|
5216
5223
|
"producerSkipped": "דולג: השלב שהוא בודק דולג, לכן אין מה להעריך.",
|
|
5217
5224
|
"runComplete": "דולג: הריצה הסתיימה לפני השלב הזה, ולא נותר מה לעשות.",
|
|
5225
|
+
"noPullRequest": "דולג: הריצה הזו לא פתחה pull request, ולכן אין לשלב הזה שינוי לקרוא.",
|
|
5218
5226
|
"unknown": "דולג: השלב הזה לא רץ."
|
|
5219
5227
|
}
|
|
5220
5228
|
},
|
package/i18n/locales/it.json
CHANGED
|
@@ -1724,10 +1724,17 @@
|
|
|
1724
1724
|
},
|
|
1725
1725
|
"estimate": {
|
|
1726
1726
|
"title": "Stima",
|
|
1727
|
-
"hint": "
|
|
1727
|
+
"hint": "Quanto questa attivita' e' complessa, rischiosa e di impatto. Un Task Estimator la prevede prima che il lavoro inizi, un Task Reassessor la misura dopo, dalla modifica effettivamente realizzata. Usata per decidere se vale la pena eseguire i passaggi di consenso (multi-esecuzione) e gli altri passaggi condizionali.",
|
|
1728
1728
|
"complexity": "Complessita'",
|
|
1729
1729
|
"risk": "Rischio",
|
|
1730
|
-
"impact": "Impatto"
|
|
1730
|
+
"impact": "Impatto",
|
|
1731
|
+
"basis": {
|
|
1732
|
+
"predicted": "Previsione prima dell'inizio del lavoro",
|
|
1733
|
+
"observed": "Misurato dalla modifica realizzata",
|
|
1734
|
+
"unknown": "Registrato da un'altra versione dell'app"
|
|
1735
|
+
},
|
|
1736
|
+
"was": "prima {value}",
|
|
1737
|
+
"supersededBasis": "Sostituisce: {basis}"
|
|
1731
1738
|
},
|
|
1732
1739
|
"reviewTarget": {
|
|
1733
1740
|
"title": "Pull request in revisione",
|
|
@@ -4739,6 +4746,7 @@
|
|
|
4739
4746
|
"conditionBackend": "Saltato: questa attività modifica solo un servizio frontend, quindi non c’è un’API dietro da provare.",
|
|
4740
4747
|
"producerSkipped": "Saltato: il passo che revisiona è stato saltato, quindi non c’è nulla da valutare.",
|
|
4741
4748
|
"runComplete": "Saltato: l’esecuzione è terminata prima di questo passo, senza altro da fare.",
|
|
4749
|
+
"noPullRequest": "Saltato: questa esecuzione non ha aperto alcuna pull request, quindi questo passo non ha modifiche da leggere.",
|
|
4742
4750
|
"unknown": "Saltato: questo passo non è stato eseguito."
|
|
4743
4751
|
}
|
|
4744
4752
|
},
|
package/i18n/locales/ja.json
CHANGED
|
@@ -1138,10 +1138,17 @@
|
|
|
1138
1138
|
},
|
|
1139
1139
|
"estimate": {
|
|
1140
1140
|
"title": "見積もり",
|
|
1141
|
-
"hint": "
|
|
1141
|
+
"hint": "このタスクの複雑さ・リスク・影響度です。Task Estimator が作業開始前に予測し、Task Reassessor が実際に入った変更から事後に測定します。コンセンサス(複数実行)ステップやその他の条件付きステップを実行する価値があるかの判断に使われます。",
|
|
1142
1142
|
"complexity": "複雑度",
|
|
1143
1143
|
"risk": "リスク",
|
|
1144
|
-
"impact": "影響度"
|
|
1144
|
+
"impact": "影響度",
|
|
1145
|
+
"basis": {
|
|
1146
|
+
"predicted": "作業開始前の予測",
|
|
1147
|
+
"observed": "実際に入った変更から測定",
|
|
1148
|
+
"unknown": "別のバージョンのアプリが記録"
|
|
1149
|
+
},
|
|
1150
|
+
"was": "以前は {value}",
|
|
1151
|
+
"supersededBasis": "置き換え:{basis}"
|
|
1145
1152
|
},
|
|
1146
1153
|
"reviewTarget": {
|
|
1147
1154
|
"title": "レビュー対象のプルリクエスト",
|
|
@@ -5215,6 +5222,7 @@
|
|
|
5215
5222
|
"conditionBackend": "スキップ:このタスクはフロントエンドサービスのみを変更するため、背後に検証するAPIがありません。",
|
|
5216
5223
|
"producerSkipped": "スキップ:レビュー対象のステップがスキップされたため、評価するものがありません。",
|
|
5217
5224
|
"runComplete": "スキップ:このステップの前に実行が終了し、行う作業が残っていませんでした。",
|
|
5225
|
+
"noPullRequest": "スキップ:この実行はプルリクエストを作成しなかったため、このステップが読み取る変更がありません。",
|
|
5218
5226
|
"unknown": "スキップ:このステップは実行されませんでした。"
|
|
5219
5227
|
}
|
|
5220
5228
|
},
|
package/i18n/locales/pl.json
CHANGED
|
@@ -1138,10 +1138,17 @@
|
|
|
1138
1138
|
},
|
|
1139
1139
|
"estimate": {
|
|
1140
1140
|
"title": "Szacunek",
|
|
1141
|
-
"hint": "
|
|
1141
|
+
"hint": "Jak złożone, ryzykowne i wpływowe jest to zadanie. Task Estimator prognozuje to przed rozpoczęciem pracy, a Task Reassessor mierzy to później na podstawie faktycznie wprowadzonej zmiany. Służy do decydowania, czy warto uruchamiać kroki konsensusu (wielokrotne przebiegi) i inne kroki warunkowe.",
|
|
1142
1142
|
"complexity": "Złożoność",
|
|
1143
1143
|
"risk": "Ryzyko",
|
|
1144
|
-
"impact": "Wpływ"
|
|
1144
|
+
"impact": "Wpływ",
|
|
1145
|
+
"basis": {
|
|
1146
|
+
"predicted": "Prognoza przed rozpoczęciem pracy",
|
|
1147
|
+
"observed": "Zmierzone na podstawie wprowadzonej zmiany",
|
|
1148
|
+
"unknown": "Zapisane przez inną wersję aplikacji"
|
|
1149
|
+
},
|
|
1150
|
+
"was": "wcześniej {value}",
|
|
1151
|
+
"supersededBasis": "Zastępuje: {basis}"
|
|
1145
1152
|
},
|
|
1146
1153
|
"reviewTarget": {
|
|
1147
1154
|
"title": "Przeglądany pull request",
|
|
@@ -5215,6 +5222,7 @@
|
|
|
5215
5222
|
"conditionBackend": "Pominięto: to zadanie zmienia tylko usługę frontendową, więc nie ma za nią API do sprawdzenia.",
|
|
5216
5223
|
"producerSkipped": "Pominięto: krok, który ocenia, został pominięty, więc nie ma czego oceniać.",
|
|
5217
5224
|
"runComplete": "Pominięto: przebieg zakończył się przed tym krokiem, nie było nic do zrobienia.",
|
|
5225
|
+
"noPullRequest": "Pominięto: ten przebieg nie otworzył żadnego pull requesta, więc ten krok nie ma zmiany do przeczytania.",
|
|
5218
5226
|
"unknown": "Pominięto: ten krok nie został wykonany."
|
|
5219
5227
|
}
|
|
5220
5228
|
},
|
package/i18n/locales/tr.json
CHANGED
|
@@ -1138,10 +1138,17 @@
|
|
|
1138
1138
|
},
|
|
1139
1139
|
"estimate": {
|
|
1140
1140
|
"title": "Tahmin",
|
|
1141
|
-
"hint": "
|
|
1141
|
+
"hint": "Bu görevin ne kadar karmaşık, riskli ve etkili olduğu. Görev Tahmincisi işe başlamadan önce öngörür, Görev Yeniden Değerlendiricisi ise sonrasında gerçekte yapılan değişiklikten ölçer. Uzlaşma (çok çalıştırmalı) adımlarının ve diğer koşullu adımların değip değmeyeceğine karar vermek için kullanılır.",
|
|
1142
1142
|
"complexity": "Karmaşıklık",
|
|
1143
1143
|
"risk": "Risk",
|
|
1144
|
-
"impact": "Etki"
|
|
1144
|
+
"impact": "Etki",
|
|
1145
|
+
"basis": {
|
|
1146
|
+
"predicted": "İşe başlamadan önceki tahmin",
|
|
1147
|
+
"observed": "Yapılan değişiklikten ölçüldü",
|
|
1148
|
+
"unknown": "Uygulamanın başka bir sürümü kaydetti"
|
|
1149
|
+
},
|
|
1150
|
+
"was": "önceki {value}",
|
|
1151
|
+
"supersededBasis": "Şunu değiştirir: {basis}"
|
|
1145
1152
|
},
|
|
1146
1153
|
"reviewTarget": {
|
|
1147
1154
|
"title": "İncelenen pull request",
|
|
@@ -5215,6 +5222,7 @@
|
|
|
5215
5222
|
"conditionBackend": "Atlandı: bu görev yalnızca bir frontend servisini değiştiriyor, dolayısıyla arkasında denenecek bir API yok.",
|
|
5216
5223
|
"producerSkipped": "Atlandı: incelediği adım atlandı, dolayısıyla değerlendirilecek bir şey yok.",
|
|
5217
5224
|
"runComplete": "Atlandı: çalışma bu adımdan önce sona erdi, yapılacak bir şey kalmadı.",
|
|
5225
|
+
"noPullRequest": "Atlandı: bu çalışma bir pull request açmadı, bu nedenle bu adımın okuyacağı bir değişiklik yok.",
|
|
5218
5226
|
"unknown": "Atlandı: bu adım çalışmadı."
|
|
5219
5227
|
}
|
|
5220
5228
|
},
|
package/i18n/locales/uk.json
CHANGED
|
@@ -1138,10 +1138,17 @@
|
|
|
1138
1138
|
},
|
|
1139
1139
|
"estimate": {
|
|
1140
1140
|
"title": "Оцінка",
|
|
1141
|
-
"hint": "
|
|
1141
|
+
"hint": "Наскільки складне, ризиковане та впливове це завдання. Task Estimator прогнозує це до початку роботи, а Task Reassessor вимірює це згодом за фактично внесеною зміною. Використовується, щоб вирішити, чи варті кроки консенсусу (кілька запусків) та інші умовні кроки.",
|
|
1142
1142
|
"complexity": "Складність",
|
|
1143
1143
|
"risk": "Ризик",
|
|
1144
|
-
"impact": "Вплив"
|
|
1144
|
+
"impact": "Вплив",
|
|
1145
|
+
"basis": {
|
|
1146
|
+
"predicted": "Прогноз до початку роботи",
|
|
1147
|
+
"observed": "Виміряно за внесеною зміною",
|
|
1148
|
+
"unknown": "Записано іншою версією застосунку"
|
|
1149
|
+
},
|
|
1150
|
+
"was": "було {value}",
|
|
1151
|
+
"supersededBasis": "Замінює: {basis}"
|
|
1145
1152
|
},
|
|
1146
1153
|
"reviewTarget": {
|
|
1147
1154
|
"title": "Pull request на огляді",
|
|
@@ -5215,6 +5222,7 @@
|
|
|
5215
5222
|
"conditionBackend": "Пропущено: це завдання змінює лише фронтенд-сервіс, тож за ним немає API для перевірки.",
|
|
5216
5223
|
"producerSkipped": "Пропущено: крок, який він перевіряє, був пропущений, тож немає чого оцінювати.",
|
|
5217
5224
|
"runComplete": "Пропущено: запуск завершився до цього кроку, робити було нічого.",
|
|
5225
|
+
"noPullRequest": "Пропущено: цей запуск не відкрив pull request, тож цьому кроку нічого читати.",
|
|
5218
5226
|
"unknown": "Пропущено: цей крок не виконувався."
|
|
5219
5227
|
}
|
|
5220
5228
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.283.0",
|
|
4
4
|
"description": "Reusable Nuxt layer for the Agent Architecture Board SPA (components, stores, composables, pages). Consume it from a thin deployment app via `extends: ['@cat-factory/app']` and point it at your backend with NUXT_PUBLIC_API_BASE. See deploy/frontend for an example.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"valibot": "^1.4.2",
|
|
41
41
|
"vue": "3.5.41",
|
|
42
42
|
"wretch": "^3.0.9",
|
|
43
|
-
"@cat-factory/contracts": "0.
|
|
43
|
+
"@cat-factory/contracts": "0.325.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@toad-contracts/testing": "0.3.2",
|