@jaimevalasek/aioson 1.30.2 → 1.36.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 (158) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/README.md +19 -6
  3. package/docs/en/1-understand/ecosystem-map.md +45 -29
  4. package/docs/en/1-understand/glossary.md +5 -5
  5. package/docs/en/1-understand/what-is-aioson.md +5 -5
  6. package/docs/en/2-start/existing-project.md +7 -7
  7. package/docs/en/2-start/first-project.md +32 -38
  8. package/docs/en/2-start/initial-decisions.md +18 -17
  9. package/docs/en/3-recipes/README.md +2 -2
  10. package/docs/en/3-recipes/continuity-between-sessions.md +2 -2
  11. package/docs/en/3-recipes/from-idea-to-prd-via-briefing.md +5 -2
  12. package/docs/en/3-recipes/full-feature-with-sheldon.md +327 -338
  13. package/docs/en/4-agents/README.md +28 -14
  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/cli-reference.md +51 -48
  17. package/docs/en/5-reference/executable-verification.md +10 -7
  18. package/docs/en/5-reference/parallel.md +2 -0
  19. package/docs/en/5-reference/qa-browser.md +2 -2
  20. package/docs/en/README.md +3 -3
  21. package/docs/pt/1-entender/glossario.md +4 -4
  22. package/docs/pt/1-entender/mapa-do-ecossistema.md +32 -21
  23. package/docs/pt/2-comecar/decisoes-iniciais.md +16 -16
  24. package/docs/pt/2-comecar/primeiro-projeto.md +1 -1
  25. package/docs/pt/3-receitas/README.md +1 -1
  26. package/docs/pt/3-receitas/app-saas-do-zero.md +35 -122
  27. package/docs/pt/3-receitas/feature-completa-com-sheldon.md +289 -338
  28. package/docs/pt/4-agentes/analyst.md +9 -5
  29. package/docs/pt/4-agentes/architect.md +9 -5
  30. package/docs/pt/4-agentes/dev.md +19 -7
  31. package/docs/pt/4-agentes/discovery-design-doc.md +25 -23
  32. package/docs/pt/4-agentes/orchestrator.md +164 -118
  33. package/docs/pt/4-agentes/pentester.md +5 -5
  34. package/docs/pt/4-agentes/pm.md +15 -7
  35. package/docs/pt/4-agentes/sheldon.md +166 -99
  36. package/docs/pt/4-agentes/ux-ui.md +7 -4
  37. package/docs/pt/5-referencia/agent-chain-continuity.md +14 -5
  38. package/docs/pt/5-referencia/comandos-cli.md +1 -1
  39. package/docs/pt/5-referencia/harness-retro.md +2 -1
  40. package/docs/pt/5-referencia/sdd-automation-scripts.md +6 -6
  41. package/docs/pt/5-referencia/sdd-framework.md +53 -16
  42. package/docs/pt/5-referencia/sdd-planos-e-estrutura.md +27 -15
  43. package/docs/pt/README.md +4 -4
  44. package/docs/pt/agentes.md +48 -50
  45. package/package.json +2 -2
  46. package/src/artifact-kinds.js +110 -0
  47. package/src/cli.js +82 -42
  48. package/src/commands/agent-epilogue.js +251 -186
  49. package/src/commands/agents.js +104 -48
  50. package/src/commands/audit-code.js +344 -0
  51. package/src/commands/classify.js +75 -13
  52. package/src/commands/feature-close.js +43 -18
  53. package/src/commands/harness-check.js +259 -175
  54. package/src/commands/harness-retro-promote.js +387 -0
  55. package/src/commands/live.js +24 -0
  56. package/src/commands/prototype-check.js +163 -0
  57. package/src/commands/review-feature.js +189 -0
  58. package/src/commands/runtime.js +81 -66
  59. package/src/commands/sync-agents-copy.js +115 -0
  60. package/src/commands/verification-plan.js +116 -0
  61. package/src/commands/verify-artifact.js +530 -0
  62. package/src/commands/verify-implementation.js +428 -0
  63. package/src/commands/workflow-execute.js +309 -309
  64. package/src/commands/workflow-next.js +361 -19
  65. package/src/commands/workflow-plan.js +5 -5
  66. package/src/constants.js +4 -0
  67. package/src/gateway-pointer-merge.js +7 -1
  68. package/src/handoff-contract.js +267 -172
  69. package/src/harness/contract-integrity-gate.js +172 -0
  70. package/src/harness/contract-integrity.js +111 -0
  71. package/src/harness/contract-schema.js +377 -332
  72. package/src/harness/detect-runtime-feature.js +90 -0
  73. package/src/harness/static-criteria.js +192 -0
  74. package/src/i18n/messages/en.js +8 -4
  75. package/src/i18n/messages/es.js +8 -4
  76. package/src/i18n/messages/fr.js +8 -4
  77. package/src/i18n/messages/pt-BR.js +8 -4
  78. package/src/install-wizard.js +8 -8
  79. package/src/installer.js +13 -6
  80. package/src/lib/retro/retro-render.js +10 -1
  81. package/src/lib/retro/retro-sources.js +45 -27
  82. package/src/lib/retro/verification-reports.js +230 -0
  83. package/src/parser.js +6 -0
  84. package/src/preflight-engine.js +12 -12
  85. package/src/runtime-store.js +13 -9
  86. package/src/verification/evidence-bundle.js +251 -0
  87. package/src/verification/ledger-store.js +221 -0
  88. package/src/verification/path-policy.js +74 -0
  89. package/src/verification/policy-engine.js +95 -0
  90. package/src/verification/prompt-package.js +314 -0
  91. package/src/verification/redaction.js +77 -0
  92. package/src/verification/report-parser.js +132 -0
  93. package/src/verification/report-store.js +97 -0
  94. package/src/verification/result.js +16 -0
  95. package/src/verification/runners/index.js +319 -0
  96. package/src/verification/runtime-telemetry.js +144 -0
  97. package/src/verification/schema.js +276 -0
  98. package/src/verification/source-discovery.js +153 -0
  99. package/src/verification-policy.js +398 -0
  100. package/src/version.js +52 -1
  101. package/template/.aioson/agents/analyst.md +9 -6
  102. package/template/.aioson/agents/architect.md +34 -5
  103. package/template/.aioson/agents/briefing-refiner.md +25 -0
  104. package/template/.aioson/agents/briefing.md +69 -12
  105. package/template/.aioson/agents/committer.md +2 -1
  106. package/template/.aioson/agents/copywriter.md +30 -21
  107. package/template/.aioson/agents/design-hybrid-forge.md +28 -15
  108. package/template/.aioson/agents/dev.md +28 -10
  109. package/template/.aioson/agents/deyvin.md +3 -2
  110. package/template/.aioson/agents/discover.md +12 -3
  111. package/template/.aioson/agents/discovery-design-doc.md +7 -2
  112. package/template/.aioson/agents/genome.md +19 -10
  113. package/template/.aioson/agents/neo.md +30 -30
  114. package/template/.aioson/agents/orache.md +20 -11
  115. package/template/.aioson/agents/orchestrator.md +84 -7
  116. package/template/.aioson/agents/pm.md +8 -8
  117. package/template/.aioson/agents/product.md +15 -11
  118. package/template/.aioson/agents/profiler-enricher.md +20 -11
  119. package/template/.aioson/agents/profiler-forge.md +20 -11
  120. package/template/.aioson/agents/profiler-researcher.md +20 -11
  121. package/template/.aioson/agents/qa.md +87 -17
  122. package/template/.aioson/agents/scope-check.md +19 -5
  123. package/template/.aioson/agents/setup.md +12 -1
  124. package/template/.aioson/agents/sheldon.md +92 -9
  125. package/template/.aioson/agents/site-forge.md +11 -2
  126. package/template/.aioson/agents/squad.md +20 -5
  127. package/template/.aioson/agents/ux-ui.md +4 -2
  128. package/template/.aioson/agents/validator.md +33 -1
  129. package/template/.aioson/config/verification.json +61 -0
  130. package/template/.aioson/config.md +13 -9
  131. package/template/.aioson/docs/LAYERS.md +2 -2
  132. package/template/.aioson/docs/autopilot-handoff.md +10 -10
  133. package/template/.aioson/docs/dev/execution-discipline.md +41 -0
  134. package/template/.aioson/docs/dev/phase-loop.md +47 -0
  135. package/template/.aioson/docs/feature-expansion-taxonomy.md +31 -3
  136. package/template/.aioson/docs/presets/workflow.config.full-merged.json +15 -0
  137. package/template/.aioson/docs/presets/workflow.config.lean.json +15 -0
  138. package/template/.aioson/docs/product/prd-contract.md +12 -12
  139. package/template/.aioson/docs/prototype-contract.md +98 -0
  140. package/template/.aioson/docs/reference-identity.md +94 -0
  141. package/template/.aioson/docs/sheldon/harness-contract.md +155 -28
  142. package/template/.aioson/docs/verification-config.md +82 -0
  143. package/template/.aioson/docs/verify-artifact-gates.md +91 -0
  144. package/template/.aioson/docs/workflow-lean-lane.md +129 -0
  145. package/template/.aioson/skills/design/interface-design/references/intent-and-domain.md +2 -0
  146. package/template/.aioson/skills/process/aioson-spec-driven/SKILL.md +16 -14
  147. package/template/.aioson/skills/process/aioson-spec-driven/references/approval-gates.md +2 -2
  148. package/template/.aioson/skills/process/aioson-spec-driven/references/classification-map.md +4 -4
  149. package/template/.aioson/skills/process/aioson-spec-driven/references/dev.md +15 -15
  150. package/template/.aioson/skills/process/briefing-expansion-scout/SKILL.md +25 -3
  151. package/template/.aioson/skills/process/design-hybrid-forge/SKILL.md +5 -3
  152. package/template/.aioson/skills/process/design-hybrid-forge/references/external-source-ingestion.md +89 -0
  153. package/template/.aioson/skills/process/product-scope-expansion/SKILL.md +29 -2
  154. package/template/.aioson/skills/process/prototype-forge/SKILL.md +98 -0
  155. package/template/.aioson/skills/process/reference-identity-extract/SKILL.md +164 -0
  156. package/template/.aioson/skills/process/sheldon-expansion-audit/SKILL.md +23 -2
  157. package/template/.aioson/skills/static/multi-agent-patterns.md +5 -5
  158. package/template/CLAUDE.md +15 -11
