peaks-loop 4.0.48 → 4.0.49
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/CHANGELOG.md +20 -0
- package/README-en.md +1 -1
- package/README.md +1 -1
- package/dist/cli/commands/compact-command.js +1 -3
- package/dist/cli/commands/feedback-commands.d.ts +11 -7
- package/dist/cli/commands/feedback-commands.js +49 -17
- package/dist/cli/commands/final-review-commands.js +12 -0
- package/dist/cli/commands/loop-eval-commands.js +22 -6
- package/dist/cli/commands/slice-integrate-commands.js +17 -0
- package/dist/services/artifacts/artifact-prerequisites.js +10 -0
- package/dist/services/artifacts/request-artifact-service.js +59 -38
- package/dist/services/audit/enforcers/active-skill-resolver.js +14 -1
- package/dist/services/code/auto-compact-lifecycle.d.ts +75 -0
- package/dist/services/code/auto-compact-lifecycle.js +65 -16
- package/dist/services/code/auto-compact-orchestrator.js +119 -19
- package/dist/services/code/compact-event-settle.d.ts +20 -8
- package/dist/services/code/compact-event-settle.js +21 -0
- package/dist/services/compact-statusline/compact-statusline-service.js +56 -22
- package/dist/services/context/auto-compact-types.d.ts +20 -2
- package/dist/services/feedback/feedback-promotion-service.d.ts +137 -14
- package/dist/services/feedback/feedback-promotion-service.js +341 -20
- package/dist/services/feedback/promotion-artifact-evidence.d.ts +69 -0
- package/dist/services/feedback/promotion-artifact-evidence.js +332 -0
- package/dist/services/job/job-progress-store.js +18 -3
- package/dist/services/observability/jsonl-store.d.ts +19 -0
- package/dist/services/observability/jsonl-store.js +27 -2
- package/dist/services/observability/observability-service.d.ts +10 -3
- package/dist/services/observability/observability-service.js +16 -3
- package/dist/services/prd/handoff-service.js +43 -0
- package/dist/services/qa/qa-business-review-state.js +19 -5
- package/dist/services/sc/sc-service.d.ts +8 -0
- package/dist/services/sc/sc-service.js +8 -1
- package/dist/services/session/getSessionDir.d.ts +33 -0
- package/dist/services/session/getSessionDir.js +60 -0
- package/dist/services/slice/slice-review-state.js +19 -4
- package/dist/services/workflow/pipeline-verify-gate-support.js +10 -11
- package/dist/services/workflow/pipeline-verify-service.d.ts +1 -1
- package/dist/services/workflow/pipeline-verify-service.js +23 -10
- package/dist/services/workflow/pipeline-verify-types.d.ts +5 -3
- package/dist/shared/runtime-root.d.ts +73 -0
- package/dist/shared/runtime-root.js +77 -0
- package/package.json +5 -5
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
//
|
|
10
10
|
// Decision priority (explicit, no implicit fall-through):
|
|
11
11
|
// 1. lifecycle missing → fall back to legacy (pending → queued,
|
|
12
|
-
// recent history → completed WITHOUT an invented
|
|
13
|
-
// else none)
|
|
12
|
+
// a recent `observed` history row → completed WITHOUT an invented
|
|
13
|
+
// after-ratio, else none)
|
|
14
14
|
// 2. lifecycle invalid → 'invalid' (NEVER fall back to legacy
|
|
15
15
|
// — a corrupted lifecycle is not a green progress bar)
|
|
16
16
|
// 3. lifecycle valid → map stage to filledCells via the
|
|
@@ -37,9 +37,10 @@
|
|
|
37
37
|
// ratios. After-ratio is only rendered when the lifecycle record
|
|
38
38
|
// carries a real one; otherwise the bar shows a stable "no
|
|
39
39
|
// measurement" hint.
|
|
40
|
-
import { existsSync, readFileSync
|
|
40
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
41
41
|
import { getSessionDir } from '../session/getSessionDir.js';
|
|
42
42
|
import { AUTO_COMPACT_RED_LINE_RATIO } from '../context/auto-compact-types.js';
|
|
43
|
+
import { readCompactHistory } from '../compact-history/compact-history-service.js';
|
|
43
44
|
import { readCompactLifecycle, } from './compact-lifecycle-store.js';
|
|
44
45
|
/**
|
|
45
46
|
* Concrete first-version stale timeout. Adjustable after real timing
|
|
@@ -58,7 +59,12 @@ const DEFAULT_STALE_AFTER_MS = 120_000;
|
|
|
58
59
|
* to not flap on subsequent reads. Adjustable after real timing feedback.
|
|
59
60
|
*/
|
|
60
61
|
export const COMPLETED_EXPIRY_MS = 10_000;
|
|
61
|
-
/**
|
|
62
|
+
/**
|
|
63
|
+
* How recently the last history row must itself have been written for the
|
|
64
|
+
* legacy path to report it as "just compacted". Measured against the row's own
|
|
65
|
+
* `ts` — the fact — rather than the file's mtime, which is only a proxy for it
|
|
66
|
+
* and is also moved by rows that record no compaction (repair R9).
|
|
67
|
+
*/
|
|
62
68
|
const LEGACY_JUST_COMPACTED_WINDOW_MS = 30_000;
|
|
63
69
|
// PRD-002b slice 2 — extract cell-table magic numbers (4/6/8) into named
|
|
64
70
|
// consts so the no-magic-numbers lint rule stops flagging the typed
|
|
@@ -142,6 +148,7 @@ export function decideCompactStatusline(input) {
|
|
|
142
148
|
// lifecycle.kind === 'missing' → fall back to legacy files.
|
|
143
149
|
return decideLegacyFallback({
|
|
144
150
|
projectRoot: input.projectRoot,
|
|
151
|
+
sessionId: input.sessionId,
|
|
145
152
|
sessionDir,
|
|
146
153
|
now: input.now,
|
|
147
154
|
});
|
|
@@ -212,26 +219,53 @@ function decideLegacyFallback(input) {
|
|
|
212
219
|
// fall through to history check
|
|
213
220
|
}
|
|
214
221
|
}
|
|
215
|
-
// Priority 2 within legacy: a
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
222
|
+
// Priority 2 within legacy: a history row TESTIFIES that a compaction was
|
|
223
|
+
// witnessed, recently enough to still be the one being reported.
|
|
224
|
+
//
|
|
225
|
+
// Repair R9 (AC4). This used to read the file's mtime — freshness taken as
|
|
226
|
+
// evidence that "a compact just landed". Freshness is evidence of neither:
|
|
227
|
+
// the same file takes a `dispatch` row every time peaks-loop ASKS for a
|
|
228
|
+
// compact, and an ask is an intent, not an outcome. One real session
|
|
229
|
+
// (2026-09-13, ~15.5 h) holds 1075 dispatch rows and ZERO compactions
|
|
230
|
+
// (`auto-compact-orchestrator.ts`), so a fresh file was the NORMAL state of a
|
|
231
|
+
// session in which nothing had compacted at all — and each of those asks
|
|
232
|
+
// painted this 8-cell "completed" bar.
|
|
233
|
+
//
|
|
234
|
+
// So the row's own testimony is read instead, through the same reader the CLI
|
|
235
|
+
// uses. Only `kind: 'observed'` means a compaction was witnessed (a row with
|
|
236
|
+
// no `kind` is a dispatch — every pre-`kind` row is one), and the row's `ts`
|
|
237
|
+
// is the moment compared, not the filesystem's.
|
|
238
|
+
//
|
|
239
|
+
// Repair R11. The testimony is looked for in EVERY row inside the window, not
|
|
240
|
+
// only in the last one. Reading the last row alone made the indicator depend
|
|
241
|
+
// on the ASK: a `dispatch` row lands on every probe, so an `observed` row
|
|
242
|
+
// stopped counting the moment peaks-loop asked again — `[observed, dispatch]`
|
|
243
|
+
// one second apart answered `none` for a compaction that had just been
|
|
244
|
+
// witnessed — i.e. it deleted the very indicator the mtime read had shown,
|
|
245
|
+
// the one the replacement was meant to keep honest. A `dispatch` row alone
|
|
246
|
+
// still testifies
|
|
247
|
+
// to nothing (the direction R9 closed): what is required is an `observed` row
|
|
248
|
+
// inside the window, wherever in the file it sits.
|
|
249
|
+
try {
|
|
250
|
+
// The reader answers `file-missing` / `empty` itself; the `catch` is for the
|
|
251
|
+
// read itself, which it does not guard.
|
|
252
|
+
const read = readCompactHistory({ projectRoot: input.projectRoot, sessionId: input.sessionId });
|
|
253
|
+
const witnessed = read.kind === 'ok' &&
|
|
254
|
+
read.events.some((row) => row.kind === 'observed' && now - Date.parse(row.ts) <= LEGACY_JUST_COMPACTED_WINDOW_MS);
|
|
255
|
+
if (witnessed) {
|
|
256
|
+
// CRITICAL: no invented after-ratio. The row may carry a measured
|
|
257
|
+
// afterRatio, but this is the legacy path and we honour the
|
|
258
|
+
// "no measurement" default.
|
|
259
|
+
return {
|
|
260
|
+
kind: 'completed',
|
|
261
|
+
filledCells: 8,
|
|
262
|
+
detail: historyPath,
|
|
263
|
+
};
|
|
233
264
|
}
|
|
234
265
|
}
|
|
266
|
+
catch {
|
|
267
|
+
// fall through to idle
|
|
268
|
+
}
|
|
235
269
|
return { kind: 'none', filledCells: 0 };
|
|
236
270
|
}
|
|
237
271
|
/**
|
|
@@ -128,13 +128,31 @@ export type AutoCompactResult = {
|
|
|
128
128
|
readonly nextActions: readonly string[];
|
|
129
129
|
} | {
|
|
130
130
|
readonly ok: true;
|
|
131
|
-
readonly code: 'AUTO_COMPACT_SKIP' | 'AUTO_COMPACT_WAIT';
|
|
131
|
+
readonly code: 'AUTO_COMPACT_SKIP' | 'AUTO_COMPACT_WAIT' | 'AUTO_COMPACT_ALREADY_ARMED' | 'AUTO_COMPACT_UNRESOLVED_SESSION';
|
|
132
132
|
readonly message: string;
|
|
133
133
|
readonly data: {
|
|
134
134
|
readonly sessionId: string;
|
|
135
135
|
readonly ratio: number;
|
|
136
136
|
readonly source: string;
|
|
137
|
-
|
|
137
|
+
/**
|
|
138
|
+
* `unresolved-session` (repair R6): the session id named no session
|
|
139
|
+
* directory, so the compact backoff's question — "is an attempt already
|
|
140
|
+
* outstanding?" — could not be asked. It is NOT `already-armed` (no run
|
|
141
|
+
* was found; the record could not be read at all) and NOT an admit: the
|
|
142
|
+
* dispatch is left undone because an unanswerable question is not a
|
|
143
|
+
* "no", and admitting on one is how a gate ends up reading a string
|
|
144
|
+
* instead of the artifact the string names.
|
|
145
|
+
*/
|
|
146
|
+
readonly decision: 'below-threshold' | 'in-flight-batch' | 'already-armed' | 'unresolved-session';
|
|
147
|
+
/**
|
|
148
|
+
* rid `2026-09-14-compact-dispatch-backoff`, `already-armed` only: the
|
|
149
|
+
* ratio the open run was dispatched at, and its id. `ratio` above is the
|
|
150
|
+
* LIVE reading — the pair is what keeps "it is still high" legible after
|
|
151
|
+
* the backoff drops the per-probe rows: the ask is at `armedAtRatio`, and
|
|
152
|
+
* the context is now at `ratio`, above it and not yet compacted.
|
|
153
|
+
*/
|
|
154
|
+
readonly armedAtRatio?: number;
|
|
155
|
+
readonly armedRunId?: string;
|
|
138
156
|
/**
|
|
139
157
|
* Slice 2026-09-13-auto-compact-trigger-ownership: what syncing the
|
|
140
158
|
* harness auto-compact window did on this probe. `null` = the active
|
|
@@ -8,23 +8,27 @@
|
|
|
8
8
|
* primitive behind the `peaks feedback promote` and
|
|
9
9
|
* `peaks feedback check-unpromoted` CLI commands.
|
|
10
10
|
*
|
|
11
|
-
* Promotion tracking convention
|
|
12
|
-
* "promoted" when one of the following is true:
|
|
11
|
+
* Promotion tracking convention — two parts, and BOTH are required:
|
|
13
12
|
*
|
|
14
|
-
* (a)
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
13
|
+
* (a) A MARKER, either an HTML comment near the top of the body
|
|
14
|
+
* (`<!-- peaks-feedback-promoted: layer=<A|B|C> -->`) or a sibling
|
|
15
|
+
* `.peaks/memory/<name>.promotion.json` sidecar with
|
|
16
|
+
* `{ layer: "A" | "B" | "C", ... }`. Written by `peaks feedback
|
|
17
|
+
* promote` so a single read of the memory file is enough to see the
|
|
18
|
+
* claimed layer.
|
|
18
19
|
*
|
|
19
|
-
* (b)
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
20
|
+
* (b) The ARTIFACT that layer implies — see `promotionArtifactChecks`.
|
|
21
|
+
* rid 2026-09-14-gate-h-promotion: the marker alone used to count,
|
|
22
|
+
* which made the gate self-certifying, because the only thing a marker
|
|
23
|
+
* proves is that `peaks feedback promote` ran. Every layer-A marker in
|
|
24
|
+
* this repo pointed at `sops/<name>.md`, a file that did not exist and
|
|
25
|
+
* that no engine reads.
|
|
23
26
|
*
|
|
24
|
-
* The comment marker is the SOURCE OF TRUTH for human review; the
|
|
25
|
-
*
|
|
26
|
-
* to mark a feedback memory as promoted.
|
|
27
|
+
* The comment marker is the SOURCE OF TRUTH for human review; the sidecar is
|
|
28
|
+
* the source of truth for the scanner. Neither is evidence on its own.
|
|
27
29
|
*/
|
|
30
|
+
import { type PromotionArtifactCheck, type PromotionEvidence } from './promotion-artifact-evidence.js';
|
|
31
|
+
export type { PromotionArtifactCheck, PromotionEvidence };
|
|
28
32
|
export type PromotionLayer = 'A' | 'B' | 'C';
|
|
29
33
|
export declare const PROMOTION_LAYERS: readonly PromotionLayer[];
|
|
30
34
|
export type PromotionLayerDetail = {
|
|
@@ -34,6 +38,59 @@ export type PromotionLayerDetail = {
|
|
|
34
38
|
description: string;
|
|
35
39
|
};
|
|
36
40
|
export declare const PROMOTION_LAYER_DETAILS: readonly PromotionLayerDetail[];
|
|
41
|
+
/**
|
|
42
|
+
* rid 2026-09-14-gate-h-promotion — what actually backs a promotion.
|
|
43
|
+
*
|
|
44
|
+
* Before this, a promotion was honored on the marker alone (HTML comment or
|
|
45
|
+
* sidecar). Both are written by `peaks feedback promote` and neither proves
|
|
46
|
+
* that anything was enforced: every layer-A promotion in this repo pointed at
|
|
47
|
+
* `sops/<name>.md`, a file that did not exist and that no engine reads. The
|
|
48
|
+
* gate was therefore self-certifying — it read only what the command it tells
|
|
49
|
+
* you to run had written.
|
|
50
|
+
*
|
|
51
|
+
* A promotion is now honored only when its layer's enforcement surface carries
|
|
52
|
+
* the artifact. The three layers keep artifacts in three different shapes, so
|
|
53
|
+
* the check is a small table rather than one rule:
|
|
54
|
+
*
|
|
55
|
+
* - A (peaks-sop gate): a SOP manifest at `.peaks/sops/<id>/sop.json` AND an
|
|
56
|
+
* entry for `<id>` in `.peaks/sops/registry.json`. The registry half is not
|
|
57
|
+
* decoration: `gate-enforce-service.enforceBashCommand` enumerates SOPs via
|
|
58
|
+
* `readRegistry()`, so an unregistered manifest is off the enforcement path
|
|
59
|
+
* no matter how valid it is.
|
|
60
|
+
* - B (peaks-hooks PreToolUse): `.peaks/.claude-settings-template.json` must
|
|
61
|
+
* register the rule inside its `hooks` block. The file always exists, so
|
|
62
|
+
* existence proves nothing — the evidence is the registration inside it.
|
|
63
|
+
* - C (mode-gate hardFloorCategory): `src/services/code/mode-gate.ts` must
|
|
64
|
+
* register the rule in the hard-floor vocabulary, for the same reason. This
|
|
65
|
+
* is the repo's existing convention: the one real layer-C promotion cites
|
|
66
|
+
* its memory by path, from the category's doc block.
|
|
67
|
+
*
|
|
68
|
+
* R2 (2026-09-14-gate-h-promotion): each of those is now a PARSE plus a shape
|
|
69
|
+
* assertion, in `promotion-artifact-evidence.ts`. Every check used to be a
|
|
70
|
+
* `text.includes(<rule>)` over the whole file, which certified a tree that was
|
|
71
|
+
* a refusal — an invalid-JSON registry, a template saying "do NOT add a
|
|
72
|
+
* matcher", a mode-gate line saying the rule is deliberately not a category —
|
|
73
|
+
* because in each case the rule's name was still in the file's bytes. A name in
|
|
74
|
+
* a file is not a registration, and a file that cannot be parsed is a finding,
|
|
75
|
+
* not a permit.
|
|
76
|
+
*/
|
|
77
|
+
/**
|
|
78
|
+
* SOP id used for a feedback memory's layer-A artifact.
|
|
79
|
+
*
|
|
80
|
+
* Prefixed because `peaks-*` SOP ids are reserved for the built-in namespace
|
|
81
|
+
* (`reservedIdReason` in sop-service.ts) and several feedback memories start
|
|
82
|
+
* with `peaks-`, which would make them unregistrable under their own name.
|
|
83
|
+
*/
|
|
84
|
+
export declare function sopIdForFeedback(memoryName: string): string;
|
|
85
|
+
/** The artifact(s) and the structural evidence each must carry for `layer` to mean anything. */
|
|
86
|
+
export declare function promotionArtifactChecks(memoryName: string, layer: PromotionLayer): PromotionArtifactCheck[];
|
|
87
|
+
/**
|
|
88
|
+
* Which of `checks` are not satisfied under `projectRoot`. Empty means the
|
|
89
|
+
* promotion is backed by its artifact. Never throws, and never permits: a file
|
|
90
|
+
* that is absent, unreadable, or unparseable is a finding, not a warning —
|
|
91
|
+
* "cannot read the evidence" must not read as "the evidence is good".
|
|
92
|
+
*/
|
|
93
|
+
export declare function missingArtifacts(checks: readonly PromotionArtifactCheck[], projectRoot: string): string[];
|
|
37
94
|
export type FeedbackMemory = {
|
|
38
95
|
/** File basename (without `.md`). */
|
|
39
96
|
name: string;
|
|
@@ -59,6 +116,43 @@ export type UnpromotedFeedbackEntry = {
|
|
|
59
116
|
path: string;
|
|
60
117
|
reason: string;
|
|
61
118
|
};
|
|
119
|
+
/**
|
|
120
|
+
* rid 2026-09-14-gate-h-promotion (classify slice) — the "not to be promoted"
|
|
121
|
+
* declaration.
|
|
122
|
+
*
|
|
123
|
+
* The gate used to know only `has artifact` / `has no artifact`, so a memory that
|
|
124
|
+
* prescribes no action could never pass: promoting it registers a SOP whose only
|
|
125
|
+
* gate is "the source file still exists", which asserts nothing about behaviour.
|
|
126
|
+
* That is a permanent false positive — the old vacuity defect facing the other way.
|
|
127
|
+
*
|
|
128
|
+
* The declaration closes it, but it must not become a way to silence the gate.
|
|
129
|
+
* It differs from the refused grandfather channel (`promotedAt` older than this
|
|
130
|
+
* rule) in that a grandfather exemption is a property of a memory's AGE: every
|
|
131
|
+
* legacy memory has it, it says nothing about content, and nobody has to assert
|
|
132
|
+
* or defend it. This is a bounded claim about the memory's CONTENT:
|
|
133
|
+
*
|
|
134
|
+
* 1. The code is drawn from a closed vocabulary — free text cannot be used.
|
|
135
|
+
* 2. Each code binds to a predicate over the memory's own frontmatter, which
|
|
136
|
+
* the gate recomputes. The declaration may only RESTATE what the memory
|
|
137
|
+
* already says; it cannot introduce a new fact.
|
|
138
|
+
* 3. A reason string is required (the `closedAt` escape hatch beside it has none).
|
|
139
|
+
* 4. Coexisting with a promotion marker is a contradiction and fails, so the
|
|
140
|
+
* channel cannot be used to bury a promotion whose artifact is missing.
|
|
141
|
+
* 5. Exempted memories stay REPORTED via `listPromotionExempt`, so the
|
|
142
|
+
* unpromoted count never drops silently.
|
|
143
|
+
*/
|
|
144
|
+
export declare const NOT_TO_PROMOTE_CODES: readonly ["non-actionable", "closed-slice-note"];
|
|
145
|
+
export type NotToPromoteCode = (typeof NOT_TO_PROMOTE_CODES)[number];
|
|
146
|
+
export type NotToPromoteRead = {
|
|
147
|
+
kind: 'none';
|
|
148
|
+
} | {
|
|
149
|
+
kind: 'valid';
|
|
150
|
+
code: NotToPromoteCode;
|
|
151
|
+
reason: string;
|
|
152
|
+
} | {
|
|
153
|
+
kind: 'invalid';
|
|
154
|
+
reason: string;
|
|
155
|
+
};
|
|
62
156
|
/**
|
|
63
157
|
* Parse a single `.peaks/memory/<file>.md` into a FeedbackMemory, or
|
|
64
158
|
* `null` when the file is missing / unreadable / not a feedback memory.
|
|
@@ -78,6 +172,26 @@ export declare function parseFeedbackMemory(filePath: string): FeedbackMemory |
|
|
|
78
172
|
export declare function listUnpromotedFeedback(opts: {
|
|
79
173
|
projectRoot: string;
|
|
80
174
|
}): UnpromotedFeedbackEntry[];
|
|
175
|
+
/**
|
|
176
|
+
* Read the memory's not-to-promote declaration. `invalid` is returned rather than
|
|
177
|
+
* `none` when the fields are present but unusable, so the gate fails with a reason
|
|
178
|
+
* instead of quietly treating a malformed declaration as "no declaration".
|
|
179
|
+
*/
|
|
180
|
+
export declare function readNotToPromote(filePath: string): NotToPromoteRead;
|
|
181
|
+
export type PromotionExemptEntry = {
|
|
182
|
+
name: string;
|
|
183
|
+
path: string;
|
|
184
|
+
code: NotToPromoteCode;
|
|
185
|
+
reason: string;
|
|
186
|
+
};
|
|
187
|
+
/**
|
|
188
|
+
* The feedback memories that declare themselves out of the gate. Exposed so the
|
|
189
|
+
* gate can REPORT them: an exemption nobody can see is the vacuity this whole
|
|
190
|
+
* channel is required to avoid. Never throws.
|
|
191
|
+
*/
|
|
192
|
+
export declare function listPromotionExempt(opts: {
|
|
193
|
+
projectRoot: string;
|
|
194
|
+
}): PromotionExemptEntry[];
|
|
81
195
|
/**
|
|
82
196
|
* Generate the code stub for a given layer. Returns a Markdown
|
|
83
197
|
* snippet the LLM / human can paste into the appropriate file. Pure
|
|
@@ -97,7 +211,16 @@ export type FeedbackPromoteEnvelope = {
|
|
|
97
211
|
feedbackPath: string;
|
|
98
212
|
layer: PromotionLayer;
|
|
99
213
|
layerDetail: string;
|
|
214
|
+
/**
|
|
215
|
+
* Files this call actually wrote. rid 2026-09-14-gate-h-promotion: this used
|
|
216
|
+
* to be the stub's *targets* — paths the command never wrote yet printed as
|
|
217
|
+
* `Generated files:` — which is the defect the Gate H rework exists to remove.
|
|
218
|
+
*/
|
|
100
219
|
generatedFiles: string[];
|
|
220
|
+
/** The artifact(s) `layer` requires before the promotion means anything. */
|
|
221
|
+
requiredArtifacts: string[];
|
|
222
|
+
/** `false` when `requiredArtifacts` are not all present — the marker is then a claim without evidence. */
|
|
223
|
+
effective: boolean;
|
|
101
224
|
snippet: string;
|
|
102
225
|
promotedAt: string;
|
|
103
226
|
promotedBy: string;
|
|
@@ -119,5 +242,5 @@ export declare function promoteFeedback(opts: {
|
|
|
119
242
|
sessionId: string;
|
|
120
243
|
projectRoot: string;
|
|
121
244
|
dryRun?: boolean;
|
|
122
|
-
}): FeedbackPromoteEnvelope
|
|
245
|
+
}): Promise<FeedbackPromoteEnvelope>;
|
|
123
246
|
export declare function isPromotionLayer(value: string): value is PromotionLayer;
|