@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.
- package/core/.claude-plugin/plugin.json +1 -1
- package/core/.codex-plugin/plugin.json +1 -1
- package/core/.plugin/plugin.json +1 -1
- package/core/harnesses/claude/hooks/session-end.sh +21 -1
- package/core/harnesses/codex/hooks/session-end.impl.sh +21 -1
- package/core/harnesses/shared/hooks/policies/compact-text.sh +8 -0
- package/core/harnesses/shared/hooks/policies/subagent-audit.sh +25 -1
- package/core/registry/contribution-points.json +1 -1
- package/core/registry/intake.json +3 -3
- package/core/registry/lifecycle.json +256 -5
- package/core/registry/packages/doflow/doflow-package.json +2 -2
- package/core/registry/settings.json +12 -12
- package/core/registry/storage.json +1 -2
- package/core/shared/guidance/references/ARTIFACT_FORMAT.md +7 -0
- package/core/shared/scripts/doflow/bash/do-git-state.sh +12 -4
- package/core/shared/scripts/doflow/bash/do-parallel-check.sh +86 -33
- package/core/shared/scripts/doflow/bash/do-review-package.sh +36 -2
- package/core/shared/scripts/doflow/bin/doflow-run +18 -0
- package/core/shared/skills/do-design/SKILL.md +6 -2
- package/core/shared/skills/do-design/references/data_model_example.md +167 -0
- package/core/shared/templates/doflow/data-model-template.md +136 -102
- package/package.json +1 -1
- package/src/adapters/antigravity/index.js +54 -12
- package/src/adapters/codex/agents.js +15 -1
- package/src/adapters/codex/config.js +5 -2
- package/src/adapters/copilot/index.js +11 -4
- package/src/adapters/copy-tree.js +7 -0
- package/src/adapters/created-file.js +41 -0
- package/src/adapters/mcp-entries.js +11 -1
- package/src/adapters/opencode/index.js +32 -5
- package/src/adapters/pi/index.js +15 -4
- package/src/adapters/pi/mcp.js +44 -18
- package/src/cli/commands/remove.js +3 -1
- package/src/cli/commands/update.js +7 -3
- package/src/cli/index.js +24 -12
- package/src/cli/runtime-commands.js +1 -1
- package/src/cli/shared.js +5 -3
- package/src/helper/marker-merge.js +11 -7
- package/src/install/backup-set.js +7 -3
- package/src/install/backup.js +13 -7
- package/src/install/context.js +2 -1
- package/src/install/manifest.js +35 -11
- package/src/install/paths.js +38 -0
- package/src/install/targets.js +11 -2
- package/src/lifecycle/index.js +80 -3
- package/src/lifecycle/retired-harnesses.js +16 -1
- package/src/lifecycle/view.js +3 -2
- package/src/registry/index.js +21 -4
- package/src/release/docs-blocks.js +5 -1
- package/src/runtime/advice/doctor.js +2 -2
- package/src/runtime/brief-tools.js +2 -1
- package/src/runtime/capability-router.js +26 -3
- package/src/runtime/context/pointer.js +17 -5
- package/src/runtime/context-pack.js +48 -8
- package/src/runtime/dispatch/integrate.js +27 -8
- package/src/runtime/dispatch/loop.js +7 -0
- package/src/runtime/dispatch/verify-run.js +9 -3
- package/src/runtime/feature-pointer.js +10 -1
- package/src/runtime/health.js +9 -4
- package/src/runtime/implementation-gate.js +10 -2
- package/src/runtime/intake/engine.js +11 -9
- package/src/runtime/knowledge/code-retrieval.js +11 -5
- package/src/runtime/knowledge/semble-provider.js +12 -2
- package/src/runtime/lifecycle/cli.js +7 -5
- package/src/runtime/lifecycle/overview.js +32 -2
- package/src/runtime/lifecycle/release.js +16 -3
- package/src/runtime/lifecycle/retention.js +12 -15
- package/src/runtime/lifecycle/store-upkeep.js +13 -3
- package/src/runtime/mask.js +3 -3
- package/src/runtime/mcp-consultations.js +11 -5
- package/src/runtime/research-request.js +3 -1
- package/src/runtime/review/command.js +3 -7
- package/src/runtime/review/start.js +24 -10
- package/src/runtime/roadmap/loop.js +14 -3
- package/src/runtime/roadmap/rows.js +2 -1
- package/src/runtime/settings/files.js +3 -1
- package/src/runtime/settings/prepared-run.js +12 -2
- package/src/runtime/settings/resolve.js +13 -1
- package/src/runtime/settings/write.js +73 -2
- package/src/runtime/storage/registry.js +2 -2
- package/src/runtime/storage/roots.js +4 -18
- package/src/runtime/storage/rules.js +22 -46
- package/src/runtime/storage/work-status.js +14 -4
- package/src/runtime/task-scope.js +17 -2
- package/src/runtime/task-state.js +11 -4
- package/src/runtime/trace/analyze.js +4 -2
- package/src/runtime/trace/indicators.js +25 -20
- package/src/runtime/trace/spans.js +4 -5
- package/src/runtime/verb-view.js +6 -5
- package/src/runtime/worker/command.js +4 -2
- package/src/runtime/worker/readiness.js +8 -4
- package/src/runtime/worker/supervisor.js +18 -6
- package/src/runtime/workflow-orchestrator.js +6 -2
package/core/.plugin/plugin.json
CHANGED
|
@@ -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 ||
|
|
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": "
|
|
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":
|
|
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": "
|
|
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:
|
|
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:
|
|
2702
|
+
"rowsDigest": "sha256:bb6f6cd25ed87131d95bfa0dda3f7a4ecd03b4f19216510685b2a5b640a353c6"
|
|
2452
2703
|
}
|
|
2453
2704
|
}
|
|
@@ -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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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." },
|
|
@@ -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
|
|