@@ -23,6 +23,20 @@ const { runSecurityAudit } = require('./security-audit');
23
23
  const dossierBootstrap = require('../dossier/dossier-bootstrap');
24
24
  const dossierStore = require('../dossier/store');
25
25
  const { emitDossierEvent } = require('../lib/dossier-telemetry');
26
+ const { parseVerificationReport } = require('../verification/report-parser');
27
+ const { applyPolicy } = require('../verification/policy-engine');
28
+ const { normalizePolicy } = require('../verification/result');
29
+ const {
30
+ evaluateContractIntegrityGate,
31
+ formatContractIntegrityGateError
32
+ } = require('../harness/contract-integrity-gate');
33
+ const { runSpecAnalyze } = require('./spec-analyze');
34
+ const {
35
+ validateFeatureSlug,
36
+ featureContextDir,
37
+ verificationRunsDir,
38
+ relativeFromRoot
39
+ } = require('../verification/path-policy');
26
40
 
27
41
  const STATE_RELATIVE_PATH = '.aioson/context/workflow.state.json';
28
42
  const CONFIG_RELATIVE_PATH = '.aioson/context/workflow.config.json';
@@ -31,21 +45,34 @@ const SCOPE_CHECK_MODES = new Set(['pre-dev', 'post-dev', 'post-fix', 'final']);
31
45
 
