@khoavu882/doflow 2.0.1 → 2.0.2

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 (93) hide show
  1. package/core/.claude-plugin/plugin.json +1 -1
  2. package/core/.codex-plugin/plugin.json +1 -1
  3. package/core/.plugin/plugin.json +1 -1
  4. package/core/harnesses/claude/hooks/session-end.sh +21 -1
  5. package/core/harnesses/codex/hooks/session-end.impl.sh +21 -1
  6. package/core/harnesses/shared/hooks/policies/compact-text.sh +8 -0
  7. package/core/harnesses/shared/hooks/policies/subagent-audit.sh +25 -1
  8. package/core/registry/contribution-points.json +1 -1
  9. package/core/registry/intake.json +3 -3
  10. package/core/registry/lifecycle.json +256 -5
  11. package/core/registry/packages/doflow/doflow-package.json +2 -2
  12. package/core/registry/settings.json +12 -12
  13. package/core/registry/storage.json +1 -2
  14. package/core/shared/guidance/references/ARTIFACT_FORMAT.md +7 -0
  15. package/core/shared/scripts/doflow/bash/do-git-state.sh +12 -4
  16. package/core/shared/scripts/doflow/bash/do-parallel-check.sh +86 -33
  17. package/core/shared/scripts/doflow/bash/do-review-package.sh +36 -2
  18. package/core/shared/scripts/doflow/bin/doflow-run +18 -0
  19. package/core/shared/skills/do-design/SKILL.md +6 -2
  20. package/core/shared/skills/do-design/references/data_model_example.md +167 -0
  21. package/core/shared/templates/doflow/data-model-template.md +136 -102
  22. package/package.json +1 -1
  23. package/src/adapters/antigravity/index.js +54 -12
  24. package/src/adapters/codex/agents.js +15 -1
  25. package/src/adapters/codex/config.js +5 -2
  26. package/src/adapters/copilot/index.js +11 -4
  27. package/src/adapters/copy-tree.js +7 -0
  28. package/src/adapters/created-file.js +41 -0
  29. package/src/adapters/mcp-entries.js +11 -1
  30. package/src/adapters/opencode/index.js +32 -5
  31. package/src/adapters/pi/index.js +15 -4
  32. package/src/adapters/pi/mcp.js +44 -18
  33. package/src/cli/commands/remove.js +3 -1
  34. package/src/cli/commands/update.js +7 -3
  35. package/src/cli/index.js +24 -12
  36. package/src/cli/runtime-commands.js +1 -1
  37. package/src/cli/shared.js +5 -3
  38. package/src/helper/marker-merge.js +11 -7
  39. package/src/install/backup-set.js +7 -3
  40. package/src/install/backup.js +13 -7
  41. package/src/install/context.js +2 -1
  42. package/src/install/manifest.js +35 -11
  43. package/src/install/paths.js +38 -0
  44. package/src/install/targets.js +11 -2
  45. package/src/lifecycle/index.js +80 -3
  46. package/src/lifecycle/retired-harnesses.js +16 -1
  47. package/src/lifecycle/view.js +3 -2
  48. package/src/registry/index.js +21 -4
  49. package/src/release/docs-blocks.js +5 -1
  50. package/src/runtime/advice/doctor.js +2 -2
  51. package/src/runtime/brief-tools.js +2 -1
  52. package/src/runtime/capability-router.js +26 -3
  53. package/src/runtime/context/pointer.js +17 -5
  54. package/src/runtime/context-pack.js +48 -8
  55. package/src/runtime/dispatch/integrate.js +27 -8
  56. package/src/runtime/dispatch/loop.js +7 -0
  57. package/src/runtime/dispatch/verify-run.js +9 -3
  58. package/src/runtime/feature-pointer.js +10 -1
  59. package/src/runtime/health.js +9 -4
  60. package/src/runtime/implementation-gate.js +10 -2
  61. package/src/runtime/intake/engine.js +11 -9
  62. package/src/runtime/knowledge/code-retrieval.js +11 -5
  63. package/src/runtime/knowledge/semble-provider.js +12 -2
  64. package/src/runtime/lifecycle/cli.js +7 -5
  65. package/src/runtime/lifecycle/overview.js +32 -2
  66. package/src/runtime/lifecycle/release.js +16 -3
  67. package/src/runtime/lifecycle/retention.js +12 -15
  68. package/src/runtime/lifecycle/store-upkeep.js +13 -3
  69. package/src/runtime/mask.js +3 -3
  70. package/src/runtime/mcp-consultations.js +11 -5
  71. package/src/runtime/research-request.js +3 -1
  72. package/src/runtime/review/command.js +3 -7
  73. package/src/runtime/review/start.js +24 -10
  74. package/src/runtime/roadmap/loop.js +14 -3
  75. package/src/runtime/roadmap/rows.js +2 -1
  76. package/src/runtime/settings/files.js +3 -1
  77. package/src/runtime/settings/prepared-run.js +12 -2
  78. package/src/runtime/settings/resolve.js +13 -1
  79. package/src/runtime/settings/write.js +73 -2
  80. package/src/runtime/storage/registry.js +2 -2
  81. package/src/runtime/storage/roots.js +4 -18
  82. package/src/runtime/storage/rules.js +22 -46
  83. package/src/runtime/storage/work-status.js +14 -4
  84. package/src/runtime/task-scope.js +17 -2
  85. package/src/runtime/task-state.js +11 -4
  86. package/src/runtime/trace/analyze.js +4 -2
  87. package/src/runtime/trace/indicators.js +25 -20
  88. package/src/runtime/trace/spans.js +4 -5
  89. package/src/runtime/verb-view.js +6 -5
  90. package/src/runtime/worker/command.js +4 -2
  91. package/src/runtime/worker/readiness.js +8 -4
  92. package/src/runtime/worker/supervisor.js +18 -6
  93. package/src/runtime/workflow-orchestrator.js +6 -2
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "doflow",
3
- "version": "2.0.1",
3
+ "version": "2.0.2",
4
4
  "description": "Reusable engineering workflows, quality gates, and specialist guidance for Claude Code.",
