@jaimevalasek/aioson 1.33.1 → 1.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/CHANGELOG.md +76 -0
  2. package/docs/en/1-understand/ecosystem-map.md +45 -29
  3. package/docs/en/1-understand/glossary.md +6 -6
  4. package/docs/en/1-understand/what-is-aioson.md +5 -5
  5. package/docs/en/2-start/existing-project.md +7 -7
  6. package/docs/en/2-start/first-project.md +33 -39
  7. package/docs/en/2-start/initial-decisions.md +22 -19
  8. package/docs/en/3-recipes/README.md +2 -2
  9. package/docs/en/3-recipes/continuity-between-sessions.md +2 -2
  10. package/docs/en/3-recipes/from-idea-to-prd-via-briefing.md +13 -3
  11. package/docs/en/3-recipes/full-feature-with-sheldon.md +329 -338
  12. package/docs/en/4-agents/README.md +33 -16
  13. package/docs/en/4-agents/briefing-refiner.md +146 -0
  14. package/docs/en/4-agents/discovery-design-doc.md +20 -8
  15. package/docs/en/4-agents/forge-run.md +3 -2
  16. package/docs/en/5-reference/README.md +1 -0
  17. package/docs/en/5-reference/autopilot-handoff.md +286 -0
  18. package/docs/en/5-reference/cli-reference.md +57 -48
  19. package/docs/en/5-reference/executable-verification.md +10 -7
  20. package/docs/en/5-reference/parallel.md +2 -0
  21. package/docs/en/5-reference/qa-browser.md +2 -2
  22. package/docs/en/README.md +3 -3
  23. package/docs/pt/1-entender/glossario.md +5 -5
  24. package/docs/pt/1-entender/mapa-do-ecossistema.md +33 -22
  25. package/docs/pt/2-comecar/decisoes-iniciais.md +20 -18
  26. package/docs/pt/2-comecar/primeiro-projeto.md +2 -2
  27. package/docs/pt/3-receitas/README.md +1 -1
  28. package/docs/pt/3-receitas/app-saas-do-zero.md +35 -122
  29. package/docs/pt/3-receitas/da-ideia-ao-prd-via-briefing.md +8 -1
  30. package/docs/pt/3-receitas/feature-completa-com-sheldon.md +291 -338
  31. package/docs/pt/4-agentes/README.md +13 -11
  32. package/docs/pt/4-agentes/analyst.md +9 -5
  33. package/docs/pt/4-agentes/architect.md +9 -5
  34. package/docs/pt/4-agentes/briefing-refiner.md +64 -40
  35. package/docs/pt/4-agentes/briefing.md +6 -1
  36. package/docs/pt/4-agentes/dev.md +38 -8
  37. package/docs/pt/4-agentes/deyvin.md +4 -0
  38. package/docs/pt/4-agentes/discover.md +4 -0
  39. package/docs/pt/4-agentes/discovery-design-doc.md +25 -23
  40. package/docs/pt/4-agentes/neo.md +4 -0
  41. package/docs/pt/4-agentes/orache.md +6 -0
  42. package/docs/pt/4-agentes/orchestrator.md +176 -118
  43. package/docs/pt/4-agentes/pentester.md +11 -5
  44. package/docs/pt/4-agentes/pm.md +15 -7
  45. package/docs/pt/4-agentes/product.md +19 -1
  46. package/docs/pt/4-agentes/qa.md +10 -2
  47. package/docs/pt/4-agentes/setup.md +3 -1
  48. package/docs/pt/4-agentes/sheldon.md +178 -99
  49. package/docs/pt/4-agentes/tester.md +6 -0
  50. package/docs/pt/4-agentes/ux-ui.md +9 -5
  51. package/docs/pt/5-referencia/README.md +1 -1
  52. package/docs/pt/5-referencia/agent-chain-continuity.md +14 -5
  53. package/docs/pt/5-referencia/autopilot-handoff.md +191 -74
  54. package/docs/pt/5-referencia/comandos-cli.md +16 -7
  55. package/docs/pt/5-referencia/sdd-automation-scripts.md +6 -6
  56. package/docs/pt/5-referencia/sdd-framework.md +53 -16
  57. package/docs/pt/5-referencia/sdd-planos-e-estrutura.md +27 -15
  58. package/docs/pt/5-referencia/skills.md +2 -0
  59. package/docs/pt/README.md +4 -4
  60. package/docs/pt/agentes.md +50 -50
  61. package/package.json +2 -2
  62. package/src/agents.js +1 -1
  63. package/src/artifact-kinds.js +111 -0
  64. package/src/autopilot-signal.js +71 -0
  65. package/src/cli.js +112 -81
  66. package/src/commands/agent-epilogue.js +251 -186
  67. package/src/commands/agents.js +122 -50
  68. package/src/commands/audit-code.js +344 -0
  69. package/src/commands/briefing.js +337 -1
  70. package/src/commands/classify.js +389 -389
  71. package/src/commands/feature-close.js +122 -4
  72. package/src/commands/harness-check.js +259 -175
  73. package/src/commands/live.js +71 -11
  74. package/src/commands/review-feature.js +189 -0
  75. package/src/commands/runtime.js +81 -66
  76. package/src/commands/sync-agents-copy.js +115 -0
  77. package/src/commands/update.js +5 -1
  78. package/src/commands/verification-plan.js +143 -0
  79. package/src/commands/verify-artifact.js +593 -0
  80. package/src/commands/workflow-execute.js +434 -316
  81. package/src/commands/workflow-next.js +193 -20
  82. package/src/commands/workflow-plan.js +5 -5
  83. package/src/constants.js +2 -0
  84. package/src/doctor.js +4 -2
  85. package/src/gateway-pointer-merge.js +7 -1
  86. package/src/handoff-contract.js +267 -172
  87. package/src/harness/contract-integrity-gate.js +172 -0
  88. package/src/harness/contract-integrity.js +111 -0
  89. package/src/harness/contract-schema.js +377 -332
  90. package/src/harness/detect-runtime-feature.js +90 -0
  91. package/src/harness/static-criteria.js +192 -0
  92. package/src/i18n/messages/en.js +10 -5
  93. package/src/i18n/messages/es.js +10 -5
  94. package/src/i18n/messages/fr.js +10 -5
  95. package/src/i18n/messages/pt-BR.js +10 -5
  96. package/src/install-wizard.js +8 -8
  97. package/src/installer.js +13 -6
  98. package/src/lib/briefing-refiner/apply-feedback.js +18 -4
  99. package/src/lib/briefing-refiner/feedback-schema.js +73 -4
  100. package/src/lib/briefing-refiner/refinement-report.js +11 -0
  101. package/src/lib/briefing-refiner/review-html.js +388 -68
  102. package/src/parser.js +12 -0
  103. package/src/preflight-engine.js +12 -12
  104. package/src/verification/policy-engine.js +95 -95
  105. package/src/verification-policy.js +398 -0
  106. package/src/version.js +52 -1
  107. package/template/.aioson/agents/architect.md +34 -5
  108. package/template/.aioson/agents/briefing-refiner.md +91 -48
  109. package/template/.aioson/agents/briefing.md +4 -0
  110. package/template/.aioson/agents/committer.md +2 -1
  111. package/template/.aioson/agents/copywriter.md +30 -21
  112. package/template/.aioson/agents/design-hybrid-forge.md +10 -1
  113. package/template/.aioson/agents/dev.md +35 -23
  114. package/template/.aioson/agents/deyvin.md +4 -0
  115. package/template/.aioson/agents/discover.md +16 -3
  116. package/template/.aioson/agents/discovery-design-doc.md +7 -2
  117. package/template/.aioson/agents/genome.md +19 -10
  118. package/template/.aioson/agents/neo.md +34 -30
  119. package/template/.aioson/agents/orache.md +24 -11
  120. package/template/.aioson/agents/orchestrator.md +100 -7
  121. package/template/.aioson/agents/pentester.md +4 -0
  122. package/template/.aioson/agents/pm.md +8 -8
  123. package/template/.aioson/agents/product.md +25 -1
  124. package/template/.aioson/agents/profiler-enricher.md +20 -11
  125. package/template/.aioson/agents/profiler-forge.md +20 -11
  126. package/template/.aioson/agents/profiler-researcher.md +20 -11
  127. package/template/.aioson/agents/qa.md +96 -31
  128. package/template/.aioson/agents/setup.md +12 -1
  129. package/template/.aioson/agents/sheldon.md +103 -13
  130. package/template/.aioson/agents/site-forge.md +11 -2
  131. package/template/.aioson/agents/squad.md +20 -5
  132. package/template/.aioson/agents/tester.md +4 -0
  133. package/template/.aioson/agents/ux-ui.md +2 -1
  134. package/template/.aioson/agents/validator.md +33 -1
  135. package/template/.aioson/config/verification.json +61 -0
  136. package/template/.aioson/config.md +13 -9
  137. package/template/.aioson/docs/LAYERS.md +2 -2
  138. package/template/.aioson/docs/agent-help.md +126 -0
  139. package/template/.aioson/docs/autopilot-handoff.md +30 -20
  140. package/template/.aioson/docs/dev/execution-discipline.md +41 -0
  141. package/template/.aioson/docs/dev/phase-loop.md +50 -0
  142. package/template/.aioson/docs/play/llm-data-and-bindings.md +70 -7
  143. package/template/.aioson/docs/presets/workflow.config.full-merged.json +15 -0
  144. package/template/.aioson/docs/presets/workflow.config.lean.json +15 -0
  145. package/template/.aioson/docs/product/prd-contract.md +12 -12
  146. package/template/.aioson/docs/prototype-contract.md +21 -4
  147. package/template/.aioson/docs/reference-identity.md +94 -0
  148. package/template/.aioson/docs/sheldon/harness-contract.md +155 -28
  149. package/template/.aioson/docs/verification-config.md +82 -0
  150. package/template/.aioson/docs/verify-artifact-gates.md +91 -0
  151. package/template/.aioson/docs/workflow-lean-lane.md +129 -0
  152. package/template/.aioson/skills/design/interface-design/SKILL.md +17 -0
  153. package/template/.aioson/skills/design/interface-design/references/intent-and-domain.md +2 -0
  154. package/template/.aioson/skills/process/aioson-spec-driven/SKILL.md +16 -14
  155. package/template/.aioson/skills/process/aioson-spec-driven/references/approval-gates.md +2 -2
  156. package/template/.aioson/skills/process/aioson-spec-driven/references/classification-map.md +4 -4
  157. package/template/.aioson/skills/process/aioson-spec-driven/references/dev.md +15 -15
  158. package/template/.aioson/skills/process/prototype-forge/SKILL.md +6 -0
  159. package/template/.aioson/skills/process/reference-identity-extract/SKILL.md +164 -0
  160. package/template/.aioson/skills/static/multi-agent-patterns.md +5 -5
  161. package/template/AGENTS.md +36 -36
  162. package/template/CLAUDE.md +15 -11
