@mestreyoda/fabrica 0.2.23 → 0.2.24

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 (2) hide show
  1. package/dist/index.js +318 -10
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -113905,8 +113905,8 @@ import fsSync from "node:fs";
113905
113905
  import path5 from "node:path";
113906
113906
  import { fileURLToPath as fileURLToPath3 } from "node:url";
113907
113907
  function getCurrentVersion() {
113908
- if ("0.2.23") {
113909
- return "0.2.23";
113908
+ if ("0.2.24") {
113909
+ return "0.2.24";
113910
113910
  }
113911
113911
  try {
113912
113912
  const pkgPath = path5.join(THIS_DIR, "..", "..", "package.json");
@@ -122268,7 +122268,9 @@ async function clearIssueRuntime(workspaceDir, slugOrChannelId, issueId) {
122268
122268
  decompositionMode: existing.decompositionMode ?? null,
122269
122269
  decompositionStatus: existing.parentIssueId ? "completed" : existing.decompositionStatus ?? null,
122270
122270
  sessionCompletedAt: existing.sessionCompletedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
122271
- artifactOfRecord: existing.artifactOfRecord ?? null
122271
+ artifactOfRecord: existing.artifactOfRecord ?? null,
122272
+ qualityCriticality: existing.qualityCriticality ?? null,
122273
+ riskProfile: existing.riskProfile ?? null
122272
122274
  } : null;
122273
122275
  if (preserved && (preserved.parentIssueId != null || (preserved.childIssueIds?.length ?? 0) > 0 || (preserved.dependencyIssueIds?.length ?? 0) > 0 || preserved.decompositionMode != null)) {
122274
122276
  project.issueRuntime[key] = preserved;
@@ -125107,6 +125109,10 @@ ${event.summary}`;
125107
125109
  if (event.summary) {
125108
125110
  msg += `
125109
125111
  ${event.summary}`;
125112
+ }
125113
+ if (event.acceptanceSummary) {
125114
+ msg += `
125115
+ \u{1F9FE} ${event.acceptanceSummary}`;
125110
125116
  }
125111
125117
  if (event.prUrl) msg += `
125112
125118
  \u{1F517} ${prLink(event.prUrl)}`;
@@ -125223,6 +125229,8 @@ ${event.summary}`;
125223
125229
  let msg = `\u{1F3C1} Issue completed: #${event.issueId} \u2014 ${event.issueTitle}`;
125224
125230
  msg += `
125225
125231
  \u{1F4E6} Project: ${event.project}`;
125232
+ if (event.acceptanceSummary) msg += `
125233
+ \u{1F9FE} ${event.acceptanceSummary}`;
125226
125234
  if (event.prUrl) msg += `
125227
125235
  \u{1F517} ${prLink(event.prUrl)}`;
125228
125236
  msg += `
@@ -125610,10 +125618,14 @@ function formatChildRollupLine(child) {
125610
125618
  const prUrl = runtime?.artifactOfRecord?.url ?? runtime?.currentPrUrl ?? null;
125611
125619
  const mergedAt = runtime?.artifactOfRecord?.mergedAt ?? null;
125612
125620
  const headSha = runtime?.artifactOfRecord?.headSha ?? runtime?.lastHeadSha ?? null;
125621
+ const qualityCriticality = runtime?.qualityCriticality ?? null;
125622
+ const riskProfile = runtime?.riskProfile ?? [];
125613
125623
  const extras = [
125614
125624
  prUrl ? `PR: ${prUrl}` : null,
125615
125625
  mergedAt ? `mergedAt: ${mergedAt}` : null,
125616
- headSha ? `headSha: ${headSha}` : null
125626
+ headSha ? `headSha: ${headSha}` : null,
125627
+ qualityCriticality ? `qualityCriticality: ${qualityCriticality}` : null,
125628
+ riskProfile.length > 0 ? `risks: ${riskProfile.join(",")}` : null
125617
125629
  ].filter(Boolean);
125618
125630
  return `- #${child.issueId} \u2014 ${state}${extras.length > 0 ? ` \u2014 ${extras.join(" \u2014 ")}` : ""}`;
125619
125631
  }
@@ -125622,12 +125634,14 @@ var PARENT_ROLLUP_END = "<!-- fabrica:parent-rollup:end -->";
125622
125634
  function buildParentRollupComment(status, completedChildIds, blockedChildIds, children) {
125623
125635
  const allChildIds = children.map((child) => child.issueId);
125624
125636
  const pendingChildIds = allChildIds.filter((id) => !completedChildIds.includes(id) && !blockedChildIds.includes(id));
125637
+ const highCriticalityChildren = children.filter((child) => child.runtime?.qualityCriticality === "high").map((child) => child.issueId);
125625
125638
  return [
125626
125639
  "## Parent Rollup",
125627
125640
  `- Status: ${status}`,
125628
125641
  `- Completed children (${completedChildIds.length}/${allChildIds.length}): ${completedChildIds.length > 0 ? completedChildIds.map((id) => `#${id}`).join(", ") : "none"}`,
125629
125642
  `- Pending children: ${pendingChildIds.length > 0 ? pendingChildIds.map((id) => `#${id}`).join(", ") : "none"}`,
125630
125643
  `- Blocked children: ${blockedChildIds.length > 0 ? blockedChildIds.map((id) => `#${id}`).join(", ") : "none"}`,
125644
+ `- High-criticality children: ${highCriticalityChildren.length > 0 ? highCriticalityChildren.map((id) => `#${id}`).join(", ") : "none"}`,
125631
125645
  "",
125632
125646
  "### Child Status",
125633
125647
  ...children.map((child) => formatChildRollupLine(child))
@@ -125704,6 +125718,200 @@ async function reconcileParentLifecycleForIssue(opts) {
125704
125718
  // lib/services/pipeline.ts
125705
125719
  init_workflow();
125706
125720
  init_context3();
125721
+
125722
+ // lib/quality/quality-gates.ts
125723
+ var BASE_POLICIES = {
125724
+ api: {
125725
+ archetype: "api",
125726
+ requiredEvidence: ["request-level verification", "acceptance criteria traceability"],
125727
+ requiredChecks: ["startup/build", "endpoint validation", "error-handling review"],
125728
+ autoRejectConditions: ["missing input validation", "missing auth review on sensitive flows", "no meaningful API evidence"],
125729
+ qualityCriticalityFloor: "medium"
125730
+ },
125731
+ "web-ui": {
125732
+ archetype: "web-ui",
125733
+ requiredEvidence: ["primary flow verification", "loading/error behavior"],
125734
+ requiredChecks: ["build/render", "interaction smoke", "a11y sanity"],
125735
+ autoRejectConditions: ["missing primary flow evidence", "missing loading/error handling"],
125736
+ qualityCriticalityFloor: "medium"
125737
+ },
125738
+ cli: {
125739
+ archetype: "cli",
125740
+ requiredEvidence: ["command smoke", "help output", "exit-code behavior"],
125741
+ requiredChecks: ["binary/script execution", "argv validation"],
125742
+ autoRejectConditions: ["missing help output", "wrong exit-code behavior", "no command evidence"],
125743
+ qualityCriticalityFloor: "low"
125744
+ },
125745
+ library: {
125746
+ archetype: "library",
125747
+ requiredEvidence: ["public API tests", "usage validation"],
125748
+ requiredChecks: ["build/install", "public export verification"],
125749
+ autoRejectConditions: ["no public API evidence", "broken exports"],
125750
+ qualityCriticalityFloor: "low"
125751
+ },
125752
+ automation: {
125753
+ archetype: "automation",
125754
+ requiredEvidence: ["main flow verification", "failure-path evidence"],
125755
+ requiredChecks: ["timeout/retry review", "idempotency review when applicable"],
125756
+ autoRejectConditions: ["unsafe retries", "no failure-path evidence"],
125757
+ qualityCriticalityFloor: "medium"
125758
+ },
125759
+ hybrid: {
125760
+ archetype: "hybrid",
125761
+ requiredEvidence: ["API and UI flow evidence", "integration behavior"],
125762
+ requiredChecks: ["build", "API smoke", "UI smoke"],
125763
+ autoRejectConditions: ["missing UI evidence", "missing API evidence"],
125764
+ qualityCriticalityFloor: "medium"
125765
+ },
125766
+ unknown: {
125767
+ archetype: "unknown",
125768
+ requiredEvidence: ["basic behavioral evidence"],
125769
+ requiredChecks: ["build or execution smoke"],
125770
+ autoRejectConditions: ["no runnable evidence"],
125771
+ qualityCriticalityFloor: "low"
125772
+ }
125773
+ };
125774
+ function resolveQualityGatePolicy(opts) {
125775
+ const archetype = opts.deliverable ?? "unknown";
125776
+ const base = BASE_POLICIES[archetype] ?? BASE_POLICIES.unknown;
125777
+ const ORDER = ["low", "medium", "high"];
125778
+ const qualityCriticalityFloor = opts.qualityCriticality ? ORDER.indexOf(opts.qualityCriticality) > ORDER.indexOf(base.qualityCriticalityFloor) ? opts.qualityCriticality : base.qualityCriticalityFloor : base.qualityCriticalityFloor;
125779
+ return {
125780
+ ...base,
125781
+ qualityCriticalityFloor
125782
+ };
125783
+ }
125784
+
125785
+ // lib/quality/done-policies.ts
125786
+ var BASE_POLICIES2 = {
125787
+ api: {
125788
+ archetype: "api",
125789
+ requiredArtifacts: ["implemented endpoint surface", "runtime contract"],
125790
+ requiredEvidence: ["API behavior evidence", "acceptance criteria coverage"],
125791
+ behavioralChecks: ["startup works", "error paths handled", "validation enforced"],
125792
+ disqualifyingConditions: ["missing endpoint evidence", "missing validation on exposed boundaries"],
125793
+ qualityCriticalityFloor: "medium"
125794
+ },
125795
+ "web-ui": {
125796
+ archetype: "web-ui",
125797
+ requiredArtifacts: ["main user flow", "UI states"],
125798
+ requiredEvidence: ["interaction evidence", "loading/error evidence"],
125799
+ behavioralChecks: ["main flow works", "render path stable"],
125800
+ disqualifyingConditions: ["missing main flow evidence", "broken loading/error handling"],
125801
+ qualityCriticalityFloor: "medium"
125802
+ },
125803
+ cli: {
125804
+ archetype: "cli",
125805
+ requiredArtifacts: ["command entrypoint", "help contract"],
125806
+ requiredEvidence: ["command execution evidence", "exit-code evidence"],
125807
+ behavioralChecks: ["help works", "main command succeeds", "invalid args fail cleanly"],
125808
+ disqualifyingConditions: ["missing help", "no command execution evidence"],
125809
+ qualityCriticalityFloor: "low"
125810
+ },
125811
+ library: {
125812
+ archetype: "library",
125813
+ requiredArtifacts: ["public API surface"],
125814
+ requiredEvidence: ["public API tests or examples"],
125815
+ behavioralChecks: ["exports resolve", "usage path works"],
125816
+ disqualifyingConditions: ["broken exports", "no public API evidence"],
125817
+ qualityCriticalityFloor: "low"
125818
+ },
125819
+ automation: {
125820
+ archetype: "automation",
125821
+ requiredArtifacts: ["orchestration flow"],
125822
+ requiredEvidence: ["main flow evidence", "failure-path evidence"],
125823
+ behavioralChecks: ["timeouts are bounded", "retry semantics are safe where needed"],
125824
+ disqualifyingConditions: ["unsafe retry behavior", "no failure-path evidence"],
125825
+ qualityCriticalityFloor: "medium"
125826
+ },
125827
+ hybrid: {
125828
+ archetype: "hybrid",
125829
+ requiredArtifacts: ["API surface", "UI/main interaction flow"],
125830
+ requiredEvidence: ["API evidence", "UI evidence"],
125831
+ behavioralChecks: ["integrated path works"],
125832
+ disqualifyingConditions: ["missing one side of hybrid evidence"],
125833
+ qualityCriticalityFloor: "medium"
125834
+ },
125835
+ unknown: {
125836
+ archetype: "unknown",
125837
+ requiredArtifacts: ["core deliverable"],
125838
+ requiredEvidence: ["basic runnable evidence"],
125839
+ behavioralChecks: ["main path works"],
125840
+ disqualifyingConditions: ["no evidence of working main path"],
125841
+ qualityCriticalityFloor: "low"
125842
+ }
125843
+ };
125844
+ function resolveDonePolicy(opts) {
125845
+ const archetype = opts.deliverable ?? "unknown";
125846
+ const base = BASE_POLICIES2[archetype] ?? BASE_POLICIES2.unknown;
125847
+ const ORDER = ["low", "medium", "high"];
125848
+ const qualityCriticalityFloor = opts.qualityCriticality ? ORDER.indexOf(opts.qualityCriticality) > ORDER.indexOf(base.qualityCriticalityFloor) ? opts.qualityCriticality : base.qualityCriticalityFloor : base.qualityCriticalityFloor;
125849
+ return {
125850
+ ...base,
125851
+ qualityCriticalityFloor
125852
+ };
125853
+ }
125854
+
125855
+ // lib/services/pipeline.ts
125856
+ function hasMeaningfulCompletionEvidence(summary, prUrl, createdTasks) {
125857
+ if (summary && summary.trim().length >= 12) return true;
125858
+ if (prUrl && prUrl.trim().length > 0) return true;
125859
+ if (createdTasks && createdTasks.length > 0) return true;
125860
+ return false;
125861
+ }
125862
+ function hasArchetypeSpecificEvidence(deliverable, summary, prUrl, createdTasks) {
125863
+ if (prUrl && prUrl.trim().length > 0) return true;
125864
+ if (createdTasks && createdTasks.length > 0) return true;
125865
+ const text = (summary ?? "").toLowerCase();
125866
+ if (!text) return deliverable === "unknown";
125867
+ if (deliverable === "cli") return /cli|command|help|exit|argv|flag|terminal/.test(text);
125868
+ if (deliverable === "api") return /api|endpoint|route|request|response|validation|handler/.test(text);
125869
+ if (deliverable === "web-ui") return /ui|screen|page|render|flow|loading|error|form/.test(text);
125870
+ if (deliverable === "hybrid") return /api|ui|flow|integration|endpoint|screen/.test(text);
125871
+ return true;
125872
+ }
125873
+ function buildFinalAcceptanceSummary(opts) {
125874
+ const openConcerns = [];
125875
+ if (!opts.hasEvidence) openConcerns.push("missing_meaningful_completion_evidence");
125876
+ if (opts.deliverable === "unknown") openConcerns.push("deliverable_inference_is_unknown");
125877
+ if (!opts.closeRequested) openConcerns.push("completion_did_not_request_close");
125878
+ if (opts.qualityCriticality === "high") openConcerns.push("quality_criticality_high_requires_conservative_review");
125879
+ if (opts.riskProfile.length > 0) openConcerns.push(...opts.riskProfile.map((risk) => `risk:${risk}`));
125880
+ return {
125881
+ deliverable: opts.deliverable,
125882
+ fidelityStatus: opts.deliverable === "unknown" ? "warn" : "pass",
125883
+ qualityGateStatus: opts.qualityPolicy.requiredChecks.length > 0 ? "pass" : "warn",
125884
+ evidenceStatus: opts.hasEvidence ? "pass" : "fail",
125885
+ donePolicyStatus: opts.donePolicy.requiredArtifacts.length > 0 ? "pass" : "warn",
125886
+ openConcerns
125887
+ };
125888
+ }
125889
+ function resolvePipelineDeliverable(project) {
125890
+ const stack = project?.environment?.stack ?? project?.stack ?? null;
125891
+ if (stack === "nextjs") return "web-ui";
125892
+ if (stack === "node-cli" || stack === "python-cli") return "cli";
125893
+ if (stack === "express" || stack === "fastapi" || stack === "flask" || stack === "django") return "api";
125894
+ const nameText = `${project?.name ?? ""} ${project?.slug ?? ""} ${project?.repo ?? ""}`.toLowerCase();
125895
+ if (/\bcli\b|command/.test(nameText)) return "cli";
125896
+ if (/\bapi\b|service|backend/.test(nameText)) return "api";
125897
+ if (/dashboard|frontend|web|ui/.test(nameText)) return "web-ui";
125898
+ return "unknown";
125899
+ }
125900
+ function buildHumanAcceptanceSummary(summary) {
125901
+ const badges = [];
125902
+ badges.push(`deliverable=${summary.deliverable}`);
125903
+ badges.push(`evidence=${summary.evidenceStatus}`);
125904
+ if (summary.fidelityStatus !== "pass") badges.push(`fidelity=${summary.fidelityStatus}`);
125905
+ if (summary.qualityGateStatus !== "pass") badges.push(`quality=${summary.qualityGateStatus}`);
125906
+ if (summary.donePolicyStatus !== "pass") badges.push(`done=${summary.donePolicyStatus}`);
125907
+ const concerns = summary.openConcerns.filter(
125908
+ (c) => c === "quality_criticality_high_requires_conservative_review" || c.startsWith("risk:") || c === "deliverable_inference_is_unknown"
125909
+ );
125910
+ if (concerns.length > 0) {
125911
+ badges.push(`concerns=${concerns.slice(0, 3).join(",")}`);
125912
+ }
125913
+ return badges.join(" | ");
125914
+ }
125707
125915
  async function persistMergedArtifact(opts) {
125708
125916
  const { workspaceDir, projectSlug, issueId, issueRuntime, prUrl, headSha } = opts;
125709
125917
  const prNumber = issueRuntime?.currentPrNumber ?? null;
@@ -125782,7 +125990,74 @@ async function executeCompletion(opts) {
125782
125990
  let mergedArtifactHeadSha;
125783
125991
  const project = await loadProjectBySlug(workspaceDir, projectSlug);
125784
125992
  const issueRuntime = project ? getIssueRuntime(project, issueId) : void 0;
125993
+ const deliverable = resolvePipelineDeliverable(project);
125994
+ const qualityCriticality = issueRuntime?.qualityCriticality ?? "medium";
125995
+ const qualityPolicy = resolveQualityGatePolicy({ deliverable, qualityCriticality });
125996
+ const donePolicy = resolveDonePolicy({ deliverable, qualityCriticality: qualityPolicy.qualityCriticalityFloor });
125785
125997
  const prSelector = issueRuntime?.currentPrNumber ? { prNumber: issueRuntime.currentPrNumber } : void 0;
125998
+ const closeRequested = completionRule.actions.includes(Action.CLOSE_ISSUE);
125999
+ const hasEvidence = hasMeaningfulCompletionEvidence(effectiveSummary, prUrl, createdTasks);
126000
+ const hasArchetypeEvidence = hasArchetypeSpecificEvidence(deliverable, effectiveSummary, prUrl, createdTasks);
126001
+ const finalAcceptance = buildFinalAcceptanceSummary({
126002
+ deliverable,
126003
+ qualityPolicy,
126004
+ donePolicy,
126005
+ hasEvidence,
126006
+ closeRequested,
126007
+ qualityCriticality,
126008
+ riskProfile: issueRuntime?.riskProfile ?? []
126009
+ });
126010
+ await log(workspaceDir, "completion_policy_snapshot", {
126011
+ project: projectName,
126012
+ issue: issueId,
126013
+ role,
126014
+ deliverable,
126015
+ qualityGateChecks: qualityPolicy.requiredChecks,
126016
+ requiredEvidence: qualityPolicy.requiredEvidence,
126017
+ doneArtifacts: donePolicy.requiredArtifacts,
126018
+ doneEvidence: donePolicy.requiredEvidence,
126019
+ qualityCriticality,
126020
+ qualityCriticalityFloor: qualityPolicy.qualityCriticalityFloor,
126021
+ riskProfile: issueRuntime?.riskProfile ?? [],
126022
+ finalAcceptance
126023
+ }).catch(() => {
126024
+ });
126025
+ await log(workspaceDir, "final_acceptance_summary", {
126026
+ project: projectName,
126027
+ issue: issueId,
126028
+ role,
126029
+ ...finalAcceptance
126030
+ }).catch(() => {
126031
+ });
126032
+ if (closeRequested && !hasEvidence) {
126033
+ await log(workspaceDir, "completion_policy_block", {
126034
+ project: projectName,
126035
+ issue: issueId,
126036
+ role,
126037
+ result,
126038
+ reason: "missing_completion_evidence",
126039
+ deliverable,
126040
+ requiredEvidence: donePolicy.requiredEvidence
126041
+ }).catch(() => {
126042
+ });
126043
+ throw new Error(
126044
+ `Refusing to complete issue #${issueId} without meaningful completion evidence for ${deliverable}. Provide a substantive summary, PR evidence, or created-task evidence before close.`
126045
+ );
126046
+ }
126047
+ if (closeRequested && !hasArchetypeEvidence) {
126048
+ await log(workspaceDir, "completion_policy_block", {
126049
+ project: projectName,
126050
+ issue: issueId,
126051
+ role,
126052
+ result,
126053
+ reason: "missing_archetype_specific_evidence",
126054
+ deliverable
126055
+ }).catch(() => {
126056
+ });
126057
+ throw new Error(
126058
+ `Refusing to complete issue #${issueId} because the final summary lacks ${deliverable}-specific evidence. Describe the relevant ${deliverable} behavior more concretely or attach PR/task evidence.`
126059
+ );
126060
+ }
125786
126061
  const shouldBlockMergeBeforeTest = completionRule.actions.includes(Action.MERGE_PR) && role === "reviewer" && (workflow.testPolicy ?? TestPolicy.SKIP) === TestPolicy.AGENT;
125787
126062
  if (shouldBlockMergeBeforeTest) {
125788
126063
  completionRule = {
@@ -125930,6 +126205,7 @@ async function executeCompletion(opts) {
125930
126205
  }
125931
126206
  const notifyConfig = getNotificationConfig(pluginConfig);
125932
126207
  await provider.transitionLabel(issueId, completionRule.from, completionRule.to);
126208
+ const acceptanceSummary = buildHumanAcceptanceSummary(finalAcceptance);
125933
126209
  for (const action of completionRule.actions) {
125934
126210
  switch (action) {
125935
126211
  case Action.CLOSE_ISSUE:
@@ -125951,7 +126227,8 @@ async function executeCompletion(opts) {
125951
126227
  issueId,
125952
126228
  issueUrl: issue2.web_url,
125953
126229
  issueTitle: issue2.title,
125954
- prUrl
126230
+ prUrl,
126231
+ acceptanceSummary
125955
126232
  },
125956
126233
  {
125957
126234
  workspaceDir,
@@ -126015,6 +126292,7 @@ async function executeCompletion(opts) {
126015
126292
  name: workerName,
126016
126293
  result: effectiveResult,
126017
126294
  summary: effectiveSummary,
126295
+ acceptanceSummary,
126018
126296
  nextState,
126019
126297
  prUrl,
126020
126298
  createdTasks,
@@ -126132,7 +126410,8 @@ ${nextState}.`;
126132
126410
  prUrl,
126133
126411
  issueUrl: issue2.web_url,
126134
126412
  issueClosed: completionRule.actions.includes(Action.CLOSE_ISSUE),
126135
- issueReopened: completionRule.actions.includes(Action.REOPEN_ISSUE)
126413
+ issueReopened: completionRule.actions.includes(Action.REOPEN_ISSUE),
126414
+ finalAcceptance
126136
126415
  };
126137
126416
  }
126138
126417
  function describeStateByLabel(workflow, label) {
@@ -129055,6 +129334,7 @@ async function dispatchTask(opts) {
129055
129334
  pluginConfig,
129056
129335
  runtime
129057
129336
  } = opts;
129337
+ const triggerSource = opts.triggerSource ?? "unknown";
129058
129338
  const slotIndex = opts.slotIndex ?? 0;
129059
129339
  const rc = opts.runCommand;
129060
129340
  const resolvedConfig = await loadConfig(workspaceDir, project.slug);
@@ -129101,6 +129381,8 @@ async function dispatchTask(opts) {
129101
129381
  role,
129102
129382
  level,
129103
129383
  fromLabel,
129384
+ triggerSource,
129385
+ dispatchSemantic: "feedback_redispatch",
129104
129386
  sessionKey: existingSessionKey,
129105
129387
  reason: "developer_feedback_cycle_requires_fresh_context"
129106
129388
  }).catch(() => {
@@ -129147,6 +129429,8 @@ async function dispatchTask(opts) {
129147
129429
  issue: issueId,
129148
129430
  role,
129149
129431
  level,
129432
+ triggerSource,
129433
+ dispatchSemantic: feedbackFreshSession ? "feedback_redispatch" : "fresh_dispatch",
129150
129434
  sessionKey,
129151
129435
  reason: feedbackFreshSession ? "gateway_session_alive_without_local_slot_tracking_after_feedback_reset" : "gateway_session_alive_without_local_slot_tracking"
129152
129436
  }).catch(() => {
@@ -129444,7 +129728,8 @@ async function dispatchTask(opts) {
129444
129728
  originalModel: effectiveModel.downgraded ? resolvedModel : void 0,
129445
129729
  effectiveModel: effectiveModel.downgraded ? model : void 0,
129446
129730
  dispatchCycleId,
129447
- dispatchRunId: sendResult.runId
129731
+ dispatchRunId: sendResult.runId,
129732
+ triggerSource
129448
129733
  },
129449
129734
  {
129450
129735
  workspaceDir,
@@ -129478,6 +129763,8 @@ async function dispatchTask(opts) {
129478
129763
  modelAvailability: effectiveModel.availableModels,
129479
129764
  workflowMeta: resolvedConfig.workflowMeta,
129480
129765
  sessionAction,
129766
+ dispatchSemantic,
129767
+ triggerSource,
129481
129768
  sessionKey,
129482
129769
  fromLabel,
129483
129770
  toLabel,
@@ -129514,7 +129801,9 @@ async function auditDispatch(workspaceDir, opts) {
129514
129801
  role: opts.role,
129515
129802
  level: opts.level,
129516
129803
  sessionAction: opts.sessionAction,
129804
+ dispatchSemantic: opts.dispatchSemantic,
129517
129805
  sessionKey: opts.sessionKey,
129806
+ triggerSource: opts.triggerSource,
129518
129807
  sessionLabel: opts.sessionLabel,
129519
129808
  sessionLabelFull: opts.sessionLabelFull,
129520
129809
  labelTransition: `${opts.fromLabel} \u2192 ${opts.toLabel}`
@@ -129525,6 +129814,8 @@ async function auditDispatch(workspaceDir, opts) {
129525
129814
  role: opts.role,
129526
129815
  level: opts.level,
129527
129816
  sessionAction: opts.sessionAction,
129817
+ dispatchSemantic: opts.dispatchSemantic,
129818
+ triggerSource: opts.triggerSource,
129528
129819
  sessionKey: opts.sessionKey,
129529
129820
  sessionLabel: opts.sessionLabel,
129530
129821
  sessionLabelFull: opts.sessionLabelFull
@@ -141231,6 +141522,8 @@ var triageStep = {
141231
141522
  childReadyForDispatch: decision.targetState === "To Do",
141232
141523
  parallelizable: child.draft.parallelizable,
141233
141524
  recommendedLevel: child.draft.recommendedLevel,
141525
+ qualityCriticality: decision.qualityCriticality,
141526
+ riskProfile: decision.riskProfile,
141234
141527
  decompositionMode: "none",
141235
141528
  decompositionStatus: null
141236
141529
  }).catch(() => {
@@ -141239,6 +141532,8 @@ var triageStep = {
141239
141532
  await updateIssueRuntime(ctx.workspaceDir, projectSlug, issue2.number, {
141240
141533
  childIssueIds: createdChildIssueNumbers,
141241
141534
  maxParallelChildren: computeMaxParallelChildren(decompositionDrafts),
141535
+ qualityCriticality: decision.qualityCriticality,
141536
+ riskProfile: decision.riskProfile,
141242
141537
  decompositionMode: "parent_child",
141243
141538
  decompositionStatus: "active"
141244
141539
  }).catch(() => {
@@ -141356,6 +141651,14 @@ var triageStep = {
141356
141651
  }).catch(() => {
141357
141652
  });
141358
141653
  }
141654
+ const resolvedProjectSlug = payload.metadata?.project_slug ?? payload.scaffold?.project_slug ?? null;
141655
+ if (resolvedProjectSlug) {
141656
+ await updateIssueRuntime(ctx.workspaceDir, resolvedProjectSlug, issue2.number, {
141657
+ qualityCriticality: decision.qualityCriticality,
141658
+ riskProfile: decision.riskProfile
141659
+ }).catch(() => {
141660
+ });
141661
+ }
141359
141662
  return {
141360
141663
  ...payload,
141361
141664
  step: "triage",
@@ -141843,6 +142146,7 @@ async function projectTick(opts) {
141843
142146
  instanceName,
141844
142147
  runCommand
141845
142148
  } = opts;
142149
+ const triggerSource = opts.triggerSource ?? (targetRole ? "followup_tick" : "heartbeat_periodic");
141846
142150
  const ensureEnvironment = opts.ensureEnvironmentReady ?? ensureEnvironmentReady;
141847
142151
  const dispatch = opts.dispatchTask ?? dispatchTask;
141848
142152
  const project = getProject(await readProjects(workspaceDir), projectSlug);
@@ -142122,7 +142426,8 @@ async function projectTick(opts) {
142122
142426
  runtime,
142123
142427
  slotIndex: freeSlot,
142124
142428
  instanceName,
142125
- runCommand
142429
+ runCommand,
142430
+ triggerSource
142126
142431
  });
142127
142432
  pickups.push({
142128
142433
  project: project.name,
@@ -142133,6 +142438,7 @@ async function projectTick(opts) {
142133
142438
  role,
142134
142439
  level: dr.level,
142135
142440
  sessionAction: dr.sessionAction,
142441
+ triggerSource,
142136
142442
  announcement: dr.announcement
142137
142443
  });
142138
142444
  await recordDispatch(workspaceDir, dispatchId).catch(() => {
@@ -143311,7 +143617,8 @@ async function completeRegisteredBootstrap(ctx, workspaceDir, session) {
143311
143617
  pluginConfig: ctx.pluginConfig,
143312
143618
  runtime: ctx.runtime,
143313
143619
  runCommand: ctx.runCommand,
143314
- maxPickups: 1
143620
+ maxPickups: 1,
143621
+ triggerSource: "bootstrap_immediate_tick"
143315
143622
  });
143316
143623
  } catch (error48) {
143317
143624
  logBootstrapWarning(ctx, `[telegram-bootstrap] immediate projectTick failed: ${error48 instanceof Error ? error48.message : String(error48)}`);
@@ -145881,7 +146188,8 @@ async function tick(opts) {
145881
146188
  maxPickups: remaining,
145882
146189
  instanceName,
145883
146190
  runtime,
145884
- runCommand
146191
+ runCommand,
146192
+ triggerSource: "heartbeat_periodic"
145885
146193
  });
145886
146194
  result.totalPickups += tickResult.pickups.length;
145887
146195
  result.totalSkipped += tickResult.skipped.length;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mestreyoda/fabrica",
3
- "version": "0.2.23",
3
+ "version": "0.2.24",
4
4
  "description": "Autonomous software engineering pipeline for OpenClaw. Turns ideas into deployed code via intake, dispatch, review, test, and merge.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",