5
5
  "author": {
6
6
  "name": "DoFlow"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "doflow",
3
- "version": "2.0.1",
3
+ "version": "2.0.2",
4
4
  "description": "Reusable engineering workflows, quality gates, and specialist guidance for Codex.",
5
5
  "author": {
6
6
  "name": "DoFlow",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "doflow",
3
- "version": "2.0.1",
3
+ "version": "2.0.2",
4
4
  "description": "Reusable engineering workflows, quality gates, and specialist guidance for GitHub Copilot CLI.",
5
5
  "author": {
6
6
  "name": "DoFlow",
@@ -5,7 +5,7 @@ case "${OSTYPE:-}" in msys*|cygwin*|win32*) if command -v jq >/dev/null 2>&1; th
5
5
  # Runs when Claude Code closes a session. Responsibilities:
6
6
  # 1. Append END marker to sessions.log
7
7
  # 2. Write uncommitted-warning.txt if the working tree is dirty
8
- # 3. Delete the session-scoped state directory (cleanup)
8
+ # 3. Delete the session-scoped state directory (cleanup) and the main session's model observation
9
9
  # 4. Trim sessions.log to last 500 lines (lock-guarded for parallel safety)
10
10
  #
11
11
  # Multi-session safe: with_file_lock (lib.sh) prevents concurrent sessions from
@@ -81,6 +81,26 @@ if [[ -n "$SESSION_ID" ]]; then
81
81
  rm -rf "$SESSION_PATH" 2>/dev/null || true
82
82
  fi
83
83
 
84
+ # ── 3b. Remove this main session's model observation (120 IC-005) ─────────────
85
+
86
+ # observe-model.sh keys the file by the first 16 hex of sha256(session id), under primary/<cwd_hash>/<harness>/.
87
+ # Only the ending main session's own file goes: other sessions, worker observations and a missing file are left
88
+ # alone, and a failure here changes nothing (SessionEnd is fire-and-forget).
89
+ forget_model_observation() {
90
+ local key="" cwd="${CWD:-}" file=""
91
+ [[ -n "$SESSION_ID" ]] || return 0
92
+ [[ "$(doflow_session_role || echo main)" == "main" ]] || return 0
93
+ if command -v sha256sum >/dev/null 2>&1; then key=$(printf '%s' "$SESSION_ID" | sha256sum | cut -c1-16)
94
+ elif command -v shasum >/dev/null 2>&1; then key=$(printf '%s' "$SESSION_ID" | shasum -a 256 | cut -c1-16)
95
+ else return 0; fi
96
+ [[ $key =~ ^[0-9a-f]{16}$ ]] || return 0
97
+ case "$cwd" in /*) ;; *) cwd=$PWD ;; esac
98
+ file="$STATE_DIR/primary/$(cwd_hash "$cwd")/claude/$key.json"
99
+ if [[ -f "$file" && ! -L "$file" ]]; then rm -f "$file"; fi
100
+ return 0
101
+ }
102
+ forget_model_observation 2>/dev/null || true
103
+
84
104
  start_storage_upkeep
85
105
 
86
106
  # ── 4. Trim sessions.log (lock-guarded) ───────────────────────────────────────
@@ -5,7 +5,7 @@ case "${OSTYPE:-}" in msys*|cygwin*|win32*) if command -v jq >/dev/null 2>&1; th
5
5
  # Runs when Claude Code closes a session. Responsibilities:
6
6
  # 1. Append END marker to sessions.log
7
7
  # 2. Write uncommitted-warning.txt if the working tree is dirty
8
- # 3. Delete the session-scoped state directory (cleanup)
8
+ # 3. Delete the session-scoped state directory (cleanup) and the main session's model observation
9
9
  # 4. Trim sessions.log to last 500 lines (lock-guarded for parallel safety,
10
10
  # via lib.sh's portable with_file_lock — no flock dependency)
11
11
  #
@@ -82,6 +82,26 @@ if [[ -n "$SESSION_ID" ]]; then
82
82
  rm -rf "$SESSION_PATH" 2>/dev/null || true
83
83
  fi
84
84
 
85
+ # ── 3b. Remove this main session's model observation (120 IC-005) ─────────────
86
+
87
+ # observe-model.sh keys the file by the first 16 hex of sha256(session id), under primary/<cwd_hash>/<harness>/.
88
+ # Only the ending main session's own file goes: other sessions, worker observations and a missing file are left
89
+ # alone, and a failure here changes nothing (SessionEnd is fire-and-forget).
90
+ forget_model_observation() {
91
+ local key="" cwd="${CWD:-}" file=""
92
+ [[ -n "$SESSION_ID" ]] || return 0
93
+ [[ "$(doflow_session_role || echo main)" == "main" ]] || return 0
94
+ if command -v sha256sum >/dev/null 2>&1; then key=$(printf '%s' "$SESSION_ID" | sha256sum | cut -c1-16)
95
+ elif command -v shasum >/dev/null 2>&1; then key=$(printf '%s' "$SESSION_ID" | shasum -a 256 | cut -c1-16)
96
+ else return 0; fi
97
+ [[ $key =~ ^[0-9a-f]{16}$ ]] || return 0
98
+ case "$cwd" in /*) ;; *) cwd=$PWD ;; esac
99
+ file="$STATE_DIR/primary/$(cwd_hash "$cwd")/codex/$key.json"
100
+ if [[ -f "$file" && ! -L "$file" ]]; then rm -f "$file"; fi
101
+ return 0
102
+ }
103
+ forget_model_observation 2>/dev/null || true
104
+
85
105
  start_storage_upkeep
86
106
 
87
107
  # ── 4. Trim sessions.log (lock-guarded) ───────────────────────────────────────
@@ -21,6 +21,14 @@ doflow_compact_text() {
21
21
  "$preserve" "${CWD:-unknown}")
22
22
  fi
23
23
 
24
+ # Malformed UTF-8 (a commit subject or path can carry any byte) becomes U+FFFD here, before the cap, so the
25
+ # Claude (raw stdout) and Codex (jq --arg) outputs decode to the same text and the cap counts the bytes sent.
26
+ # jq is a hard requirement of both hooks; without it the text is left as it was (FU-535bfv).
27
+ if command -v jq >/dev/null 2>&1; then
28
+ local clean
29
+ if clean=$(printf '%s' "$text" | jq -Rsj '.' 2>/dev/null); then text="$clean"; fi
30
+ fi
31
+
24
32
  # The cap is 490 BYTES in every locale: LC_ALL=C makes the substring and length below count bytes,
25
33
  # where a UTF-8 locale would count characters. A cut can then end inside a multi-byte character, so
26
34
  # a trailing partial UTF-8 sequence is dropped (FU-tsq77m).
@@ -67,6 +67,26 @@ TIMESTAMP=$(date -u +%FT%TZ)
67
67
 
68
68
  SESSION_PATH=$(ensure_session_dir "$SESSION_ID")
69
69
 
70
+ # One SubagentStop record per session+agent id. A harness that runs another harness's hook wiring as
71
+ # well as its own (Copilot with a Claude install, issue 21) delivers each stop twice, possibly at the
72
+ # same moment. mkdir is the atomic claim: the delivery that creates the marker writes the record, a
73
+ # delivery that finds it is a duplicate. SubagentStart, an id-less stop and an id that is not a plain
74
+ # token (no safe marker name) are always recorded, and any failure to claim records anyway (fail open).
75
+ STOP_CLAIM=""
76
+ STOP_EVENT_KEY=$(printf '%s' "$EVENT" | tr 'A-Z_' 'a-z')
77
+ if [ "$STOP_EVENT_KEY" = "subagentstop" ] && [ -n "$AGENT_ID" ] && [ "${#AGENT_ID}" -le 128 ]; then
78
+ case "$AGENT_ID" in
79
+ [A-Za-z0-9]*) case "$AGENT_ID" in *[!A-Za-z0-9._-]*) ;; *)
80
+ if mkdir -p "$SESSION_PATH/subagent-stops" 2>/dev/null; then
81
+ if mkdir "$SESSION_PATH/subagent-stops/$AGENT_ID" 2>/dev/null; then
82
+ STOP_CLAIM="$SESSION_PATH/subagent-stops/$AGENT_ID"
83
+ elif [ -d "$SESSION_PATH/subagent-stops/$AGENT_ID" ]; then
84
+ exit 0
85
+ fi
86
+ fi ;; esac ;;
87
+ esac
88
+ fi
89
+
70
90
  jq -nc \
71
91
  --arg ts "$TIMESTAMP" \
72
92
  --arg session "$SESSION_ID" \
@@ -74,6 +94,10 @@ jq -nc \
74
94
  --arg agent_type "$AGENT_TYPE" \
75
95
  --arg agent_id "$AGENT_ID" \
76
96
  '{timestamp: $ts, session_id: $session, event: $event, agent_type: $agent_type, agent_id: $agent_id}' \
77
- >> "$SESSION_PATH/subagent-audit.log" 2>/dev/null || doflow_decide error audit-write-failed
97
+ >> "$SESSION_PATH/subagent-audit.log" 2>/dev/null || {
98
+ # Release the claim so a later delivery of the same stop can still be recorded.
99
+ [ -z "$STOP_CLAIM" ] || rmdir "$STOP_CLAIM" 2>/dev/null || true
100
+ doflow_decide error audit-write-failed
101
+ }
78
102
 
79
103
  exit 0
@@ -30,6 +30,6 @@
30
30
  "referencedBy": [], "slice": "136", "template": "package-templates/intake-category" }
31
31
  ],
32
32
  "bundled": [
33
- { "id": "doflow", "dir": "core/registry/packages/doflow", "contentDigest": "4684bab1385564aef5e65100c789605895f3597c7fc23f340afa55333d11377b" }
33
+ { "id": "doflow", "dir": "core/registry/packages/doflow", "contentDigest": "a8f5766277e1cf284780c78efa487e2b8a9272951a5f8c67fabb830a54b55af8" }
34
34
  ]
35
35
  }
@@ -11,7 +11,7 @@
11
11
  "names": ["prd", "requirements"],
12
12
  "summary": "Product requirement documents, briefs and stories as the user wrote them.",
13
13
  "rules": [
14
- { "extensions": ["md", "txt", "pdf", "docx"], "namePattern": "prd|requirement|brief|epic|(^|[^a-z0-9])(story|stories)([^a-z0-9]|$)" }
14
+ { "extensions": ["md", "txt", "pdf", "docx"], "namePattern": "prd|requirement|brief|epic|(^|[^a-z0-9])(user[-_ ]?)?(story|stories)([^a-z0-9]|$)" }
15
15
  ]
16
16
  },
17
17
  {
@@ -21,7 +21,7 @@
21
21
  "rules": [
22
22
  { "extensions": ["mmd", "puml", "drawio", "excalidraw"], "into": "diagrams" },
23
23
  { "extensions": ["png", "svg", "jpg", "jpeg"], "companionOf": ["mmd", "puml", "drawio", "excalidraw"] },
24
- { "extensions": ["md"], "namePattern": "hld|high[-_ ]?level|design|architecture|decision|adr" }
24
+ { "extensions": ["md"], "namePattern": "^(?!.*(transcript|meeting|minutes|session[-_ ]?notes)).*(hld|high[-_ ]?level|design|architecture|decision|adr)" }
25
25
  ]
26
26
  },
27
27
  {
@@ -32,7 +32,7 @@
32
32
  { "extensions": ["mp3", "m4a", "wav", "ogg", "mp4", "mov", "webm"], "into": "records" },
33
33
  { "extensions": ["vtt", "srt"], "into": "transcripts" },
34
34
  { "extensions": ["txt", "md"], "namePattern": "transcript|meeting|minutes|discuss|session", "into": "transcripts" },
35
- { "extensions": ["txt"], "namePattern": "^(\\d{1,2}-\\d{1,2}-\\d{4}|\\d{4}-\\d{2}-\\d{2})", "into": "transcripts" }
35
+ { "extensions": ["txt"], "namePattern": "^(\\d{1,2}-\\d{1,2}-\\d{4}|\\d{4}-\\d{2}-\\d{2})([ _T]\\d{1,2}[.:]\\d{2}([.:]\\d{2})?)?$", "into": "transcripts" }
36
36
  ]
37
37
  },
38
38
  {
@@ -83,6 +83,47 @@
83
83
  }
84
84
  }
85
85
  },
86
+ {
87
+ "id": "session-end",
88
+ "intent": "remove-session-model-observation",
89
+ "tier": "enhanced",
90
+ "requires": [
91
+ "hooks"
92
+ ],
93
+ "mappings": {
94
+ "claude": {
95
+ "event": "SessionEnd",
96
+ "status": "supported"
97
+ },
98
+ "codex": {
99
+ "event": "SessionEnd",
100
+ "status": "supported",
101
+ "prerequisites": [
102
+ "hook-review"
103
+ ]
104
+ },
105
+ "opencode": {
106
+ "status": "unavailable",
107
+ "fallback": "guidance"
108
+ },
109
+ "pi": {
110
+ "status": "unavailable",
111
+ "fallback": "guidance"
112
+ },
113
+ "copilot": {
114
+ "status": "unavailable",
115
+ "fallback": "guidance"
116
+ },
117
+ "kiro": {
118
+ "status": "unavailable",
119
+ "fallback": "guidance"
120
+ },
121
+ "antigravity": {
122
+ "status": "unavailable",
123
+ "fallback": "guidance"
124
+ }
125
+ }
126
+ },
86
127
  {
87
128
  "id": "mcp-tool-guard",
88
129
  "intent": "enforce-mcp-policy",
@@ -169,7 +210,7 @@
169
210
  ],
170
211
  "coverage": {
171
212
  "schemaVersion": 1,
172
- "revision": 3,
213
+ "revision": 4,
173
214
  "refresh": {
174
215
  "trigger": "a harness bridge, template or installed harness version changes",
175
216
  "owner": "the feature that changes it"
@@ -293,7 +334,7 @@
293
334
  "tested": "1.1.0"
294
335
  },
295
336
  "class": "advisory",
296
- "verification": "verified",
337
+ "verification": "unverified",
297
338
  "prerequisites": [],
298
339
  "covers": [],
299
340
  "doesNotCover": [
@@ -321,7 +362,7 @@
321
362
  },
322
363
  {
323
364
  "kind": "live",
324
- "locator": "test/fixtures/hooks/pi/live/probe-2026-10-14.jsonl",
365
+ "locator": "historical blocking evidence: test/fixtures/hooks/pi/live/probe-2026-10-14.jsonl",
325
366
  "date": "2026-10-14"
326
367
  }
327
368
  ]
@@ -976,6 +1017,216 @@
976
1017
  }
977
1018
  ]
978
1019
  },
1020
+ {
1021
+ "policy": "session-end",
1022
+ "harness": "claude",
1023
+ "event": "SessionEnd",
1024
+ "timing": "session",
1025
+ "profile": "any",
1026
+ "wired": true,
1027
+ "configSource": "core/harnesses/claude/settings/settings.json:176",
1028
+ "harnessVersion": {
1029
+ "tested": "2.1.287 (Claude Code)"
1030
+ },
1031
+ "class": "observation",
1032
+ "verification": "unverified",
1033
+ "prerequisites": [],
1034
+ "covers": [
1035
+ "removes the ending main session's hashed model observation"
1036
+ ],
1037
+ "doesNotCover": [
1038
+ "worker observations",
1039
+ "sessions that end without the hook running (the model-observations age bound applies)"
1040
+ ],
1041
+ "caveats": [
1042
+ "native event enforcement is not yet verified"
1043
+ ],
1044
+ "provenance": [
1045
+ {
1046
+ "kind": "doc",
1047
+ "locator": "https://code.claude.com/docs/en/hooks",
1048
+ "date": "2026-10-12"
1049
+ },
1050
+ {
1051
+ "kind": "fixture",
1052
+ "locator": "test/hooks/session-end-observation.test.ts",
1053
+ "date": "2026-11-04"
1054
+ }
1055
+ ]
1056
+ },
1057
+ {
1058
+ "policy": "session-end",
1059
+ "harness": "codex",
1060
+ "event": "SessionEnd",
1061
+ "timing": "session",
1062
+ "profile": "any",
1063
+ "wired": true,
1064
+ "configSource": "core/harnesses/codex/hooks/hooks.json:100",
1065
+ "harnessVersion": {
1066
+ "tested": "codex-cli 0.162.1"
1067
+ },
1068
+ "class": "observation",
1069
+ "verification": "unverified",
1070
+ "prerequisites": [
1071
+ "hook-review"
1072
+ ],
1073
+ "covers": [
1074
+ "removes the ending main session's hashed model observation"
1075
+ ],
1076
+ "doesNotCover": [
1077
+ "worker observations",
1078
+ "sessions that end without the hook running (the model-observations age bound applies)"
1079
+ ],
1080
+ "caveats": [
1081
+ "native event enforcement is not yet verified"
1082
+ ],
1083
+ "provenance": [
1084
+ {
1085
+ "kind": "doc",
1086
+ "locator": "https://learn.chatgpt.com/docs/hooks",
1087
+ "date": "2026-10-12"
1088
+ },
1089
+ {
1090
+ "kind": "fixture",
1091
+ "locator": "test/hooks/session-end-observation.test.ts",
1092
+ "date": "2026-11-04"
1093
+ }
1094
+ ]
1095
+ },
1096
+ {
1097
+ "policy": "session-end",
1098
+ "harness": "opencode",
1099
+ "event": "*",
1100
+ "timing": "session",
1101
+ "profile": "any",
1102
+ "wired": false,
1103
+ "configSource": null,
1104
+ "harnessVersion": {
1105
+ "tested": "1.18.30"
1106
+ },
1107
+ "class": "unsupported",
1108
+ "verification": "unverified",
1109
+ "prerequisites": [],
1110
+ "covers": [],
1111
+ "doesNotCover": [],
1112
+ "caveats": [],
1113
+ "provenance": [
1114
+ {
1115
+ "kind": "doc",
1116
+ "locator": "core/registry/harnesses.json: opencode harness; core/registry/contracts.json: unavailable hook mapping",
1117
+ "date": "2026-10-12"
1118
+ }
1119
+ ]
1120
+ },
1121
+ {
1122
+ "policy": "session-end",
1123
+ "harness": "pi",
1124
+ "event": "*",
1125
+ "timing": "session",
1126
+ "profile": "any",
1127
+ "wired": false,
1128
+ "configSource": null,
1129
+ "harnessVersion": {
1130
+ "tested": "1.1.0"
1131
+ },
1132
+ "class": "unsupported",
1133
+ "verification": "unverified",
1134
+ "prerequisites": [],
1135
+ "covers": [],
1136
+ "doesNotCover": [],
1137
+ "caveats": [
1138
+ "not wired for this harness mapping",
1139
+ "Pi user- and project-scope extensions have not been exercised in a live session; a later tool_call handler may mutate input after DoFlow allows it"
1140
+ ],
1141
+ "provenance": [
1142
+ {
1143
+ "kind": "doc",
1144
+ "locator": "core/registry/lifecycle.json: policy session-end mapping for pi",
1145
+ "date": "2026-11-04"
1146
+ }
1147
+ ]
1148
+ },
1149
+ {
1150
+ "policy": "session-end",
1151
+ "harness": "copilot",
1152
+ "event": "*",
1153
+ "timing": "session",
1154
+ "profile": "any",
1155
+ "wired": false,
1156
+ "configSource": null,
1157
+ "harnessVersion": {
1158
+ "tested": "GitHub Copilot CLI 1.0.103"
1159
+ },
1160
+ "class": "unsupported",
1161
+ "verification": "unverified",
1162
+ "prerequisites": [],
1163
+ "covers": [],
1164
+ "doesNotCover": [],
1165
+ "caveats": [
1166
+ "not wired for this harness mapping"
1167
+ ],
1168
+ "provenance": [
1169
+ {
1170
+ "kind": "doc",
1171
+ "locator": "core/registry/lifecycle.json: policy session-end mapping for copilot",
1172
+ "date": "2026-11-04"
1173
+ }
1174
+ ]
1175
+ },
1176
+ {
1177
+ "policy": "session-end",
1178
+ "harness": "kiro",
1179
+ "event": "*",
1180
+ "timing": "session",
1181
+ "profile": "any",
1182
+ "wired": false,
1183
+ "configSource": null,
1184
+ "harnessVersion": {
1185
+ "tested": "kiro-cli 2.29.1"
1186
+ },
1187
+ "class": "unsupported",
1188
+ "verification": "unverified",
1189
+ "prerequisites": [],
1190
+ "covers": [],
1191
+ "doesNotCover": [],
1192
+ "caveats": [
1193
+ "not wired for this harness mapping"
1194
+ ],
1195
+ "provenance": [
1196
+ {
1197
+ "kind": "doc",
1198
+ "locator": "core/registry/lifecycle.json: policy session-end mapping for kiro",
1199
+ "date": "2026-11-04"
1200
+ }
1201
+ ]
1202
+ },
1203
+ {
1204
+ "policy": "session-end",
1205
+ "harness": "antigravity",
1206
+ "event": "*",
1207
+ "timing": "session",
1208
+ "profile": "any",
1209
+ "wired": false,
1210
+ "configSource": null,
1211
+ "harnessVersion": {
1212
+ "tested": "1.3.3"
1213
+ },
1214
+ "class": "unsupported",
1215
+ "verification": "unverified",
1216
+ "prerequisites": [],
1217
+ "covers": [],
1218
+ "doesNotCover": [],
1219
+ "caveats": [
1220
+ "not wired for this harness mapping"
1221
+ ],
1222
+ "provenance": [
1223
+ {
1224
+ "kind": "doc",
1225
+ "locator": "core/registry/lifecycle.json: policy session-end mapping for antigravity",
1226
+ "date": "2026-11-04"
1227
+ }
1228
+ ]
1229
+ },
979
1230
  {
980
1231
  "policy": "session-context",
981
1232
  "harness": "opencode",
@@ -1793,7 +2044,7 @@
1793
2044
  "timing": "stop",
1794
2045
  "profile": "any",
1795
2046
  "wired": true,
1796
- "configSource": "src/adapters/antigravity/index.js:60",
2047
+ "configSource": "src/adapters/antigravity/index.js:64",
1797
2048
  "harnessVersion": {
1798
2049
  "tested": "1.3.3"
1799
2050
  },
@@ -2448,6 +2699,6 @@
2448
2699
  ]
2449
2700
  }
2450
2701
  ],
2451
- "rowsDigest": "sha256:39c81a958388528cddec2fa524296872bf420d37073ae643a76faddc54893cf5"
2702
+ "rowsDigest": "sha256:bb6f6cd25ed87131d95bfa0dda3f7a4ecd03b4f19216510685b2a5b640a353c6"
2452
2703
  }
2453
2704
  }
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "manifest": 1,
3
3
  "id": "doflow",
4
- "version": "2.0.1",
4
+ "version": "2.0.2",
5
5
  "summary": "DoFlow first-party presets",
6
- "doflow": "=2.0.1",
6
+ "doflow": "=2.0.2",
7
7
  "contributions": [
8
8
  {
9
9
  "point": "debate-preset",
@@ -27,62 +27,62 @@
27
27
  { "layer": "project", "kind": "decision-model", "path": "decision-model.json", "field": "model" }],
28
28
  "consumers": ["src/runtime/advice/config.js"], "description": "Decision-model name; a project may choose it while advice is on." },
29
29
  "advice.kinds.tier": { "type": "enum", "values": ["off", "shadow", "act"], "default": null,
30
- "scope": "project-overridable", "combine": "override", "securityRelevant": false, "failSafe": "off",
30
+ "scope": "project-overridable", "combine": "override", "securityRelevant": true, "failSafe": "off",
31
31
  "env": null, "flag": null, "shellRead": null, "needsConfigHome": false, "legacy": [],
32
32
  "consumers": ["src/runtime/advice/shadow-config.js"],
33
33
  "description": "Advice mode for the tier kind: off, shadow (record only) or act; unset keeps the kind's own path, the highest layer that sets it decides and an invalid value is off." },
34
34
  "advice.kinds.task-class": { "type": "enum", "values": ["off", "shadow", "act"], "default": null,
35
- "scope": "project-overridable", "combine": "override", "securityRelevant": false, "failSafe": "off",
35
+ "scope": "project-overridable", "combine": "override", "securityRelevant": true, "failSafe": "off",
36
36
  "env": null, "flag": null, "shellRead": null, "needsConfigHome": false, "legacy": [],
37
37
  "consumers": ["src/runtime/advice/shadow-config.js"],
38
38
  "description": "Advice mode for the task-class kind: off, shadow (record only) or act; unset keeps the kind's own path, the highest layer that sets it decides and an invalid value is off." },
39
39
  "advice.kinds.verify-risk": { "type": "enum", "values": ["off", "shadow", "act"], "default": null,
40
- "scope": "project-overridable", "combine": "override", "securityRelevant": false, "failSafe": "off",
40
+ "scope": "project-overridable", "combine": "override", "securityRelevant": true, "failSafe": "off",
41
41
  "env": null, "flag": null, "shellRead": null, "needsConfigHome": false, "legacy": [],
42
42
  "consumers": ["src/runtime/advice/shadow-config.js"],
43
43
  "description": "Advice mode for the verify-risk kind: off, shadow (record only) or act; unset keeps the kind's own path, the highest layer that sets it decides and an invalid value is off." },
44
44
  "advice.kinds.review-depth": { "type": "enum", "values": ["off", "shadow", "act"], "default": null,
45
- "scope": "project-overridable", "combine": "override", "securityRelevant": false, "failSafe": "off",
45
+ "scope": "project-overridable", "combine": "override", "securityRelevant": true, "failSafe": "off",
46
46
  "env": null, "flag": null, "shellRead": null, "needsConfigHome": false, "legacy": [],
47
47
  "consumers": ["src/runtime/advice/shadow-config.js"],
48
48
  "description": "Advice mode for the review-depth kind: off, shadow (record only) or act; unset keeps the kind's own path, the highest layer that sets it decides and an invalid value is off." },
49
49
  "advice.kinds.mcp-need": { "type": "enum", "values": ["off", "shadow", "act"], "default": null,
50
- "scope": "project-overridable", "combine": "override", "securityRelevant": false, "failSafe": "off",
50
+ "scope": "project-overridable", "combine": "override", "securityRelevant": true, "failSafe": "off",
51
51
  "env": null, "flag": null, "shellRead": null, "needsConfigHome": false, "legacy": [],
52
52
  "consumers": ["src/runtime/advice/shadow-config.js"],
53
53
  "description": "Advice mode for the mcp-need kind: off, shadow (record only) or act; unset keeps the kind's own path, the highest layer that sets it decides and an invalid value is off." },
54
54
  "advice.kinds.followup-triage": { "type": "enum", "values": ["off", "shadow", "act"], "default": null,
55
- "scope": "project-overridable", "combine": "override", "securityRelevant": false, "failSafe": "off",
55
+ "scope": "project-overridable", "combine": "override", "securityRelevant": true, "failSafe": "off",
56
56
  "env": null, "flag": null, "shellRead": null, "needsConfigHome": false, "legacy": [],
57
57
  "consumers": ["src/runtime/advice/shadow-config.js"],
58
58
  "description": "Advice mode for the followup-triage kind: off, shadow (record only) or act; unset keeps the kind's own path, the highest layer that sets it decides and an invalid value is off." },
59
59
  "advice.models.tier": { "type": "string", "default": null,
60
- "scope": "project-overridable", "combine": "override", "securityRelevant": false,
60
+ "scope": "project-overridable", "combine": "override", "securityRelevant": true, "failSafe": { "gate": "advice.enabled" },
61
61
  "env": null, "flag": null, "shellRead": null, "needsConfigHome": false, "legacy": [],
62
62
  "consumers": ["src/runtime/advice/shadow-config.js"],
63
63
  "description": "Decision-model name for the tier kind; unset uses advice.model." },
64
64
  "advice.models.task-class": { "type": "string", "default": null,
65
- "scope": "project-overridable", "combine": "override", "securityRelevant": false,
65
+ "scope": "project-overridable", "combine": "override", "securityRelevant": true, "failSafe": { "gate": "advice.enabled" },
66
66
  "env": null, "flag": null, "shellRead": null, "needsConfigHome": false, "legacy": [],
67
67
  "consumers": ["src/runtime/advice/shadow-config.js"],
68
68
  "description": "Decision-model name for the task-class kind; unset uses advice.model." },
69
69
  "advice.models.verify-risk": { "type": "string", "default": null,
70
- "scope": "project-overridable", "combine": "override", "securityRelevant": false,
70
+ "scope": "project-overridable", "combine": "override", "securityRelevant": true, "failSafe": { "gate": "advice.enabled" },
71
71
  "env": null, "flag": null, "shellRead": null, "needsConfigHome": false, "legacy": [],
72
72
  "consumers": ["src/runtime/advice/shadow-config.js"],
73
73
  "description": "Decision-model name for the verify-risk kind; unset uses advice.model." },
74
74
  "advice.models.review-depth": { "type": "string", "default": null,
75
- "scope": "project-overridable", "combine": "override", "securityRelevant": false,
75
+ "scope": "project-overridable", "combine": "override", "securityRelevant": true, "failSafe": { "gate": "advice.enabled" },
76
76
  "env": null, "flag": null, "shellRead": null, "needsConfigHome": false, "legacy": [],
77
77
  "consumers": ["src/runtime/advice/shadow-config.js"],
78
78
  "description": "Decision-model name for the review-depth kind; unset uses advice.model." },
79
79
  "advice.models.mcp-need": { "type": "string", "default": null,
80
- "scope": "project-overridable", "combine": "override", "securityRelevant": false,
80
+ "scope": "project-overridable", "combine": "override", "securityRelevant": true, "failSafe": { "gate": "advice.enabled" },
81
81
  "env": null, "flag": null, "shellRead": null, "needsConfigHome": false, "legacy": [],
82
82
  "consumers": ["src/runtime/advice/shadow-config.js"],
83
83
  "description": "Decision-model name for the mcp-need kind; unset uses advice.model." },
84
84
  "advice.models.followup-triage": { "type": "string", "default": null,
85
- "scope": "project-overridable", "combine": "override", "securityRelevant": false,
85
+ "scope": "project-overridable", "combine": "override", "securityRelevant": true, "failSafe": { "gate": "advice.enabled" },
86
86
  "env": null, "flag": null, "shellRead": null, "needsConfigHome": false, "legacy": [],
87
87
  "consumers": ["src/runtime/advice/shadow-config.js"],
88
88
  "description": "Decision-model name for the followup-triage kind; unset uses advice.model." },
@@ -596,8 +596,7 @@
596
596
  "match": "^[0-9a-f]{12}$",
597
597
  "rule": "report-orphan",
598
598
  "bound": {
599
- "orphanGraceHours": 24,
600
- "foreignMaxAgeDays": 180
599
+ "orphanGraceHours": 24
601
600
  },
602
601
  "protect": null,
603
602
  "moments": [
@@ -308,6 +308,13 @@ reading it whole:
308
308
  attributes, keys and cardinalities of that subdomain alone. The table catalog of entities, keys,
309
309
  indexes and ORM file references is unchanged and stays below the views. Splitting one diagram into
310
310
  views must not drop an entity, a key or a constraint the single diagram carried.
311
+ - **`data-model.md` §3 to §9 — lifecycles, coupling and the rest.** §3 Lifecycles holds every
312
+ entity state, one `#### Lifecycle: <entity>` block each, and nothing else restates a state; §4 to
313
+ §9 are Cross-entity coupling, Invariants, Ownership / CRUD matrix, Event catalogue, Retention, PII
314
+ and migration, and History. Each `#### Dictionary: <entity>` row and each row of the §3 to §8
315
+ tables ends in a `Source` cell holding one of `FR-###`, `NFR-###`, `IC-###`, `code:<path>:<line>`,
316
+ `proposed`, or `UNKNOWN -> Open Point`. A `proposed` or `UNKNOWN -> Open Point` row is copied to
317
+ `design.md` Open Points for Review. A conditional section takes `N/A: [why]`.
311
318
 
312
319
  ### The `N/A: [why]` escape
313
320