@@ -16,6 +16,7 @@ const { logError, buildHealingPrompt } = require('../self-healing');
16
16
  const { validateHandoffProtocol } = require('../handoff-validator');
17
17
  const { readAutonomyProtocol, resolveEffectiveMode } = require('../autonomy-policy');
18
18
  const { readAgentManifest, buildAgentCapabilitySummary } = require('../agent-manifests');
19
+ const { resolveAutopilotSignal } = require('../autopilot-signal');
19
20
  const { runMemoryReflectPrepare } = require('./memory-reflect-prepare');
20
21
  const { inspectStagedChanges } = require('../lib/git-commit-guard');
21
22
  const { emitSecurityRuntimeEvent } = require('../lib/security/runtime-events');
@@ -26,6 +27,11 @@ const { emitDossierEvent } = require('../lib/dossier-telemetry');
26
27
  const { parseVerificationReport } = require('../verification/report-parser');
27
28
  const { applyPolicy } = require('../verification/policy-engine');
28
29
  const { normalizePolicy } = require('../verification/result');
30
+ const {
31
+ evaluateContractIntegrityGate,
32
+ formatContractIntegrityGateError
33
+ } = require('../harness/contract-integrity-gate');
34
+ const { runSpecAnalyze } = require('./spec-analyze');
29
35
  const {
30
36
  validateFeatureSlug,
31
37
  featureContextDir,
@@ -40,22 +46,34 @@ const SCOPE_CHECK_MODES = new Set(['pre-dev', 'post-dev', 'post-fix', 'final']);
40
46
 
41
47
  const DEFAULT_FEATURE_WORKFLOW_BY_CLASSIFICATION = {
42
48
  MICRO: ['product', 'dev', 'qa'],
43
- SMALL: ['product', 'analyst', 'scope-check', 'architect', 'discovery-design-doc', 'dev', 'qa'],
44
- // MEDIUM routes through @pm after discovery-design-doc (mirrors the
45
- // project-mode position): Gate C requires implementation-plan-{slug}.md and
46
- // @pm is its canonical owner (AC-SDLC-15/16) without the stage, the
47
- // sequence dead-ends at @dev preflight with no agent to produce the plan.
48
- MEDIUM: ['product', 'analyst', 'architect', 'discovery-design-doc', 'pm', 'scope-check', 'dev', 'pentester', 'qa']
49
+ // SMALL defaults to the lean lane: @sheldon is the single spec authority
50
+ // (requirements + spec + design-doc + readiness + plan + harness-contract in
51
+ // one pass), replacing analyst/scope-check/architect/discovery-design-doc.
52
+ // Those agents remain available as opt-in detours (allowDetours: true).
53
+ SMALL: ['product', 'sheldon', 'dev', 'qa'],
54
+ // MEDIUM collapses the spec phase into @orchestrator the maestro that fans out
55
+ // to @analyst + @architect + @pm (+ @ux-ui when UI-heavy) as sub-agents, then
56
+ // consolidates/verifies/redoes their output into the gated spec package
57
+ // (requirements + spec[A/B/C approved] + design-doc + readiness + implementation-
58
+ // plan + harness-contract) and hands to @dev. SMALL = @sheldon solo (vertical),
59
+ // MEDIUM = @orchestrator fan-out (horizontal). The scope drift check is enforced at
60
+ // the dev/qa done gate (finalizeCurrentStage). @pentester stays as the post-dev
61
+ // security stage. analyst/architect/pm/ddd/scope-check/ux-ui remain opt-in detours.
62
+ MEDIUM: ['product', 'orchestrator', 'dev', 'pentester', 'qa']
49
63
  };
50
64
 
51
- // Stages eligible for autopilot handoff (auto_handoff: true in project.context.md).
52
- // Two segments — see .aioson/docs/autopilot-handoff.md:
53
- // 1. analyst -> dev: deterministic pre-dev chain. Prompt-only clients stop
54
- // before the first @dev entry; workflow:execute --agentic may resume it
55
- // through a fresh checkpointed activation.
56
- // 2. post-dev review cycle: @dev @qa @tester/@pentester (when their @qa triggers
57
- // fire) @validator STOPS before feature:close (human approves the close).
65
+ // Stages eligible for autopilot handoff the FULL feature chain (see
66
+ // .aioson/docs/autopilot-handoff.md). Activation = auto_handoff: true in
67
+ // project.context.md OR the seeded scheme (resolveAutopilotSignal). Two segments:
68
+ // 1. spec dev chain: @product seeds the agentic scheme and invokes the spec
69
+ // authority (@sheldon lean / @orchestrator maestro), which crosses into
70
+ // @dev via the dev-state.md cold-start packet once its own gates/decisions
71
+ // are settled. Detour agents (analyst/architect/pm/...) chain only when an
72
+ // opt-in detour adds them to the active sequence.
73
+ // 2. post-dev review cycle: @dev → @qa → @tester/@pentester (when their @qa
74
+ // triggers fire) → @validator → STOPS before feature:close (human gate).
58
75
  const AUTOPILOT_HANDOFF_STAGES = new Set([
76
+ 'product', 'sheldon', 'orchestrator',
59
77
  'analyst', 'scope-check', 'architect', 'discovery-design-doc', 'pm',
60
78
  'dev', 'qa', 'tester', 'pentester', 'validator'
61
79
  ]);
@@ -73,13 +91,29 @@ function normalizeClassification(value, fallback = 'MICRO') {
73
91
  return fallback;
74
92
  }
75
93
 
94
+ // MEDIUM maestro lane: @orchestrator routes straight to @dev (it is the single
95
+ // spec authority that fans out to analyst/architect/pm sub-agents and consolidates).
96
+ function isMaestroOrchestratorState(state) {
97
+ const sequence = Array.isArray(state && state.sequence) ? state.sequence.map(normalizeAgentName) : [];
98
+ const idx = sequence.indexOf('orchestrator');
99
+ return idx !== -1 && sequence[idx + 1] === 'dev';
100
+ }
101
+
102
+ // Lean lane (SMALL, sheldon → dev): @sheldon is the single spec authority.
103
+ // Mirrors isLeanSheldonState in handoff-contract.js.
104
+ function isLeanSheldonState(state) {
105
+ const sequence = Array.isArray(state && state.sequence) ? state.sequence.map(normalizeAgentName) : [];
106
+ const idx = sequence.indexOf('sheldon');
107
+ return idx !== -1 && sequence[idx + 1] === 'dev';
108
+ }
109
+
76
110
  function buildDefaultWorkflowConfig() {
77
111
  return {
78
112
  version: 1,
79
113
  project: {
80
114
  MICRO: ['setup', 'dev'],
81
- SMALL: ['setup', 'product', 'analyst', 'scope-check', 'architect', 'discovery-design-doc', 'dev', 'qa'],
82
- MEDIUM: ['setup', 'product', 'analyst', 'architect', 'discovery-design-doc', 'ux-ui', 'pm', 'orchestrator', 'scope-check', 'dev', 'qa']
115
+ SMALL: ['setup', 'product', 'sheldon', 'dev', 'qa'],
116
+ MEDIUM: ['setup', 'product', 'orchestrator', 'dev', 'qa']
83
117
  },
84
118
  feature: DEFAULT_FEATURE_WORKFLOW_BY_CLASSIFICATION,
85
119
  rules: {
@@ -350,7 +384,43 @@ async function validateStageArtifacts(targetDir, state, stage) {
350
384
  return true;
351
385
  }
352
386
 
387
+ if (stage === 'sheldon') {
388
+ // Lean lane (SMALL, sheldon → dev): @sheldon is the single spec authority —
389
+ // "done" once the collapsed spec package exists (mirrors the orchestrator
390
+ // maestro branch below; the handoff contract re-checks Gates A/B/C). Without
391
+ // this branch nothing ever marks the sheldon stage resolved, and a later
392
+ // `--complete=dev` computes `next: sheldon` — the state machine walking
393
+ // BACKWARDS into the spec agent after implementation.
394
+ if (state.mode === 'feature' && slug && isLeanSheldonState(state)) {
395
+ const designDoc = [path.join(base, `design-doc-${slug}.md`), path.join(base, 'design-doc.md')];
396
+ const readiness = [path.join(base, `readiness-${slug}.md`), path.join(base, 'readiness.md')];
397
+ return (await exists(path.join(base, `sheldon-enrichment-${slug}.md`)))
398
+ && (await exists(path.join(base, `requirements-${slug}.md`)))
399
+ && (await exists(path.join(base, `spec-${slug}.md`)))
400
+ && (await exists(path.join(base, `implementation-plan-${slug}.md`)))
401
+ && (await anyExists(designDoc))
402
+ && (await anyExists(readiness));
403
+ }
404
+ if (state.mode === 'feature' && slug) {
405
+ return await exists(path.join(base, `sheldon-enrichment-${slug}.md`));
406
+ }
407
+ return await exists(path.join(base, 'sheldon-enrichment.md'));
408
+ }
409
+
353
410
  if (stage === 'orchestrator') {
411
+ // Maestro lane (MEDIUM, orchestrator → dev): the orchestrator is the single
412
+ // spec authority — "done" once the gated spec package exists (mirrors how the
413
+ // per-hop stages were inferred). Otherwise it is the parallel-impl coordinator
414
+ // and owns the lane workspace.
415
+ if (state.mode === 'feature' && slug && isMaestroOrchestratorState(state)) {
416
+ const designDoc = [path.join(base, `design-doc-${slug}.md`), path.join(base, 'design-doc.md')];
417
+ const readiness = [path.join(base, `readiness-${slug}.md`), path.join(base, 'readiness.md')];
418
+ return (await exists(path.join(base, `requirements-${slug}.md`)))
419
+ && (await exists(path.join(base, `spec-${slug}.md`)))
420
+ && (await exists(path.join(base, `implementation-plan-${slug}.md`)))
421
+ && (await anyExists(designDoc))
422
+ && (await anyExists(readiness));
423
+ }
354
424
  return await exists(path.join(base, 'parallel'));
355
425
  }
356
426
 
@@ -480,7 +550,10 @@ function isInferableStage(stage) {
480
550
  // could never infer scope-check as completed during stale-state recovery.
481
551
  // pm is inferable from implementation-plan-{slug}.md for the same reason:
482
552
  // it sits before scope-check in the MEDIUM feature sequence.
483
- return ['setup', 'product', 'analyst', 'scope-check', 'architect', 'discovery-design-doc', 'ux-ui', 'pm', 'orchestrator'].includes(
553
+ // sheldon (lean lane) and orchestrator (maestro lane) are the single spec
554
+ // authorities — both inferable from their collapsed spec package so stale-state
555
+ // recovery and mid-lane seeding never re-activate a finished spec stage.
556
+ return ['setup', 'product', 'analyst', 'scope-check', 'architect', 'discovery-design-doc', 'ux-ui', 'pm', 'sheldon', 'orchestrator'].includes(
484
557
  normalizeAgentName(stage)
485
558
  );
486
559
  }
@@ -767,9 +840,94 @@ async function finalizeCurrentStage(targetDir, config, state, stageName) {
767
840
  if (!normalizedStage) {
768
841
  throw new Error('No stage is active to complete.');
769
842
  }
843
+ let auditCodeSummary = null;
770
844
 
771
845
  // ── Harness Done Gate ───────────────────────────────────────────────────
772
846
  if (state.mode === 'feature' && state.featureSlug) {
847
+ if (normalizedStage === 'dev' || normalizedStage === 'qa') {
848
+ const integrityGate = await evaluateContractIntegrityGate(targetDir, state.featureSlug, {
849
+ runChecks: true
850
+ });
851
+ if (!integrityGate.ok) {
852
+ const errMsg = formatContractIntegrityGateError(integrityGate, normalizedStage);
853
+ await logError(targetDir, normalizedStage, errMsg, 'harness-contract');
854
+ throw new Error(errMsg);
855
+ }
856
+
857
+ // ── Scope drift gate (absorbs @scope-check's deterministic spec:analyze) ──
858
+ // scope-check is no longer a default stage; preserve its drift check so a
859
+ // dev/qa completion still blocks on real drift — a design-doc/readiness that
860
+ // declares `readiness: blocked`, or a malformed/invalid harness-contract.json.
861
+ // Non-strict spec:analyze only raises error-severity findings for those
862
+ // genuine problems (never for merely-absent artifacts), so this never
863
+ // false-blocks an artifact-light feature. Defensive: never crashes the run.
864
+ try {
865
+ const drift = await runSpecAnalyze({
866
+ args: [targetDir],
867
+ options: { feature: state.featureSlug },
868
+ logger: { log() {}, error() {} }
869
+ });
870
+ if (drift && Array.isArray(drift.findings) && drift.summary && drift.summary.errors > 0) {
871
+ const errs = drift.findings
872
+ .filter((f) => f.severity === 'error')
873
+ .map((f) => ` - ${f.check}: ${f.message}`)
874
+ .join('\n');
875
+ const driftMsg = `[Scope Drift Gate] @${normalizedStage} blocked — spec:analyze found ${drift.summary.errors} drift error(s):\n${errs}\nResolve the drift (or run @scope-check) before completing this stage.`;
876
+ await logError(targetDir, normalizedStage, driftMsg, 'scope-drift');
877
+ throw new Error(driftMsg);
878
+ }
879
+ } catch (driftErr) {
880
+ if (driftErr && driftErr.message && driftErr.message.includes('[Scope Drift Gate]')) throw driftErr;
881
+ // spec:analyze unavailable or non-analyzable — non-blocking
882
+ }
883
+
884
+ // ── Code-quality gate (deterministic audit:code) ───────────────────────
885
+ // Build-free scan of the changed files for the non-security categories
886
+ // (anti-patterns / TODOs / dead code / duplication). Unlike the integrity
887
+ // and drift gates above — which enforce the feature's DECLARED contract /
888
+ // spec — audit:code is a heuristic opinion, so it defaults to ADVISORY: the
889
+ // report is persisted (.aioson/context/audit-code.json), a guard event is
890
+ // emitted, and a summary rides the finalize result, but the stage is NOT
891
+ // blocked. Set verification.json `audit_code.tracked_gate: "block"` to make a
892
+ // HIGH finding in scope a hard gate, or "off" to skip. Defensive: only a
893
+ // deliberate block-mode throw escapes; any other error is swallowed.
894
+ try {
895
+ const { readVerificationConfig, getAuditCodePolicy } = require('../verification-policy');
896
+ const auditPolicy = getAuditCodePolicy(await readVerificationConfig(targetDir));
897
+ if (auditPolicy.tracked_gate !== 'off') {
898
+ const { runAuditCode } = require('./audit-code');
899
+ const codeAudit = await runAuditCode({
900
+ args: [targetDir],
901
+ options: { changed: auditPolicy.scope !== 'full', json: true, suppressExitCode: true },
902
+ logger: { log() {}, error() {} }
903
+ });
904
+ const high = codeAudit && codeAudit.by_severity ? (codeAudit.by_severity.HIGH || 0) : 0;
905
+ const med = codeAudit && codeAudit.by_severity ? (codeAudit.by_severity.MED || 0) : 0;
906
+ const categories = Object.keys((codeAudit && codeAudit.by_category) || {});
907
+ auditCodeSummary = { gate: auditPolicy.tracked_gate, scope: auditPolicy.scope, high, med, categories };
908
+ if (high > 0 && auditPolicy.tracked_gate === 'block') {
909
+ const msg = `[Code-Quality Gate] @${normalizedStage} blocked — audit:code found ${high} HIGH finding(s) in the ${auditPolicy.scope} files (${categories.join(', ')}). Fix them, or relax verification.json audit_code.tracked_gate to "advisory"/"off". See .aioson/context/audit-code.json`;
910
+ await logError(targetDir, normalizedStage, msg, 'audit-code');
911
+ throw new Error(msg);
912
+ }
913
+ if (high > 0) {
914
+ try {
915
+ const { emitGuardEvent } = require('../harness/guard-events');
916
+ await emitGuardEvent(targetDir, {
917
+ eventType: 'audit_code_findings',
918
+ agent: normalizedStage,
919
+ message: `${high} HIGH / ${med} MED in ${auditPolicy.scope} files (${categories.join(', ')}) — advisory`,
920
+ payload: { slug: state.featureSlug, high, med, scope: auditPolicy.scope }
921
+ });
922
+ } catch { /* telemetry best-effort */ }
923
+ }
924
+ }
925
+ } catch (auditErr) {
926
+ if (auditErr && auditErr.message && auditErr.message.includes('[Code-Quality Gate]')) throw auditErr;
927
+ // audit:code unavailable / non-git — non-blocking
928
+ }
929
+ }
930
+
773
931
  const contractPath = path.join(targetDir, '.aioson', 'plans', state.featureSlug, 'harness-contract.json');
774
932
  const progressPath = path.join(targetDir, '.aioson', 'plans', state.featureSlug, 'progress.json');
775
933
 
@@ -869,7 +1027,18 @@ async function finalizeCurrentStage(targetDir, config, state, stageName) {
869
1027
  detour: null
870
1028
  });
871
1029
 
872
- return { state: nextState, completedStage: normalizedStage };
1030
+ // Reconcile eagerly: completing a later stage must never leave `next` pointing
1031
+ // at an earlier unresolved stage (e.g. lean-lane sheldon that only chained via
1032
+ // prompt). Without this, `--complete=dev` re-activated the spec agent and the
1033
+ // reconcile only healed on the NEXT load — after the backwards activation had
1034
+ // already been printed and persisted.
1035
+ const reconciled = reconcileWorkflowState(nextState);
1036
+
1037
+ return {
1038
+ state: reconciled.changed ? reconciled.state : nextState,
1039
+ completedStage: normalizedStage,
1040
+ ...(auditCodeSummary ? { auditCode: auditCodeSummary } : {})
1041
+ };
873
1042
  }
874
1043
 
875
1044
  /**
@@ -1432,9 +1601,12 @@ async function activateStage(
1432
1601
  state.mode === 'feature' &&
1433
1602
  (state.classification === 'SMALL' || state.classification === 'MEDIUM')
1434
1603
  ) {
1604
+ // Frontmatter flag OR the seeded scheme (slug-scoped) — the per-feature
1605
+ // "Autopilot" choice only seeds workflow-execute.json and never writes
1606
+ // auto_handoff, so reading the frontmatter alone silently disabled it.
1435
1607
  try {
1436
- const projectContext = await validateProjectContextFile(targetDir);
1437
- autoHandoff = Boolean(projectContext && projectContext.data && projectContext.data.auto_handoff === true);
1608
+ const signal = await resolveAutopilotSignal(targetDir, { slug: state.featureSlug });
1609
+ autoHandoff = signal.enabled;
1438
1610
  } catch {
1439
1611
  autoHandoff = false;
1440
1612
  }
@@ -1608,7 +1780,8 @@ async function runWorkflowNext({ args, options, logger, t }) {
1608
1780
  const autoHeal = Boolean(options['auto-heal'] || options.autoHeal);
1609
1781
  const isHealabled = autoHeal && (
1610
1782
  err.message.includes('[Technical Gate BLOCKED]') ||
1611
- err.message.includes('[Handoff Contract BLOCKED]')
1783
+ err.message.includes('[Handoff Contract BLOCKED]') ||
1784
+ err.message.includes('[Harness Contract Gate BLOCKED]')
1612
1785
  );
1613
1786
  if (isHealabled) {
1614
1787
  const failedStage = normalizeAgentName(options.complete === true ? state.current || state.next : options.complete);
@@ -3,11 +3,11 @@
3
3
  const path = require('node:path');
4
4
  const { validateProjectContextFile } = require('../context');
5
5
 
6
- const WORKFLOW_BY_CLASSIFICATION = {
7
- MICRO: ['setup', 'dev'],
8
- SMALL: ['setup', 'product', 'analyst', 'scope-check', 'architect', 'dev', 'qa'],
9
- MEDIUM: ['setup', 'product', 'analyst', 'architect', 'ux-ui', 'pm', 'orchestrator', 'scope-check', 'dev', 'qa']
10
- };
6
+ const WORKFLOW_BY_CLASSIFICATION = {
7
+ MICRO: ['setup', 'dev'],
8
+ SMALL: ['setup', 'product', 'sheldon', 'dev', 'qa'],
9
+ MEDIUM: ['setup', 'product', 'orchestrator', 'dev', 'qa']
10
+ };
11
11
 
12
12
  function normalizeClassification(value, fallback = 'MICRO') {
13
13
  const text = String(value || '').trim().toUpperCase();
package/src/constants.js CHANGED
@@ -47,6 +47,7 @@ const MANAGED_FILES = [
47
47
  '.aioson/docs/squad/genome-bindings.md',
48
48
  '.aioson/docs/feature-expansion-taxonomy.md',
49
49
  '.aioson/docs/prototype-contract.md',
50
+ '.aioson/docs/reference-identity.md',
50
51
  '.aioson/docs/product/conversation-playbook.md',
51
52
  '.aioson/docs/product/research-loop.md',
52
53
  '.aioson/docs/product/quality-lens.md',
@@ -83,6 +84,7 @@ const MANAGED_FILES = [
83
84
  '.aioson/skills/process/product-scope-expansion/SKILL.md',
84
85
  '.aioson/skills/process/sheldon-expansion-audit/SKILL.md',
85
86
  '.aioson/skills/process/prototype-forge/SKILL.md',
87
+ '.aioson/skills/process/reference-identity-extract/SKILL.md',
86
88
  '.aioson/skills/static/laravel-conventions.md',
87
89
  '.aioson/skills/static/tall-stack-patterns.md',
88
90
  '.aioson/skills/static/jetstream-setup.md',
package/src/doctor.js CHANGED
@@ -228,8 +228,10 @@ async function runDoctor(targetDir) {
228
228
  }
229
229
 
230
230
  // Autopilot handoff: protocol doc installed but flag never declared in the
231
- // context frontmatter autopilot stays silently inactive (absent = manual
232
- // handoffs). An explicit true/false is a deliberate choice and passes.
231
+ // context frontmatter. Absent is no longer "silently manual" @product asks
232
+ // the run mode on screen at each feature kickoff. Declaring an explicit
233
+ // true/false sets a project default (skip the kickoff question) and passes;
234
+ // the advisory just surfaces that a default can be set.
233
235
  const autopilotDocExists = await exists(path.join(targetDir, '.aioson/docs/autopilot-handoff.md'));
234
236
  if (autopilotDocExists && contextValidation.exists && contextValidation.data) {
235
237
  const autoHandoffDeclared = Object.prototype.hasOwnProperty.call(contextValidation.data, 'auto_handoff');
@@ -31,6 +31,12 @@ function buildBlock(templateContent) {
31
31
  return `${MARKER_BEGIN}\n${BLOCK_NOTICE}\n\n${body}${MARKER_END}\n`;
32
32
  }
33
33
 
34
+ function trimBlankLinesAfterBlock(content, rangeEnd) {
35
+ let end = rangeEnd;
36
+ while (content[end] === '\n' || content[end] === '\r') end += 1;
37
+ return end;
38
+ }
39
+
34
40
  function findBlockRange(content) {
35
41
  const start = content.indexOf(MARKER_BEGIN);
36
42
  if (start === -1) return null;
@@ -71,7 +77,7 @@ async function mergeGatewayPointer({ templatePath, targetPath, backupRoot, targe
71
77
  let action;
72
78
  if (range) {
73
79
  const before = stripLegacyUnmanagedGateway(existing.slice(0, range.start));
74
- const after = existing.slice(range.end);
80
+ const after = existing.slice(trimBlankLinesAfterBlock(existing, range.end));
75
81
  const cleanBefore = before.length === 0 || before.endsWith('\n') ? before : `${before}\n`;
76
82
  next = `${cleanBefore}${block}${after}`;
77
83
  action = 'block_updated';