32
46
  const DEFAULT_FEATURE_WORKFLOW_BY_CLASSIFICATION = {
33
47
  MICRO: ['product', 'dev', 'qa'],
34
- SMALL: ['product', 'analyst', 'scope-check', 'architect', 'discovery-design-doc', 'dev', 'qa'],
35
- // MEDIUM routes through @pm after discovery-design-doc (mirrors the
36
- // project-mode position): Gate C requires implementation-plan-{slug}.md and
37
- // @pm is its canonical owner (AC-SDLC-15/16) without the stage, the
38
- // sequence dead-ends at @dev preflight with no agent to produce the plan.
39
- MEDIUM: ['product', 'analyst', 'architect', 'discovery-design-doc', 'pm', 'scope-check', 'dev', 'pentester', 'qa']
48
+ // SMALL defaults to the lean lane: @sheldon is the single spec authority
49
+ // (requirements + spec + design-doc + readiness + plan + harness-contract in
50
+ // one pass), replacing analyst/scope-check/architect/discovery-design-doc.
51
+ // Those agents remain available as opt-in detours (allowDetours: true).
52
+ SMALL: ['product', 'sheldon', 'dev', 'qa'],
53
+ // MEDIUM collapses the spec phase into @orchestrator the maestro that fans out
54
+ // to @analyst + @architect + @pm (+ @ux-ui when UI-heavy) as sub-agents, then
55
+ // consolidates/verifies/redoes their output into the gated spec package
56
+ // (requirements + spec[A/B/C approved] + design-doc + readiness + implementation-
57
+ // plan + harness-contract) and hands to @dev. SMALL = @sheldon solo (vertical),
58
+ // MEDIUM = @orchestrator fan-out (horizontal). The scope drift check is enforced at
59
+ // the dev/qa done gate (finalizeCurrentStage). @pentester stays as the post-dev
60
+ // security stage. analyst/architect/pm/ddd/scope-check/ux-ui remain opt-in detours.
61
+ MEDIUM: ['product', 'orchestrator', 'dev', 'pentester', 'qa']
40
62
  };
41
63
 
42
64
  // Stages eligible for autopilot handoff (auto_handoff: true in project.context.md).
43
65
  // Two segments — see .aioson/docs/autopilot-handoff.md:
44
- // 1. analyst -> dev: deterministic pre-dev chain. Prompt-only clients stop
45
- // before the first @dev entry; workflow:execute --agentic may resume it
46
- // through a fresh checkpointed activation.
66
+ // 1. analyst -> dev: deterministic pre-dev chain. Prompt-only clients stop
67
+ // before the first @dev entry; workflow:execute --agentic may resume it
68
+ // through a fresh checkpointed activation.
47
69
  // 2. post-dev review cycle: @dev → @qa → @tester/@pentester (when their @qa triggers
48
70
  // fire) → @validator → STOPS before feature:close (human approves the close).
