substrate-ai 0.20.27 → 0.20.28
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/dist/cli/index.js +4 -4
- package/dist/{health-CrEdV2B3.js → health-C6x1jDlX.js} +1 -1
- package/dist/{health-0_axmI2t.js → health-Dx9hm9x1.js} +72 -1
- package/dist/{run-DQcG05Ar.js → run-BmRu588B.js} +2 -2
- package/dist/{run-DQ29oNG2.js → run-CV3EAUZK.js} +2 -2
- package/package.json +1 -1
- package/packs/bmad/prompts/create-story.md +48 -0
package/dist/cli/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { FileStateStore, RunManifest, SUBSTRATE_OWNED_SETTINGS_KEYS, SupervisorLock, VALID_PHASES, WorkGraphRepository, ZERO_FINDING_COUNTS, buildPipelineStatusOutput, createDatabaseAdapter, createStateStore, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, parseDbTimestampAsUtc, registerHealthCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts } from "../health-
|
|
2
|
+
import { FileStateStore, RunManifest, SUBSTRATE_OWNED_SETTINGS_KEYS, SupervisorLock, VALID_PHASES, WorkGraphRepository, ZERO_FINDING_COUNTS, buildPipelineStatusOutput, createDatabaseAdapter, createStateStore, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, parseDbTimestampAsUtc, registerHealthCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts } from "../health-Dx9hm9x1.js";
|
|
3
3
|
import { createLogger } from "../logger-KeHncl-f.js";
|
|
4
4
|
import { createEventBus } from "../helpers-CElYrONe.js";
|
|
5
5
|
import { AdapterRegistry, BudgetConfigSchema, CURRENT_CONFIG_FORMAT_VERSION, CURRENT_TASK_GRAPH_VERSION, ConfigError, CostTrackerConfigSchema, DEFAULT_CONFIG, DoltClient, DoltNotInstalled, GlobalSettingsSchema, IngestionServer, MonitorDatabaseImpl, OPERATIONAL_FINDING, PartialGlobalSettingsSchema, PartialProviderConfigSchema, ProvidersSchema, RoutingRecommender, STORY_METRICS, TelemetryConfigSchema, addTokenUsage, aggregateTokenUsageForRun, checkDoltInstalled, compareRunMetrics, createAmendmentRun, createConfigSystem, createDecision, createDoltClient, createPipelineRun, getActiveDecisions, getAllCostEntriesFiltered, getBaselineRunMetrics, getDecisionsByCategory, getDecisionsByPhaseForRun, getLatestCompletedRun, getLatestRun, getPipelineRunById, getPlanningCostTotal, getRetryableEscalations, getRunMetrics, getRunningPipelineRuns, getSessionCostSummary, getSessionCostSummaryFiltered, getStoryMetricsForRun, getTokenUsageSummary, incrementRunRestarts, initSchema, initializeDolt, listRunMetrics, loadParentRunDecisions, supersedeDecision, tagRunAsBaseline, updatePipelineRun } from "../dist-CqtWS9wF.js";
|
|
6
6
|
import "../adapter-registry-DXLMTmfD.js";
|
|
7
|
-
import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GitClient, GrammarLoader, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runSolutioningPhase, validateStopAfterFromConflict } from "../run-
|
|
7
|
+
import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GitClient, GrammarLoader, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runSolutioningPhase, validateStopAfterFromConflict } from "../run-BmRu588B.js";
|
|
8
8
|
import "../errors-1uLGqnvr.js";
|
|
9
9
|
import "../routing-CcBOCuC9.js";
|
|
10
10
|
import "../decisions-C0pz9Clx.js";
|
|
@@ -3667,7 +3667,7 @@ async function runStatusAction(options) {
|
|
|
3667
3667
|
logger$12.debug({ err }, "Work graph query failed, continuing without work graph data");
|
|
3668
3668
|
}
|
|
3669
3669
|
if (run === void 0) {
|
|
3670
|
-
const { inspectProcessTree: inspectProcessTree$1 } = await import("../health-
|
|
3670
|
+
const { inspectProcessTree: inspectProcessTree$1 } = await import("../health-C6x1jDlX.js");
|
|
3671
3671
|
const substrateDirPath = join(projectRoot, ".substrate");
|
|
3672
3672
|
const processInfo = inspectProcessTree$1({
|
|
3673
3673
|
projectRoot,
|
|
@@ -5198,7 +5198,7 @@ async function runSupervisorAction(options, deps = {}) {
|
|
|
5198
5198
|
await initSchema(expAdapter);
|
|
5199
5199
|
const { runRunAction: runPipeline } = await import(
|
|
5200
5200
|
/* @vite-ignore */
|
|
5201
|
-
"../run-
|
|
5201
|
+
"../run-CV3EAUZK.js"
|
|
5202
5202
|
);
|
|
5203
5203
|
const runStoryFn = async (opts) => {
|
|
5204
5204
|
const exitCode = await runPipeline({
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DEFAULT_STALL_THRESHOLD_SECONDS, getAllDescendantPids, getAutoHealthData, inspectProcessTree, isOrchestratorProcessLine, registerHealthCommand, runHealthAction } from "./health-
|
|
1
|
+
import { DEFAULT_STALL_THRESHOLD_SECONDS, getAllDescendantPids, getAutoHealthData, inspectProcessTree, isOrchestratorProcessLine, registerHealthCommand, runHealthAction } from "./health-Dx9hm9x1.js";
|
|
2
2
|
import "./logger-KeHncl-f.js";
|
|
3
3
|
import "./dist-CqtWS9wF.js";
|
|
4
4
|
import "./decisions-C0pz9Clx.js";
|
|
@@ -3744,6 +3744,70 @@ const CATEGORY_TIMEOUT = "runtime-probe-timeout";
|
|
|
3744
3744
|
* from "tool errored loudly".
|
|
3745
3745
|
*/
|
|
3746
3746
|
const CATEGORY_ASSERTION_FAIL = "runtime-probe-assertion-fail";
|
|
3747
|
+
/**
|
|
3748
|
+
* Story 60-11: source AC describes an event-driven mechanism (hook, timer,
|
|
3749
|
+
* signal, webhook) but no probe's command invokes a known production-trigger
|
|
3750
|
+
* pattern. Strata Run 13 (Story 1-12, 2026-04-26): vault conflict hook
|
|
3751
|
+
* shipped SHIP_IT non-functional because the dev's probe ran the hook script
|
|
3752
|
+
* directly with `bash .git/hooks/post-merge` — git only fires post-merge on
|
|
3753
|
+
* a SUCCESSFUL merge, so under conflict (the hook's actual use case) the
|
|
3754
|
+
* production trigger never fires. Direct-invocation probe missed it; only
|
|
3755
|
+
* e2e smoke caught it. Sibling to obs_012's success-shape gap.
|
|
3756
|
+
*
|
|
3757
|
+
* Severity is warn (advisory, non-blocking) until the heuristic is
|
|
3758
|
+
* calibrated against several runs. Flip to error once false-positive rate
|
|
3759
|
+
* is verified low.
|
|
3760
|
+
*/
|
|
3761
|
+
const CATEGORY_MISSING_TRIGGER = "runtime-probe-missing-production-trigger";
|
|
3762
|
+
/**
|
|
3763
|
+
* Source-AC keywords that signal an event-driven implementation. Word-boundary
|
|
3764
|
+
* matched, case-insensitive. When any of these appears in source AC text AND
|
|
3765
|
+
* no probe's command invokes a known production trigger, the check emits a
|
|
3766
|
+
* `runtime-probe-missing-production-trigger` warn finding.
|
|
3767
|
+
*
|
|
3768
|
+
* Each keyword is paired with the trigger patterns that satisfy it:
|
|
3769
|
+
* - `git hook` / `post-merge` / etc. → satisfied by `git merge|pull|push|commit|rebase`
|
|
3770
|
+
* - `systemd` / `timer` / `unit` → satisfied by `systemctl ... start|enable|trigger`
|
|
3771
|
+
* - `cron` / `crontab` / `schedule` → satisfied by `crontab|run-parts|schedule`
|
|
3772
|
+
* - `signal` / `SIGHUP|SIGTERM|SIGUSR` → satisfied by `kill -<signal>`
|
|
3773
|
+
* - `webhook` / `HTTP POST` / `endpoint` → satisfied by `curl ... -X POST` or wget
|
|
3774
|
+
* - `inotify` / `path watch` → satisfied by `touch|mkdir|rm` (filesystem mutation)
|
|
3775
|
+
*/
|
|
3776
|
+
const EVENT_DRIVEN_KEYWORDS = [
|
|
3777
|
+
/\b(?:git\s+hook|post-merge|post-commit|post-rewrite|pre-push|pre-commit|pre-merge-commit)\b/i,
|
|
3778
|
+
/\b(?:systemd\s+(?:unit|service|timer|path)|systemctl|\.timer\b|\.service\b)\b/i,
|
|
3779
|
+
/\b(?:cron\s*(?:job|tab|expression)?|crontab|scheduled\s+task)\b/i,
|
|
3780
|
+
/\b(?:signal\s+handler|SIG(?:HUP|TERM|INT|USR1|USR2|KILL))\b/,
|
|
3781
|
+
/\b(?:webhook|HTTP\s+(?:POST|GET)\s+endpoint|REST\s+endpoint)\b/i,
|
|
3782
|
+
/\b(?:inotify|path\s+watch|file\s+watcher)\b/i
|
|
3783
|
+
];
|
|
3784
|
+
/**
|
|
3785
|
+
* Production-trigger command patterns. If ANY probe's command matches one of
|
|
3786
|
+
* these, the heuristic considers the trigger covered. Word-boundary matched.
|
|
3787
|
+
*/
|
|
3788
|
+
const TRIGGER_COMMAND_PATTERNS = [
|
|
3789
|
+
/\bgit\s+(?:merge|pull|push|commit|rebase|cherry-pick)\b/,
|
|
3790
|
+
/\bsystemctl\b/,
|
|
3791
|
+
/\bcrontab\b|\brun-parts\b/,
|
|
3792
|
+
/\bkill\s+-/,
|
|
3793
|
+
/\bcurl\s+(?:[^|]*\s)?-X\s+(?:POST|GET|PUT|DELETE)/i,
|
|
3794
|
+
/\bwget\s+--method=(?:POST|GET|PUT|DELETE)/i,
|
|
3795
|
+
/\b(?:touch|mkdir|rm)\s+/
|
|
3796
|
+
];
|
|
3797
|
+
/**
|
|
3798
|
+
* Returns true if the source AC text mentions an event-driven mechanism.
|
|
3799
|
+
*/
|
|
3800
|
+
function detectsEventDrivenAC(sourceEpicContent) {
|
|
3801
|
+
for (const pattern of EVENT_DRIVEN_KEYWORDS) if (pattern.test(sourceEpicContent)) return true;
|
|
3802
|
+
return false;
|
|
3803
|
+
}
|
|
3804
|
+
/**
|
|
3805
|
+
* Returns true if any probe's command line invokes a known production trigger.
|
|
3806
|
+
*/
|
|
3807
|
+
function probesInvokeProductionTrigger(probes) {
|
|
3808
|
+
for (const probe of probes) for (const pattern of TRIGGER_COMMAND_PATTERNS) if (pattern.test(probe.command)) return true;
|
|
3809
|
+
return false;
|
|
3810
|
+
}
|
|
3747
3811
|
const defaultExecutors = { host: (probe) => executeProbeOnHost(probe, { cwd: process.cwd() }) };
|
|
3748
3812
|
var RuntimeProbeCheck = class {
|
|
3749
3813
|
name = "runtime-probes";
|
|
@@ -3797,6 +3861,13 @@ var RuntimeProbeCheck = class {
|
|
|
3797
3861
|
findings: []
|
|
3798
3862
|
};
|
|
3799
3863
|
const findings = [];
|
|
3864
|
+
if (context.sourceEpicContent !== void 0) {
|
|
3865
|
+
if (detectsEventDrivenAC(context.sourceEpicContent) && !probesInvokeProductionTrigger(parsed.probes)) findings.push({
|
|
3866
|
+
category: CATEGORY_MISSING_TRIGGER,
|
|
3867
|
+
severity: "warn",
|
|
3868
|
+
message: "source AC describes an event-driven mechanism (hook / timer / signal / webhook) but no probe's command invokes a known production trigger (git merge/pull/push, systemctl, crontab, kill -<sig>, curl -X POST, etc.). Probes that call the implementation directly skip the wiring layer the AC's user-facing event would exercise — see strata Run 13 / Story 1-12 for the canonical case (post-merge hook never fires under git's conflict semantic). Authoring guidance: probes/event-driven section of create-story.md."
|
|
3869
|
+
});
|
|
3870
|
+
}
|
|
3800
3871
|
for (const probe of parsed.probes) {
|
|
3801
3872
|
if (probe.sandbox === "twin") {
|
|
3802
3873
|
findings.push({
|
|
@@ -5996,4 +6067,4 @@ function registerHealthCommand(program, _version = "0.0.0", projectRoot = proces
|
|
|
5996
6067
|
|
|
5997
6068
|
//#endregion
|
|
5998
6069
|
export { BMAD_BASELINE_TOKENS_FULL, DEFAULT_STALL_THRESHOLD_SECONDS, DoltMergeConflict, FileStateStore, FindingsInjector, RunManifest, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN$1 as STORY_KEY_PATTERN, SUBSTRATE_OWNED_SETTINGS_KEYS, SupervisorLock, VALID_PHASES, WorkGraphRepository, ZERO_FINDING_COUNTS, __commonJS, __require, __toESM, applyConfigToGraph, buildPipelineStatusOutput, createDatabaseAdapter$1 as createDatabaseAdapter, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, createStateStore, detectCycles, extractTargetFilesFromStoryContent, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, isOrchestratorProcessLine, parseDbTimestampAsUtc, registerHealthCommand, renderFindings, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveGraphPath, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, runHealthAction, validateStoryKey };
|
|
5999
|
-
//# sourceMappingURL=health-
|
|
6070
|
+
//# sourceMappingURL=health-Dx9hm9x1.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BMAD_BASELINE_TOKENS_FULL, DoltMergeConflict, FileStateStore, FindingsInjector, RunManifest, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN, VALID_PHASES, WorkGraphRepository, __commonJS, __require, __toESM, applyConfigToGraph, buildPipelineStatusOutput, createDatabaseAdapter, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectCycles, extractTargetFilesFromStoryContent, formatOutput, formatPipelineSummary, formatTokenTelemetry, inspectProcessTree, parseDbTimestampAsUtc, renderFindings, resolveGraphPath, resolveMainRepoRoot, validateStoryKey } from "./health-
|
|
1
|
+
import { BMAD_BASELINE_TOKENS_FULL, DoltMergeConflict, FileStateStore, FindingsInjector, RunManifest, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN, VALID_PHASES, WorkGraphRepository, __commonJS, __require, __toESM, applyConfigToGraph, buildPipelineStatusOutput, createDatabaseAdapter, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectCycles, extractTargetFilesFromStoryContent, formatOutput, formatPipelineSummary, formatTokenTelemetry, inspectProcessTree, parseDbTimestampAsUtc, renderFindings, resolveGraphPath, resolveMainRepoRoot, validateStoryKey } from "./health-Dx9hm9x1.js";
|
|
2
2
|
import { createLogger } from "./logger-KeHncl-f.js";
|
|
3
3
|
import { TypedEventBusImpl, createEventBus, createTuiApp, isTuiCapable, printNonTtyWarning, sleep } from "./helpers-CElYrONe.js";
|
|
4
4
|
import { ADVISORY_NOTES, Categorizer, ConsumerAnalyzer, DEFAULT_GLOBAL_SETTINGS, DispatcherImpl, DoltClient, ESCALATION_DIAGNOSIS, EXPERIMENT_RESULT, EfficiencyScorer, IngestionServer, LogTurnAnalyzer, OPERATIONAL_FINDING, Recommender, RoutingRecommender, RoutingResolver, RoutingTelemetry, RoutingTokenAccumulator, RoutingTuner, STORY_METRICS, STORY_OUTCOME, SubstrateConfigSchema, TEST_EXPANSION_FINDING, TEST_PLAN, TelemetryNormalizer, TelemetryPipeline, TurnAnalyzer, addTokenUsage, aggregateTokenUsageForRun, aggregateTokenUsageForStory, callLLM, createConfigSystem, createDatabaseAdapter$1, createDecision, createPipelineRun, createRequirement, detectInterfaceChanges, getArtifactByTypeForRun, getArtifactsByRun, getDecisionsByCategory, getDecisionsByPhase, getDecisionsByPhaseForRun, getLatestRun, getPipelineRunById, getRunMetrics, getRunningPipelineRuns, getStoryMetricsForRun, getTokenUsageSummary, initSchema, listRequirements, loadModelRoutingConfig, registerArtifact, updatePipelineRun, updatePipelineRunConfig, upsertDecision, writeRunMetrics, writeStoryMetrics } from "./dist-CqtWS9wF.js";
|
|
@@ -44488,4 +44488,4 @@ function registerRunCommand(program, _version = "0.0.0", projectRoot = process.c
|
|
|
44488
44488
|
|
|
44489
44489
|
//#endregion
|
|
44490
44490
|
export { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GitClient, GrammarLoader, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, normalizeGraphSummaryToStatus, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveMaxReviewCycles, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runRunAction, runSolutioningPhase, validateStopAfterFromConflict, wireNdjsonEmitter };
|
|
44491
|
-
//# sourceMappingURL=run-
|
|
44491
|
+
//# sourceMappingURL=run-BmRu588B.js.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import "./health-
|
|
1
|
+
import "./health-Dx9hm9x1.js";
|
|
2
2
|
import "./logger-KeHncl-f.js";
|
|
3
3
|
import "./helpers-CElYrONe.js";
|
|
4
4
|
import "./dist-CqtWS9wF.js";
|
|
5
|
-
import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, runRunAction, wireNdjsonEmitter } from "./run-
|
|
5
|
+
import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, runRunAction, wireNdjsonEmitter } from "./run-BmRu588B.js";
|
|
6
6
|
import "./routing-CcBOCuC9.js";
|
|
7
7
|
import "./decisions-C0pz9Clx.js";
|
|
8
8
|
|
package/package.json
CHANGED
|
@@ -158,6 +158,54 @@ Exit-code success is necessary but **not sufficient** for probes calling tools t
|
|
|
158
158
|
|
|
159
159
|
Patterns are JavaScript regex (`new RegExp`). Evaluated only when exit code is 0; non-zero exits emit `runtime-probe-fail` and assertions are skipped to avoid redundant findings.
|
|
160
160
|
|
|
161
|
+
### Probes for event-driven mechanisms must invoke the production trigger
|
|
162
|
+
|
|
163
|
+
When the source AC describes a hook, timer, signal, webhook, or other event-driven mechanism, the probe MUST invoke the **production trigger** that fires the implementation in real usage — NOT call the implementation script directly. Calling the implementation directly verifies it produces correct outputs given synthetic inputs; it does NOT verify the implementation is wired to the right trigger and will actually fire when the AC's user-facing event occurs.
|
|
164
|
+
|
|
165
|
+
Strata Run 13 (Story 1-12, post-merge git hook) shipped SHIP_IT after the dev's probe ran the resolver script directly with conflict-marker fixtures. The resolver was correct; the wiring was not. `git`'s `post-merge` hook is **not executed when a merge fails due to conflicts** (per `githooks(5)`) — and the AC's whole point was conflict resolution. The hook never fired in production. Direct invocation hid this entirely.
|
|
166
|
+
|
|
167
|
+
**Rule**: if the AC describes "when X happens, Y runs", the probe must MAKE X HAPPEN and assert Y ran. Synthesized inputs to Y skip the wiring layer.
|
|
168
|
+
|
|
169
|
+
| AC describes | Production trigger to invoke | Common wrong shape (DO NOT use) |
|
|
170
|
+
|---|---|---|
|
|
171
|
+
| `post-merge` / `post-commit` / `post-rewrite` git hook | `git merge <branch>` (with the conflict scenario the AC describes) | `bash .git/hooks/post-merge` |
|
|
172
|
+
| `pre-push` git hook | `git push` against a local fixture remote | `bash .git/hooks/pre-push` |
|
|
173
|
+
| systemd unit / timer | `systemctl --user start <unit>` or `systemctl --user start <timer>.timer` then assert `<unit>.service` ran | direct call to the binary the unit invokes |
|
|
174
|
+
| systemd path / inotify trigger | touch / create / modify the watched path; assert the unit fires within N seconds | direct call to the script |
|
|
175
|
+
| cron job | invoke `crontab` to install + run-once via `run-parts` OR shorten the schedule to `* * * * *` and wait | direct call to the script |
|
|
176
|
+
| Signal handler | `kill -<SIGNAL> <pid>` against the running process | direct call to the handler function |
|
|
177
|
+
| Webhook receiver | `curl -X POST <endpoint>` with the actual payload shape | direct call to the handler with synthetic payload |
|
|
178
|
+
|
|
179
|
+
**Example: post-merge hook probe (the strata 1-12 case, fixed)**
|
|
180
|
+
|
|
181
|
+
```yaml
|
|
182
|
+
- name: post-merge-hook-fires-and-resolves-conflict
|
|
183
|
+
sandbox: twin
|
|
184
|
+
command: |
|
|
185
|
+
set -e
|
|
186
|
+
REPO=$(mktemp -d)
|
|
187
|
+
cd "$REPO" && git init -q
|
|
188
|
+
git config user.email t@example.com && git config user.name test
|
|
189
|
+
bash <REPO_ROOT>/hooks/install-vault-hooks.sh "$REPO"
|
|
190
|
+
echo "human content" > note.md && git add . && git commit -qm initial
|
|
191
|
+
git checkout -qb branch-jarvis
|
|
192
|
+
GIT_AUTHOR_NAME=jarvis-bot GIT_AUTHOR_EMAIL=jarvis@bot \
|
|
193
|
+
bash -c 'echo "jarvis content" > note.md && git commit -aqm "jarvis edit"'
|
|
194
|
+
git checkout -q main
|
|
195
|
+
echo "human content edit" > note.md && git commit -aqm "human edit"
|
|
196
|
+
git merge --no-edit branch-jarvis || true # produces conflict
|
|
197
|
+
# If post-merge fired correctly via the production trigger, the conflict is resolved.
|
|
198
|
+
# If it did NOT fire (because it can't, by design — see githooks(5)), the working
|
|
199
|
+
# tree still has conflict markers and this assertion catches it.
|
|
200
|
+
expect_stdout_no_regex:
|
|
201
|
+
- '<{7}|>{7}' # conflict markers must NOT remain in tree after resolution
|
|
202
|
+
expect_stdout_regex:
|
|
203
|
+
- 'human content' # human side preserved per "Jarvis yields to human" rule
|
|
204
|
+
description: real git merge fires (or fails to fire) post-merge — assertion catches both
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Note this example, taken to production, would have caught the strata 1-12 bug at runtime-probe phase rather than only at e2e smoke pass. That's the standard 60-10 sets.
|
|
208
|
+
|
|
161
209
|
### Examples by artifact class
|
|
162
210
|
|
|
163
211
|
**Systemd unit:**
|