71
+ // @product and @sheldon are intentionally absent: per config.md, upstream agents
72
+ // (@briefing/@product/@sheldon) always hand off MANUALLY. In the lean lane
73
+ // (product → sheldon → dev → qa) this means auto_handoff is a deliberate no-op
74
+ // pre-dev — @sheldon is the only pre-dev agent and hands off by hand — and is
75
+ // active only on the post-dev cycle (dev → qa). This is by design, not an omission.
49
76
  const AUTOPILOT_HANDOFF_STAGES = new Set([
50
77
  'analyst', 'scope-check', 'architect', 'discovery-design-doc', 'pm',
51
78
  'dev', 'qa', 'tester', 'pentester', 'validator'
@@ -64,13 +91,21 @@ function normalizeClassification(value, fallback = 'MICRO') {
64
91
  return fallback;
65
92
  }
66
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
+
67
102
  function buildDefaultWorkflowConfig() {
68
103
  return {
69
104
  version: 1,
70
105
  project: {
71
106
  MICRO: ['setup', 'dev'],
72
- SMALL: ['setup', 'product', 'analyst', 'scope-check', 'architect', 'discovery-design-doc', 'dev', 'qa'],
73
- MEDIUM: ['setup', 'product', 'analyst', 'architect', 'discovery-design-doc', 'ux-ui', 'pm', 'orchestrator', 'scope-check', 'dev', 'qa']
107
+ SMALL: ['setup', 'product', 'sheldon', 'dev', 'qa'],
108
+ MEDIUM: ['setup', 'product', 'orchestrator', 'dev', 'qa']
74
109
  },
75
110
  feature: DEFAULT_FEATURE_WORKFLOW_BY_CLASSIFICATION,
76
111
  rules: {
@@ -114,6 +149,18 @@ function getScopeCheckModeOption(options = {}) {
114
149
  );
115
150
  }
116
151
 
152
+ function resolveVerificationPolicy(options = {}, state = {}) {
153
+ const explicit = options.verificationPolicy ||
154
+ options['verification-policy'] ||
155
+ options.verification_policy ||
156
+ options.policy;
157
+ if (explicit) return normalizePolicy(explicit) || 'standard';
158
+ // No explicit policy: MEDIUM features default to strict so the auto-injected
159
+ // scope-check verification briefing matches the strict `--check-report` the
160
+ // @dev / @scope-check prompts run. Smaller tiers stay advisory (standard).
161
+ return String(state.classification || '').toUpperCase() === 'MEDIUM' ? 'strict' : 'standard';
162
+ }
163
+
117
164
  function chooseActiveFeature(features, preferredSlug = null) {
118
165
  const activeFeatures = (features || []).filter((feature) => feature.status === 'in_progress');
119
166
  if (preferredSlug) {
@@ -330,6 +377,19 @@ async function validateStageArtifacts(targetDir, state, stage) {
330
377
  }
331
378
 
332
379
  if (stage === 'orchestrator') {
380
+ // Maestro lane (MEDIUM, orchestrator → dev): the orchestrator is the single
381
+ // spec authority — "done" once the gated spec package exists (mirrors how the
382
+ // per-hop stages were inferred). Otherwise it is the parallel-impl coordinator
383
+ // and owns the lane workspace.
384
+ if (state.mode === 'feature' && slug && isMaestroOrchestratorState(state)) {
385
+ const designDoc = [path.join(base, `design-doc-${slug}.md`), path.join(base, 'design-doc.md')];
386
+ const readiness = [path.join(base, `readiness-${slug}.md`), path.join(base, 'readiness.md')];
387
+ return (await exists(path.join(base, `requirements-${slug}.md`)))
388
+ && (await exists(path.join(base, `spec-${slug}.md`)))
389
+ && (await exists(path.join(base, `implementation-plan-${slug}.md`)))
390
+ && (await anyExists(designDoc))
391
+ && (await anyExists(readiness));
392
+ }
333
393
  return await exists(path.join(base, 'parallel'));
334
394
  }
335
395
 
@@ -746,9 +806,94 @@ async function finalizeCurrentStage(targetDir, config, state, stageName) {
746
806
  if (!normalizedStage) {
747
807
  throw new Error('No stage is active to complete.');
748
808
  }
809
+ let auditCodeSummary = null;
749
810
 
750
811
  // ── Harness Done Gate ───────────────────────────────────────────────────
751
812
  if (state.mode === 'feature' && state.featureSlug) {
813
+ if (normalizedStage === 'dev' || normalizedStage === 'qa') {
814
+ const integrityGate = await evaluateContractIntegrityGate(targetDir, state.featureSlug, {
815
+ runChecks: true
816
+ });
817
+ if (!integrityGate.ok) {
818
+ const errMsg = formatContractIntegrityGateError(integrityGate, normalizedStage);
819
+ await logError(targetDir, normalizedStage, errMsg, 'harness-contract');
820
+ throw new Error(errMsg);
821
+ }
822
+
823
+ // ── Scope drift gate (absorbs @scope-check's deterministic spec:analyze) ──
824
+ // scope-check is no longer a default stage; preserve its drift check so a
825
+ // dev/qa completion still blocks on real drift — a design-doc/readiness that
826
+ // declares `readiness: blocked`, or a malformed/invalid harness-contract.json.
827
+ // Non-strict spec:analyze only raises error-severity findings for those
828
+ // genuine problems (never for merely-absent artifacts), so this never
829
+ // false-blocks an artifact-light feature. Defensive: never crashes the run.
830
+ try {
831
+ const drift = await runSpecAnalyze({
832
+ args: [targetDir],
833
+ options: { feature: state.featureSlug },
834
+ logger: { log() {}, error() {} }
835
+ });
836
+ if (drift && Array.isArray(drift.findings) && drift.summary && drift.summary.errors > 0) {
837
+ const errs = drift.findings
838
+ .filter((f) => f.severity === 'error')
839
+ .map((f) => ` - ${f.check}: ${f.message}`)
840
+ .join('\n');
841
+ 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.`;
842
+ await logError(targetDir, normalizedStage, driftMsg, 'scope-drift');
843
+ throw new Error(driftMsg);
844
+ }
845
+ } catch (driftErr) {
846
+ if (driftErr && driftErr.message && driftErr.message.includes('[Scope Drift Gate]')) throw driftErr;
847
+ // spec:analyze unavailable or non-analyzable — non-blocking
848
+ }
849
+
850
+ // ── Code-quality gate (deterministic audit:code) ───────────────────────
851
+ // Build-free scan of the changed files for the non-security categories
852
+ // (anti-patterns / TODOs / dead code / duplication). Unlike the integrity
853
+ // and drift gates above — which enforce the feature's DECLARED contract /
854
+ // spec — audit:code is a heuristic opinion, so it defaults to ADVISORY: the
855
+ // report is persisted (.aioson/context/audit-code.json), a guard event is
856
+ // emitted, and a summary rides the finalize result, but the stage is NOT
857
+ // blocked. Set verification.json `audit_code.tracked_gate: "block"` to make a
858
+ // HIGH finding in scope a hard gate, or "off" to skip. Defensive: only a
859
+ // deliberate block-mode throw escapes; any other error is swallowed.
860
+ try {
861
+ const { readVerificationConfig, getAuditCodePolicy } = require('../verification-policy');
862
+ const auditPolicy = getAuditCodePolicy(await readVerificationConfig(targetDir));
863
+ if (auditPolicy.tracked_gate !== 'off') {
864
+ const { runAuditCode } = require('./audit-code');
865
+ const codeAudit = await runAuditCode({
866
+ args: [targetDir],
867
+ options: { changed: auditPolicy.scope !== 'full', json: true, suppressExitCode: true },
868
+ logger: { log() {}, error() {} }
869
+ });
870
+ const high = codeAudit && codeAudit.by_severity ? (codeAudit.by_severity.HIGH || 0) : 0;
871
+ const med = codeAudit && codeAudit.by_severity ? (codeAudit.by_severity.MED || 0) : 0;
872
+ const categories = Object.keys((codeAudit && codeAudit.by_category) || {});
873
+ auditCodeSummary = { gate: auditPolicy.tracked_gate, scope: auditPolicy.scope, high, med, categories };
874
+ if (high > 0 && auditPolicy.tracked_gate === 'block') {
875
+ 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`;
876
+ await logError(targetDir, normalizedStage, msg, 'audit-code');
877
+ throw new Error(msg);
878
+ }
879
+ if (high > 0) {
880
+ try {
881
+ const { emitGuardEvent } = require('../harness/guard-events');
882
+ await emitGuardEvent(targetDir, {
883
+ eventType: 'audit_code_findings',
884
+ agent: normalizedStage,
885
+ message: `${high} HIGH / ${med} MED in ${auditPolicy.scope} files (${categories.join(', ')}) — advisory`,
886
+ payload: { slug: state.featureSlug, high, med, scope: auditPolicy.scope }
887
+ });
888
+ } catch { /* telemetry best-effort */ }
889
+ }
890
+ }
891
+ } catch (auditErr) {
892
+ if (auditErr && auditErr.message && auditErr.message.includes('[Code-Quality Gate]')) throw auditErr;
893
+ // audit:code unavailable / non-git — non-blocking
894
+ }
895
+ }
896
+
752
897
  const contractPath = path.join(targetDir, '.aioson', 'plans', state.featureSlug, 'harness-contract.json');
753
898
  const progressPath = path.join(targetDir, '.aioson', 'plans', state.featureSlug, 'progress.json');
754
899
 
@@ -848,7 +993,11 @@ async function finalizeCurrentStage(targetDir, config, state, stageName) {
848
993
  detour: null
849
994
  });
850
995
 
851
- return { state: nextState, completedStage: normalizedStage };
996
+ return {
997
+ state: nextState,
998
+ completedStage: normalizedStage,
999
+ ...(auditCodeSummary ? { auditCode: auditCodeSummary } : {})
1000
+ };
852
1001
  }
853
1002
 
854
1003
  /**
@@ -1032,6 +1181,8 @@ async function resolveStageDependencies(targetDir, state, stageName, agent) {
1032
1181
  'readiness.md',
1033
1182
  'ui-spec.md',
1034
1183
  slug ? `implementation-plan-${slug}.md` : 'implementation-plan.md',
1184
+ slug ? `features/${slug}/implementation-ledger.md` : null,
1185
+ slug ? `features/${slug}/verification-report.md` : null,
1035
1186
  'dev-state.md',
1036
1187
  'last-handoff.json',
1037
1188
  'project-pulse.md'
@@ -1139,6 +1290,146 @@ function buildScopeCheckActivationContext(state, mode) {
1139
1290
  return lines.join('\n');
1140
1291
  }
1141
1292
 
1293
+ function routeLabel(route) {
1294
+ return route ? `@${normalizeAgentName(route)}` : '@qa';
1295
+ }
1296
+
1297
+ function workflowGuidanceForVerification(verdict, route, normalReturnTo) {
1298
+ if (verdict === 'PASS') {
1299
+ return `PASS: keep normal workflow ownership (${routeLabel(normalReturnTo || route)}), then continue diff/scope review.`;
1300
+ }
1301
+ if (verdict === 'NEEDS_DEV_FIX') {
1302
+ return 'NEEDS_DEV_FIX: do not approve clean post-dev scope; route concrete file:line findings to @dev.';
1303
+ }
1304
+ if (verdict === 'NEEDS_SCOPE_DECISION') {
1305
+ return `NEEDS_SCOPE_DECISION: route to ${routeLabel(route)}; do not patch product scope locally.`;
1306
+ }
1307
+ if (verdict === 'NEEDS_QA_RECHECK') {
1308
+ return 'NEEDS_QA_RECHECK: route to @qa after scope alignment is clear.';
1309
+ }
1310
+ if (verdict === 'NEEDS_SECURITY_REVIEW') {
1311
+ return 'NEEDS_SECURITY_REVIEW: preserve the security review owner and route to @pentester.';
1312
+ }
1313
+ return `INCONCLUSIVE: route to the owner of missing evidence (${routeLabel(route)}) when strict verification applies.`;
1314
+ }
1315
+
1316
+ async function findImplementationVerificationReport(targetDir, slug) {
1317
+ const slugResult = validateFeatureSlug(slug);
1318
+ if (!slugResult.ok) return null;
1319
+
1320
+ const latestPath = path.join(featureContextDir(targetDir, slug), 'verification-report.md');
1321
+ if (await exists(latestPath)) {
1322
+ return {
1323
+ absolutePath: latestPath,
1324
+ relativePath: relativeFromRoot(targetDir, latestPath),
1325
+ source: 'latest'
1326
+ };
1327
+ }
1328
+
1329
+ const runsDir = verificationRunsDir(targetDir, slug);
1330
+ let entries = [];
1331
+ try {
1332
+ entries = await fs.readdir(runsDir);
1333
+ } catch {
1334
+ return null;
1335
+ }
1336
+ const reportName = entries
1337
+ .filter((entry) => /-report\.md$/i.test(entry))
1338
+ .sort()
1339
+ .pop();
1340
+ if (!reportName) return null;
1341
+
1342
+ const reportPath = path.join(runsDir, reportName);
1343
+ return {
1344
+ absolutePath: reportPath,
1345
+ relativePath: relativeFromRoot(targetDir, reportPath),
1346
+ source: 'verification-runs'
1347
+ };
1348
+ }
1349
+
1350
+ async function buildImplementationVerificationBriefing(targetDir, state, scopeCheckMode, policy) {
1351
+ const mode = inferScopeCheckMode(state, scopeCheckMode);
1352
+ if (
1353
+ state.mode !== 'feature' ||
1354
+ !state.featureSlug ||
1355
+ !['post-dev', 'post-fix', 'final'].includes(mode)
1356
+ ) {
1357
+ return null;
1358
+ }
1359
+
1360
+ const slug = state.featureSlug;
1361
+ const latestPath = `.aioson/context/features/${slug}/verification-report.md`;
1362
+ const reportRef = await findImplementationVerificationReport(targetDir, slug);
1363
+ const lines = [
1364
+ '## Implementation verification briefing',
1365
+ `Policy: ${policy}`,
1366
+ `Expected latest report: ${latestPath}`,
1367
+ 'Workflow note: this briefing only validates local report artifacts; it never runs `--tool` or any external auditor.'
1368
+ ];
1369
+
1370
+ if (!reportRef) {
1371
+ lines.push('Report status: missing');
1372
+ if (state.classification === 'MICRO') {
1373
+ lines.push('MICRO: missing report is not a workflow blocker by default; record residual risk only when the dev handoff relied on verification.');
1374
+ } else if (state.classification === 'MEDIUM' && policy === 'strict') {
1375
+ lines.push('Strict MEDIUM guidance: do not issue final clean scope approval until @dev produces a valid report or documents an explicit N/A rationale.');
1376
+ } else {
1377
+ lines.push('Guidance: absence is advisory unless the feature policy or dev handoff made verification strict.');
1378
+ }
1379
+ return {
1380
+ status: 'missing',
1381
+ mode,
1382
+ policy,
1383
+ report_path: null,
1384
+ verdict: 'INCONCLUSIVE',
1385
+ recommended_route: state.classification === 'MICRO' ? state.next || 'qa' : 'dev',
1386
+ briefing: lines.join('\n')
1387
+ };
1388
+ }
1389
+
1390
+ lines.push(`Report path: ${reportRef.relativePath}`);
1391
+ lines.push(`Validate command: aioson verify:implementation . --feature=${slug} --check-report=${reportRef.relativePath} --policy=${policy} --json`);
1392
+
1393
+ const parsed = await parseVerificationReport(targetDir, slug, reportRef.relativePath, policy);
1394
+ if (!parsed.ok) {
1395
+ lines.push(`Report status: invalid (${parsed.reason})`);
1396
+ lines.push('Guidance: treat this as INCONCLUSIVE local evidence; do not treat auditor prose as PASS.');
1397
+ return {
1398
+ status: 'invalid',
1399
+ mode,
1400
+ policy,
1401
+ report_path: reportRef.relativePath,
1402
+ verdict: 'INCONCLUSIVE',
1403
+ recommended_route: 'qa',
1404
+ reason: parsed.reason,
1405
+ briefing: lines.join('\n')
1406
+ };
1407
+ }
1408
+
1409
+ const policyResult = applyPolicy(parsed.report, policy);
1410
+ lines.push('Report status: schema-valid');
1411
+ lines.push(`Report verdict: ${parsed.report.verdict}`);
1412
+ lines.push(`Policy verdict: ${policyResult.verdict}`);
1413
+ lines.push(`Policy route: ${routeLabel(policyResult.recommended_route)}`);
1414
+ lines.push(`Blocking findings: ${policyResult.blocking_findings_count || 0}`);
1415
+ lines.push(`Guidance: ${workflowGuidanceForVerification(policyResult.verdict, policyResult.recommended_route, state.next)}`);
1416
+ lines.push('Scope-check still must inspect the diff and approved plan; a PASS report is not final approval.');
1417
+
1418
+ return {
1419
+ status: 'valid',
1420
+ mode,
1421
+ policy,
1422
+ report_path: reportRef.relativePath,
1423
+ report_source: reportRef.source,
1424
+ verdict: policyResult.verdict,
1425
+ auditor_verdict: parsed.report.verdict,
1426
+ recommended_route: policyResult.recommended_route,
1427
+ blocking_findings_count: policyResult.blocking_findings_count || 0,
1428
+ reason: policyResult.reason,
1429
+ briefing: lines.join('\n')
1430
+ };
1431
+ }
1432
+
1142
1433
  function buildStageActivationContext(state, stageName, dependencies, scopeCheckMode = null) {
1143
1434
  if (stageName === 'scope-check') {
1144
1435
  return buildScopeCheckActivationContext(state, scopeCheckMode);
@@ -1155,7 +1446,16 @@ function buildStageActivationContext(state, stageName, dependencies, scopeCheckM
1155
1446
  ].join('\n');
1156
1447
  }
1157
1448
 
1158
- async function activateStage(targetDir, state, locale, tool, explicitAgent = null, requestedMode = null, scopeCheckMode = null) {
1449
+ async function activateStage(
1450
+ targetDir,
1451
+ state,
1452
+ locale,
1453
+ tool,
1454
+ explicitAgent = null,
1455
+ requestedMode = null,
1456
+ scopeCheckMode = null,
1457
+ verificationPolicy = 'standard'
1458
+ ) {
1159
1459
  const stageName = normalizeAgentName(explicitAgent || state.current || state.next);
1160
1460
  if (!stageName) {
1161
1461
  return {
@@ -1270,6 +1570,13 @@ async function activateStage(targetDir, state, locale, tool, explicitAgent = nul
1270
1570
 
1271
1571
  const instructionPath = await resolveExistingInstructionPath(targetDir, agent, locale);
1272
1572
  const dependencies = await resolveStageDependencies(targetDir, state, stageName, agent);
1573
+ const verificationBriefing = stageName === 'scope-check'
1574
+ ? await buildImplementationVerificationBriefing(targetDir, state, scopeCheckMode, verificationPolicy)
1575
+ : null;
1576
+ const activationContext = [
1577
+ buildStageActivationContext(state, stageName, dependencies, scopeCheckMode),
1578
+ verificationBriefing && verificationBriefing.briefing
1579
+ ].filter(Boolean).join('\n\n');
1273
1580
  let prompt = buildAgentPrompt(agent, tool, {
1274
1581
  instructionPath,
1275
1582
  targetDir,
@@ -1278,7 +1585,7 @@ async function activateStage(targetDir, state, locale, tool, explicitAgent = nul
1278
1585
  capabilitySummary: buildAgentCapabilitySummary(agentManifest, tool),
1279
1586
  dependsOn: dependencies,
1280
1587
  autoHandoff,
1281
- activationContext: buildStageActivationContext(state, stageName, dependencies, scopeCheckMode)
1588
+ activationContext
1282
1589
  });
1283
1590
 
1284
1591
  if (testBriefing) {
@@ -1316,7 +1623,20 @@ async function activateStage(targetDir, state, locale, tool, explicitAgent = nul
1316
1623
  agent: stageName,
1317
1624
  instructionPath,
1318
1625
  prompt,
1319
- effectiveMode
1626
+ effectiveMode,
1627
+ verification: verificationBriefing
1628
+ ? {
1629
+ status: verificationBriefing.status,
1630
+ mode: verificationBriefing.mode,
1631
+ policy: verificationBriefing.policy,
1632
+ report_path: verificationBriefing.report_path,
1633
+ verdict: verificationBriefing.verdict,
1634
+ auditor_verdict: verificationBriefing.auditor_verdict || null,
1635
+ recommended_route: verificationBriefing.recommended_route,
1636
+ blocking_findings_count: verificationBriefing.blocking_findings_count || 0,
1637
+ reason: verificationBriefing.reason || null
1638
+ }
1639
+ : null
1320
1640
  };
1321
1641
  }
1322
1642
 
@@ -1416,7 +1736,8 @@ async function runWorkflowNext({ args, options, logger, t }) {
1416
1736
  const autoHeal = Boolean(options['auto-heal'] || options.autoHeal);
1417
1737
  const isHealabled = autoHeal && (
1418
1738
  err.message.includes('[Technical Gate BLOCKED]') ||
1419
- err.message.includes('[Handoff Contract BLOCKED]')
1739
+ err.message.includes('[Handoff Contract BLOCKED]') ||
1740
+ err.message.includes('[Harness Contract Gate BLOCKED]')
1420
1741
  );
1421
1742
  if (isHealabled) {
1422
1743
  const failedStage = normalizeAgentName(options.complete === true ? state.current || state.next : options.complete);
@@ -1425,7 +1746,16 @@ async function runWorkflowNext({ args, options, logger, t }) {
1425
1746
  if (retryCount < require('../self-healing').MAX_RETRIES) {
1426
1747
  await require('../self-healing').incrementRetryCount(targetDir, failedStage, err.message.substring(0, 200));
1427
1748
  // Build healing activation
1428
- const baseActivation = await activateStage(targetDir, state, locale, tool, failedStage, options.mode || null);
1749
+ const baseActivation = await activateStage(
1750
+ targetDir,
1751
+ state,
1752
+ locale,
1753
+ tool,
1754
+ failedStage,
1755
+ options.mode || null,
1756
+ null,
1757
+ resolveVerificationPolicy(options, state)
1758
+ );
1429
1759
  const healingPrompt = buildHealingPrompt(
1430
1760
  baseActivation.prompt || '',
1431
1761
  failedStage,
@@ -1552,7 +1882,17 @@ async function runWorkflowNext({ args, options, logger, t }) {
1552
1882
  const activationAgent = normalizeAgentName(requestedAgent || state.current || state.next);
1553
1883
  const scopeCheckMode = activationAgent === 'scope-check' ? getScopeCheckModeOption(options) : null;
1554
1884
  const requestedAutonomyMode = scopeCheckMode && activationAgent === 'scope-check' ? null : options.mode || null;
1555
- const activation = await activateStage(targetDir, state, locale, tool, requestedAgent, requestedAutonomyMode, scopeCheckMode);
1885
+ const verificationPolicy = resolveVerificationPolicy(options, state);
1886
+ const activation = await activateStage(
1887
+ targetDir,
1888
+ state,
1889
+ locale,
1890
+ tool,
1891
+ requestedAgent,
1892
+ requestedAutonomyMode,
1893
+ scopeCheckMode,
1894
+ verificationPolicy
1895
+ );
1556
1896
  state = activation.state;
1557
1897
 
1558
1898
  // ── Living Memory: if a reflect manifest is pending (created above by the
@@ -1590,7 +1930,8 @@ async function runWorkflowNext({ args, options, logger, t }) {
1590
1930
  completed: state.completed,
1591
1931
  skipped: state.skipped,
1592
1932
  sequence: state.sequence,
1593
- autonomyMode: activation.effectiveMode || null
1933
+ autonomyMode: activation.effectiveMode || null,
1934
+ verification: activation.verification || null
1594
1935
  };
1595
1936
  await appendWorkflowEvent(targetDir, eventPayload);
1596
1937
  const runtime = await syncWorkflowRuntime(targetDir, {
@@ -1645,6 +1986,7 @@ async function runWorkflowNext({ args, options, logger, t }) {
1645
1986
  runtime,
1646
1987
  agent: activation.agent,
1647
1988
  effectiveMode: activation.effectiveMode || null,
1989
+ verification: activation.verification || null,
1648
1990
  instructionPath: activation.instructionPath,
1649
1991
  prompt: activation.prompt
1650
1992
  };
@@ -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
@@ -46,6 +46,8 @@ const MANAGED_FILES = [
46
46
  '.aioson/docs/squad/session-operations.md',
47
47
  '.aioson/docs/squad/genome-bindings.md',
48
48
  '.aioson/docs/feature-expansion-taxonomy.md',
49
+ '.aioson/docs/prototype-contract.md',
50
+ '.aioson/docs/reference-identity.md',
49
51
  '.aioson/docs/product/conversation-playbook.md',
50
52
  '.aioson/docs/product/research-loop.md',
51
53
  '.aioson/docs/product/quality-lens.md',
@@ -81,6 +83,8 @@ const MANAGED_FILES = [
81
83
  '.aioson/skills/process/briefing-expansion-scout/SKILL.md',
82
84
  '.aioson/skills/process/product-scope-expansion/SKILL.md',
83
85
  '.aioson/skills/process/sheldon-expansion-audit/SKILL.md',
86
+ '.aioson/skills/process/prototype-forge/SKILL.md',
87
+ '.aioson/skills/process/reference-identity-extract/SKILL.md',
84
88
  '.aioson/skills/static/laravel-conventions.md',
85
89
  '.aioson/skills/static/tall-stack-patterns.md',
86
90
  '.aioson/skills/static/jetstream-setup.md',
@@ -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';