repo-harness 0.8.3 → 0.8.5

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/AGENTS.md CHANGED
@@ -63,35 +63,38 @@ bash scripts/migrate-project-template.sh --repo . --dry-run
63
63
  <!-- BEGIN ARCHITECTURE CONTRACT -->
64
64
  ## Architecture Contract
65
65
 
66
- - Functional block: `.ai/hooks`
67
- - Capability ID: `runtime-harness-hook-adapters`
68
- - Matched prefix: `.ai/hooks`
69
- - Architecture domain: `runtime-harness`
70
- - Architecture capability: `hook-adapters`
71
- - Architecture module: `docs/architecture/modules/runtime-harness/hook-adapters.md`
72
- - Last architecture event: 2026-05-29T09:44:46+0800
73
- - Last changed path: `.ai/hooks/session-start-context.sh`
66
+ - Functional block: `scripts/inspect-project-state.ts`
67
+ - Capability ID: `workflow-engine-inspection-migration`
68
+ - Matched prefix: `scripts/inspect-project-state.ts`
69
+ - Architecture domain: `workflow-engine`
70
+ - Architecture capability: `inspection-migration`
71
+ - Architecture module: `docs/architecture/modules/workflow-engine/inspection-migration.md`
72
+ - Last architecture event: 2026-07-03T15:44:54+0800
73
+ - Last changed path: `docs/architecture/requests/archive/2026/workflow-engine-inspection-migration.md`
74
74
  - Severity: high
75
- - Change type: workflow-surface
75
+ - Change type: architecture-closeout
76
76
  - Module responsibility: Keep this block aligned with the local boundary described by surrounding human-owned context.
77
- - Entrypoints: `.ai/hooks`
77
+ - Entrypoints: `scripts/inspect-project-state.ts`
78
78
  - Allowed dependencies: Follow root `AGENTS.md` / `CLAUDE.md` and this local contract.
79
79
  - Forbidden dependencies: Do not cross sibling app/service/package boundaries without an architecture snapshot or explicit plan.
80
- - Runtime path: `.ai/hooks`
80
+ - Runtime path: `scripts/inspect-project-state.ts`
81
81
  - LSP/tooling profile: `typescript-lsp`
82
82
  - Verification: Use root required checks plus local commands recorded in this capability contract.
83
83
  - Latest snapshot: `(none yet)`
84
- - Semantic diagram source: `docs/architecture/modules/runtime-harness/hook-adapters.md`
84
+ - Semantic diagram source: `docs/architecture/modules/workflow-engine/inspection-migration.md`
85
85
  - Latest human diagram: `(none yet)`
86
86
  - Pending architecture request: `(none)`
87
87
 
88
88
  ## Active Workstreams
89
89
 
90
- - (none yet)
90
+ - `tasks/workstreams/workflow-engine/inspection-migration/20260703-inspection-migration.md`
91
+ - status: active
92
+ - current_slice: completed-20260703-architecture-closeout
93
+ - source_plan: (none)
91
94
 
92
95
  ## Current Session Projection
93
96
 
94
- - Durable progress lives under `tasks/workstreams/runtime-harness/hook-adapters`.
97
+ - Durable progress lives under `tasks/workstreams/workflow-engine/inspection-migration`.
95
98
  - `tasks/current.md` is the tracked derived status snapshot; it is not a live lock or task source.
96
99
  - `tasks/todos.md` is the deferred-goal ledger; current execution slices stay in the active plan's `## Task Breakdown`.
97
100
  <!-- END ARCHITECTURE CONTRACT -->
package/CLAUDE.md CHANGED
@@ -63,35 +63,38 @@ bash scripts/migrate-project-template.sh --repo . --dry-run
63
63
  <!-- BEGIN ARCHITECTURE CONTRACT -->
64
64
  ## Architecture Contract
65
65
 
66
- - Functional block: `.ai/hooks`
67
- - Capability ID: `runtime-harness-hook-adapters`
68
- - Matched prefix: `.ai/hooks`
69
- - Architecture domain: `runtime-harness`
70
- - Architecture capability: `hook-adapters`
71
- - Architecture module: `docs/architecture/modules/runtime-harness/hook-adapters.md`
72
- - Last architecture event: 2026-05-29T09:44:46+0800
73
- - Last changed path: `.ai/hooks/session-start-context.sh`
66
+ - Functional block: `scripts/inspect-project-state.ts`
67
+ - Capability ID: `workflow-engine-inspection-migration`
68
+ - Matched prefix: `scripts/inspect-project-state.ts`
69
+ - Architecture domain: `workflow-engine`
70
+ - Architecture capability: `inspection-migration`
71
+ - Architecture module: `docs/architecture/modules/workflow-engine/inspection-migration.md`
72
+ - Last architecture event: 2026-07-03T15:44:54+0800
73
+ - Last changed path: `docs/architecture/requests/archive/2026/workflow-engine-inspection-migration.md`
74
74
  - Severity: high
75
- - Change type: workflow-surface
75
+ - Change type: architecture-closeout
76
76
  - Module responsibility: Keep this block aligned with the local boundary described by surrounding human-owned context.
77
- - Entrypoints: `.ai/hooks`
77
+ - Entrypoints: `scripts/inspect-project-state.ts`
78
78
  - Allowed dependencies: Follow root `AGENTS.md` / `CLAUDE.md` and this local contract.
79
79
  - Forbidden dependencies: Do not cross sibling app/service/package boundaries without an architecture snapshot or explicit plan.
80
- - Runtime path: `.ai/hooks`
80
+ - Runtime path: `scripts/inspect-project-state.ts`
81
81
  - LSP/tooling profile: `typescript-lsp`
82
82
  - Verification: Use root required checks plus local commands recorded in this capability contract.
83
83
  - Latest snapshot: `(none yet)`
84
- - Semantic diagram source: `docs/architecture/modules/runtime-harness/hook-adapters.md`
84
+ - Semantic diagram source: `docs/architecture/modules/workflow-engine/inspection-migration.md`
85
85
  - Latest human diagram: `(none yet)`
86
86
  - Pending architecture request: `(none)`
87
87
 
88
88
  ## Active Workstreams
89
89
 
90
- - (none yet)
90
+ - `tasks/workstreams/workflow-engine/inspection-migration/20260703-inspection-migration.md`
91
+ - status: active
92
+ - current_slice: completed-20260703-architecture-closeout
93
+ - source_plan: (none)
91
94
 
92
95
  ## Current Session Projection
93
96
 
94
- - Durable progress lives under `tasks/workstreams/runtime-harness/hook-adapters`.
97
+ - Durable progress lives under `tasks/workstreams/workflow-engine/inspection-migration`.
95
98
  - `tasks/current.md` is the tracked derived status snapshot; it is not a live lock or task source.
96
99
  - `tasks/todos.md` is the deferred-goal ledger; current execution slices stay in the active plan's `## Task Breakdown`.
97
100
  <!-- END ARCHITECTURE CONTRACT -->
package/README.es.md CHANGED
@@ -85,7 +85,7 @@ artifacts.
85
85
  ## Novedades
86
86
 
87
87
  Las notas de versión viven en [`docs/CHANGELOG.md`](docs/CHANGELOG.md). La línea
88
- actual es `0.8.3`.
88
+ actual es `0.8.5`.
89
89
 
90
90
  ## Cómo funciona
91
91
 
@@ -419,8 +419,8 @@ Guards habituales:
419
419
 
420
420
  ## Release actual
421
421
 
422
- - npm package: `repo-harness@0.8.3`
423
- - Generated workflow stamp: `repo-harness@0.8.3+template@0.8.3`
422
+ - npm package: `repo-harness@0.8.5`
423
+ - Generated workflow stamp: `repo-harness@0.8.5+template@0.8.5`
424
424
  - GitHub repository: `Ancienttwo/repo-harness`
425
425
  - Release history: [`docs/CHANGELOG.md`](docs/CHANGELOG.md)
426
426
 
package/README.fr.md CHANGED
@@ -85,7 +85,7 @@ l'emportent.
85
85
  ## Nouveautés
86
86
 
87
87
  Les notes de version vivent dans [`docs/CHANGELOG.md`](docs/CHANGELOG.md). La
88
- ligne actuelle est `0.8.3`.
88
+ ligne actuelle est `0.8.5`.
89
89
 
90
90
  ## Comment ça marche
91
91
 
@@ -424,8 +424,8 @@ Guards courants :
424
424
 
425
425
  ## Release actuelle
426
426
 
427
- - npm package : `repo-harness@0.8.3`
428
- - Generated workflow stamp : `repo-harness@0.8.3+template@0.8.3`
427
+ - npm package : `repo-harness@0.8.5`
428
+ - Generated workflow stamp : `repo-harness@0.8.5+template@0.8.5`
429
429
  - GitHub repository : `Ancienttwo/repo-harness`
430
430
  - Release history : [`docs/CHANGELOG.md`](docs/CHANGELOG.md)
431
431
 
package/README.ja.md CHANGED
@@ -75,7 +75,7 @@ review、checks、handoff と食い違う場合は、source artifacts を優先
75
75
  ## What's New
76
76
 
77
77
  リリースノートは [`docs/CHANGELOG.md`](docs/CHANGELOG.md) にあります。現在の
78
- ラインは `0.8.3` です。
78
+ ラインは `0.8.5` です。
79
79
 
80
80
  ## 仕組み
81
81
 
@@ -398,8 +398,8 @@ hook がブロックしたときは、まず terminal の構造化された出
398
398
 
399
399
  ## 現在の Release
400
400
 
401
- - npm package:`repo-harness@0.8.3`
402
- - Generated workflow stamp:`repo-harness@0.8.3+template@0.8.3`
401
+ - npm package:`repo-harness@0.8.5`
402
+ - Generated workflow stamp:`repo-harness@0.8.5+template@0.8.5`
403
403
  - GitHub repository:`Ancienttwo/repo-harness`
404
404
  - Release history:[`docs/CHANGELOG.md`](docs/CHANGELOG.md)
405
405
 
package/README.md CHANGED
@@ -79,7 +79,7 @@ active plan, contract, review, checks, or handoff, the source artifacts win.
79
79
  ## What's New
80
80
 
81
81
  Release notes live in [`docs/CHANGELOG.md`](docs/CHANGELOG.md). The current line
82
- is `0.8.3`.
82
+ is `0.8.5`.
83
83
 
84
84
  ## How It Works
85
85
 
@@ -599,8 +599,8 @@ Most common guards:
599
599
 
600
600
  ## Current Release
601
601
 
602
- - npm package: `repo-harness@0.8.3`
603
- - Generated workflow stamp: `repo-harness@0.8.3+template@0.8.3`
602
+ - npm package: `repo-harness@0.8.5`
603
+ - Generated workflow stamp: `repo-harness@0.8.5+template@0.8.5`
604
604
  - GitHub repository: `Ancienttwo/repo-harness`
605
605
  - Release history: [`docs/CHANGELOG.md`](docs/CHANGELOG.md)
606
606
 
package/README.zh-CN.md CHANGED
@@ -69,7 +69,7 @@ review、checks 或 handoff 冲突,以 source artifacts 为准。
69
69
 
70
70
  ## What's New
71
71
 
72
- Release notes 见 [`docs/CHANGELOG.md`](docs/CHANGELOG.md),当前版本线是 `0.8.3`。
72
+ Release notes 见 [`docs/CHANGELOG.md`](docs/CHANGELOG.md),当前版本线是 `0.8.5`。
73
73
 
74
74
  ## 工作原理
75
75
 
@@ -445,8 +445,8 @@ hook block 工作时,先看 terminal 里的结构化输出。核心字段是
445
445
 
446
446
  ## 当前 Release
447
447
 
448
- - npm package:`repo-harness@0.8.3`
449
- - Generated workflow stamp:`repo-harness@0.8.3+template@0.8.3`
448
+ - npm package:`repo-harness@0.8.5`
449
+ - Generated workflow stamp:`repo-harness@0.8.5+template@0.8.5`
450
450
  - GitHub repository:`Ancienttwo/repo-harness`
451
451
  - Release history:[`docs/CHANGELOG.md`](docs/CHANGELOG.md)
452
452
 
@@ -29,6 +29,14 @@ Before changing behavior, infer why the current shape exists: compatibility boun
29
29
 
30
30
  Do not introduce a new abstraction unless it removes real complexity, matches an existing local pattern, or protects a cross-module invariant.
31
31
 
32
+ ## No Compatibility Fallbacks in Product Code
33
+
34
+ Do not add fallback, compatibility, heuristic, defensive, or "best effort" code paths unless the current task or a human-approved migration/release contract explicitly demands that path. Prefer fail-closed behavior with a clear error over silently inventing output.
35
+
36
+ When the source of truth is an LLM/provider/external authority/user input contract, do not re-derive the same semantic data with local deterministic rules, regexes, multilingual pattern lists, shadow parsers, or compatibility shims. If the authoritative value is missing, malformed, unauthenticated, or unavailable, surface that failure and stop; do not synthesize a replacement to make the flow continue.
37
+
38
+ Product-logic compatibility is harmful by default. Do not preserve old product semantics, accept multiple semantic shapes, infer missing fields, or translate one domain meaning into another unless the user explicitly requested that compatibility in the current task or a human-approved migration/release contract names it. Compatibility for old wire formats, legacy clients, or migration windows is allowed only when it is explicit, covered by tests, and bounded by a removal or ownership path. Validation, security checks, data-safety checks, and error handling remain required, but they must reject or report invalid states instead of changing semantics.
39
+
32
40
  ## Reporting
33
41
 
34
42
  For small tasks, keep P1/P2/P3 internal and report only the conclusion.
@@ -43,12 +51,10 @@ Reports must be concise and grounded in files, commands, runtime behavior, obser
43
51
 
44
52
  ## Completion Summary Rule
45
53
 
46
- For non-trivial completed tasks, include a short `下一刀` section at the end of the final delivery report unless there is genuinely no meaningful follow-up.
47
54
  For non-trivial completed tasks, include a short `下一刀` section only when verified state shows a concrete next bottleneck, unresolved risk, failing check, deployment gap, review gap, or active-plan item that materially affects the user's stated goal.
48
55
 
49
56
  Do not manufacture follow-up work just to keep slicing. If the task is reasonably complete and the remaining work would be speculative, low-value polish, or over-engineering, omit `下一刀` and stop at the completion report.
50
57
 
51
- The recommendation is not a question. It must be one concrete, bounded next slice derived from verified state: active plan, todo, handoff, failing checks, review gaps, deployment state, unresolved risk, or observed system behavior.
52
58
  When included, the recommendation is not a question. It must be one concrete, bounded next slice derived from verified state: active plan, todo, handoff, failing checks, review gaps, deployment state, unresolved risk, or observed system behavior.
53
59
 
54
60
  Format:
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "0.8.3",
3
- "templateVersion": "0.8.3",
2
+ "version": "0.8.5",
3
+ "templateVersion": "0.8.5",
4
4
  "skillName": "repo-harness",
5
5
  "contractId": "tasks-first-harness-v1",
6
6
  "compatibility": {
@@ -179,6 +179,14 @@
179
179
  {
180
180
  "version": "0.8.3",
181
181
  "description": "Keeps adopt and migration helper runtime package-only, removes local compatibility wrapper generation, and refreshes dependency lines to latest"
182
+ },
183
+ {
184
+ "version": "0.8.4",
185
+ "description": "Lets package-dispatched workstream sync resolve bundled helper siblings when downstream repos do not vendor legacy scripts"
186
+ },
187
+ {
188
+ "version": "0.8.5",
189
+ "description": "Repairs workspace-source Bun global installs that hit DependencyLoop by reinstalling from a packed tarball and adds packaged sprint-backlog target-root smoke coverage"
182
190
  }
183
191
  ],
184
192
  "generatedProjectStamp": {
@@ -2,7 +2,22 @@
2
2
  set -euo pipefail
3
3
 
4
4
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
- if REPO_ROOT="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null)"; then
5
+ if [[ -n "${REPO_HARNESS_TARGET_REPO_ROOT:-}" ]]; then
6
+ if [[ "$REPO_HARNESS_TARGET_REPO_ROOT" != /* ]]; then
7
+ echo "sprint-backlog: REPO_HARNESS_TARGET_REPO_ROOT must be an absolute path" >&2
8
+ exit 2
9
+ fi
10
+ if ! REPO_ROOT="$(cd "$REPO_HARNESS_TARGET_REPO_ROOT" 2>/dev/null && pwd -P)"; then
11
+ echo "sprint-backlog: REPO_HARNESS_TARGET_REPO_ROOT does not resolve to a directory" >&2
12
+ exit 2
13
+ fi
14
+ CURRENT_ROOT="$(pwd -P)"
15
+ if [[ "$REPO_ROOT" != "$CURRENT_ROOT" ]]; then
16
+ echo "sprint-backlog: REPO_HARNESS_TARGET_REPO_ROOT must match the current helper cwd" >&2
17
+ exit 2
18
+ fi
19
+ cd "$REPO_ROOT"
20
+ elif REPO_ROOT="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null)"; then
6
21
  cd "$REPO_ROOT"
7
22
  else
8
23
  cd "$SCRIPT_DIR/.."
@@ -83,6 +83,47 @@ validate_block() {
83
83
  [[ -e "$block" ]]
84
84
  }
85
85
 
86
+ helper_sibling() {
87
+ local helper_name="$1"
88
+ local helper_dir=""
89
+ if [[ -n "${REPO_HARNESS_HELPER_SOURCE_PATH:-}" ]]; then
90
+ helper_dir="$(dirname "$REPO_HARNESS_HELPER_SOURCE_PATH")"
91
+ fi
92
+ if [[ -n "$helper_dir" && -f "$helper_dir/$helper_name" ]]; then
93
+ printf '%s\n' "$helper_dir/$helper_name"
94
+ return 0
95
+ fi
96
+ return 1
97
+ }
98
+
99
+ capability_resolver() {
100
+ local sibling=""
101
+ if command -v bun >/dev/null 2>&1 && [[ -f "scripts/capability-resolver.ts" ]]; then
102
+ bun scripts/capability-resolver.ts "$@"
103
+ return $?
104
+ fi
105
+ sibling="$(helper_sibling capability-resolver.ts || true)"
106
+ if command -v bun >/dev/null 2>&1 && [[ -n "$sibling" ]]; then
107
+ bun "$sibling" "$@"
108
+ return $?
109
+ fi
110
+ return 127
111
+ }
112
+
113
+ context_contract_sync() {
114
+ local sibling=""
115
+ if [[ -x "scripts/context-contract-sync.sh" ]]; then
116
+ bash "scripts/context-contract-sync.sh" "$@"
117
+ return $?
118
+ fi
119
+ sibling="$(helper_sibling context-contract-sync.sh || true)"
120
+ if [[ -n "$sibling" ]]; then
121
+ bash "$sibling" "$@"
122
+ return $?
123
+ fi
124
+ return 127
125
+ }
126
+
86
127
  while [[ $# -gt 0 ]]; do
87
128
  case "$1" in
88
129
  --block)
@@ -139,12 +180,12 @@ if ! validate_block "$functional_block"; then
139
180
  exit 2
140
181
  fi
141
182
 
142
- if [[ ! -f "scripts/capability-resolver.ts" ]] || ! command -v bun >/dev/null 2>&1; then
143
- echo "workstream-sync: scripts/capability-resolver.ts and bun are required" >&2
183
+ if ! command -v bun >/dev/null 2>&1 || ! capability_resolver list --format json >/dev/null 2>&1; then
184
+ echo "workstream-sync: capability-resolver.ts and bun are required" >&2
144
185
  exit 2
145
186
  fi
146
187
 
147
- if ! resolver_json="$(bun scripts/capability-resolver.ts match --path "$functional_block" --format json 2>&1)"; then
188
+ if ! resolver_json="$(capability_resolver match --path "$functional_block" --format json 2>&1)"; then
148
189
  echo "$resolver_json" >&2
149
190
  exit 1
150
191
  fi
@@ -257,8 +298,6 @@ fi
257
298
  event_json="{\"ts\":\"$(json_escape "$iso_timestamp")\",\"file_path\":\"$(json_escape "$workstream_file")\",\"severity\":\"medium\",\"functional_block\":\"$(json_escape "$functional_block")\",\"capability_id\":\"$(json_escape "$capability_id")\",\"matched_prefix\":\"$(json_escape "$matched_prefix")\",\"architecture_domain\":\"$(json_escape "$architecture_domain")\",\"architecture_capability\":\"$(json_escape "$architecture_capability")\",\"architecture_module\":\"$(json_escape "$architecture_module")\",\"workstream_dir\":\"$(json_escape "$workstream_dir")\",\"contract_agents\":\"$(json_escape "$contract_agents")\",\"contract_claude\":\"$(json_escape "$contract_claude")\",\"active_workstream\":\"$(json_escape "$workstream_file")\",\"change_type\":\"workstream-sync\",\"spawn_recommended\":false,\"contract_sync_required\":true,\"request_file\":\"$(json_escape "$request_file")\"}"
258
299
  printf '%s\n' "$event_json" >> "$event_file"
259
300
 
260
- if [[ -f "$helper_dir/context-contract-sync.sh" ]]; then
261
- bash "$helper_dir/context-contract-sync.sh" sync-event --json "$event_json"
262
- fi
301
+ context_contract_sync sync-event --json "$event_json" >/dev/null 2>&1 || true
263
302
 
264
303
  echo "[WorkstreamSync] Ensured $workstream_file for $capability_id."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "repo-harness",
3
- "version": "0.8.3",
3
+ "version": "0.8.5",
4
4
  "description": "Installs, migrates, audits, and repairs repo-local agentic development harnesses",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -0,0 +1,68 @@
1
+ # Functional Block Agent Context
2
+
3
+ Keep this file focused on the local contract for this primary functional block.
4
+
5
+ <!-- BEGIN CAPABILITY CONTEXT -->
6
+ ## Capability Context
7
+
8
+ - Capability ID: `workflow-engine-inspection-migration`
9
+ - Domain: `workflow-engine`
10
+ - Name: `inspection-migration`
11
+ - Primary prefix: `scripts/inspect-project-state.ts`
12
+ - Architecture module: `docs/architecture/modules/workflow-engine/inspection-migration.md`
13
+ - Workstream: `tasks/workstreams/workflow-engine/inspection-migration`
14
+
15
+ ## Positioning
16
+
17
+ Owns the workflow-engine-inspection-migration capability boundary declared in .ai/context/capabilities.json.
18
+
19
+ ## Source Map
20
+
21
+ - Primary prefix: `scripts/inspect-project-state.ts` (entrypoint)
22
+ - Architecture module: `docs/architecture/modules/workflow-engine/inspection-migration.md` (design-source)
23
+ - Workstream: `tasks/workstreams/workflow-engine/inspection-migration` (durable-progress)
24
+
25
+ ## Refresh Hints
26
+
27
+ - `bun test tests/migration-script.test.ts tests/create-project-dirs.runtime.test.ts tests/workflow-contract.test.ts`
28
+ - `bash scripts/migrate-project-template.sh --repo . --dry-run`
29
+ <!-- END CAPABILITY CONTEXT -->
30
+
31
+ <!-- BEGIN ARCHITECTURE CONTRACT -->
32
+ ## Architecture Contract
33
+
34
+ - Functional block: `scripts/inspect-project-state.ts`
35
+ - Capability ID: `workflow-engine-inspection-migration`
36
+ - Matched prefix: `scripts/inspect-project-state.ts`
37
+ - Architecture domain: `workflow-engine`
38
+ - Architecture capability: `inspection-migration`
39
+ - Architecture module: `docs/architecture/modules/workflow-engine/inspection-migration.md`
40
+ - Last architecture event: 2026-07-03T15:45:36+0800
41
+ - Last changed path: `docs/architecture/requests/archive/2026/workflow-engine-inspection-migration.md`
42
+ - Severity: high
43
+ - Change type: architecture-closeout
44
+ - Module responsibility: Keep this block aligned with the local boundary described by surrounding human-owned context.
45
+ - Entrypoints: `scripts/inspect-project-state.ts`
46
+ - Allowed dependencies: Follow root `AGENTS.md` / `CLAUDE.md` and this local contract.
47
+ - Forbidden dependencies: Do not cross sibling app/service/package boundaries without an architecture snapshot or explicit plan.
48
+ - Runtime path: `scripts/inspect-project-state.ts`
49
+ - LSP/tooling profile: `typescript-lsp`
50
+ - Verification: Use root required checks plus local commands recorded in this capability contract.
51
+ - Latest snapshot: `(none yet)`
52
+ - Semantic diagram source: `docs/architecture/modules/workflow-engine/inspection-migration.md`
53
+ - Latest human diagram: `(none yet)`
54
+ - Pending architecture request: `(none)`
55
+
56
+ ## Active Workstreams
57
+
58
+ - `tasks/workstreams/workflow-engine/inspection-migration/20260703-inspection-migration.md`
59
+ - status: active
60
+ - current_slice: completed-20260703-architecture-closeout
61
+ - source_plan: (none)
62
+
63
+ ## Current Session Projection
64
+
65
+ - Durable progress lives under `tasks/workstreams/workflow-engine/inspection-migration`.
66
+ - `tasks/current.md` is the tracked derived status snapshot; it is not a live lock or task source.
67
+ - `tasks/todos.md` is the deferred-goal ledger; current execution slices stay in the active plan's `## Task Breakdown`.
68
+ <!-- END ARCHITECTURE CONTRACT -->
@@ -0,0 +1,68 @@
1
+ # Functional Block Agent Context
2
+
3
+ Keep this file focused on the local contract for this primary functional block.
4
+
5
+ <!-- BEGIN CAPABILITY CONTEXT -->
6
+ ## Capability Context
7
+
8
+ - Capability ID: `workflow-engine-inspection-migration`
9
+ - Domain: `workflow-engine`
10
+ - Name: `inspection-migration`
11
+ - Primary prefix: `scripts/inspect-project-state.ts`
12
+ - Architecture module: `docs/architecture/modules/workflow-engine/inspection-migration.md`
13
+ - Workstream: `tasks/workstreams/workflow-engine/inspection-migration`
14
+
15
+ ## Positioning
16
+
17
+ Owns the workflow-engine-inspection-migration capability boundary declared in .ai/context/capabilities.json.
18
+
19
+ ## Source Map
20
+
21
+ - Primary prefix: `scripts/inspect-project-state.ts` (entrypoint)
22
+ - Architecture module: `docs/architecture/modules/workflow-engine/inspection-migration.md` (design-source)
23
+ - Workstream: `tasks/workstreams/workflow-engine/inspection-migration` (durable-progress)
24
+
25
+ ## Refresh Hints
26
+
27
+ - `bun test tests/migration-script.test.ts tests/create-project-dirs.runtime.test.ts tests/workflow-contract.test.ts`
28
+ - `bash scripts/migrate-project-template.sh --repo . --dry-run`
29
+ <!-- END CAPABILITY CONTEXT -->
30
+
31
+ <!-- BEGIN ARCHITECTURE CONTRACT -->
32
+ ## Architecture Contract
33
+
34
+ - Functional block: `scripts/inspect-project-state.ts`
35
+ - Capability ID: `workflow-engine-inspection-migration`
36
+ - Matched prefix: `scripts/inspect-project-state.ts`
37
+ - Architecture domain: `workflow-engine`
38
+ - Architecture capability: `inspection-migration`
39
+ - Architecture module: `docs/architecture/modules/workflow-engine/inspection-migration.md`
40
+ - Last architecture event: 2026-07-03T15:45:36+0800
41
+ - Last changed path: `docs/architecture/requests/archive/2026/workflow-engine-inspection-migration.md`
42
+ - Severity: high
43
+ - Change type: architecture-closeout
44
+ - Module responsibility: Keep this block aligned with the local boundary described by surrounding human-owned context.
45
+ - Entrypoints: `scripts/inspect-project-state.ts`
46
+ - Allowed dependencies: Follow root `AGENTS.md` / `CLAUDE.md` and this local contract.
47
+ - Forbidden dependencies: Do not cross sibling app/service/package boundaries without an architecture snapshot or explicit plan.
48
+ - Runtime path: `scripts/inspect-project-state.ts`
49
+ - LSP/tooling profile: `typescript-lsp`
50
+ - Verification: Use root required checks plus local commands recorded in this capability contract.
51
+ - Latest snapshot: `(none yet)`
52
+ - Semantic diagram source: `docs/architecture/modules/workflow-engine/inspection-migration.md`
53
+ - Latest human diagram: `(none yet)`
54
+ - Pending architecture request: `(none)`
55
+
56
+ ## Active Workstreams
57
+
58
+ - `tasks/workstreams/workflow-engine/inspection-migration/20260703-inspection-migration.md`
59
+ - status: active
60
+ - current_slice: completed-20260703-architecture-closeout
61
+ - source_plan: (none)
62
+
63
+ ## Current Session Projection
64
+
65
+ - Durable progress lives under `tasks/workstreams/workflow-engine/inspection-migration`.
66
+ - `tasks/current.md` is the tracked derived status snapshot; it is not a live lock or task source.
67
+ - `tasks/todos.md` is the deferred-goal ledger; current execution slices stay in the active plan's `## Task Breakdown`.
68
+ <!-- END ARCHITECTURE CONTRACT -->
@@ -79,6 +79,33 @@ if ! "$CLI" run check-task-workflow --help >/dev/null; then
79
79
  echo "[tarball-smoke] ERROR: packaged 'repo-harness run check-task-workflow --help' failed (run dispatcher / helper lookup / bin startup broken)" >&2
80
80
  exit 1
81
81
  fi
82
+
83
+ mkdir -p "$TARGET_REPO/plans/sprints" "$TARGET_REPO/.ai/harness/sprint"
84
+ cat > "$TARGET_REPO/plans/sprints/20991231-2359-tarball-root.sprint.md" <<'SPRINT_EOF'
85
+ # Sprint: Tarball Root
86
+
87
+ > **Status**: Approved
88
+
89
+ ## Backlog
90
+
91
+ | # | Status | Task | Mode | Acceptance | Plan |
92
+ |---|--------|------|------|------------|------|
93
+ | 1 | [ ] | task-a | inline | packaged helper reads target repo | (pending) |
94
+ | 2 | [ ] | task-b | inline | packaged helper reads target repo | (pending) |
95
+ | 3 | [ ] | task-c | inline | packaged helper reads target repo | (pending) |
96
+ | 4 | [ ] | task-d | inline | packaged helper reads target repo | (pending) |
97
+ | 5 | [ ] | task-e | inline | packaged helper reads target repo | (pending) |
98
+ SPRINT_EOF
99
+ printf '%s' 'plans/sprints/20991231-2359-tarball-root.sprint.md' > "$TARGET_REPO/.ai/harness/sprint/active-sprint"
100
+
101
+ (cd "$TARGET_REPO" && "$CLI" run sprint-backlog status) >"$TMP_DIR/sprint-status.txt"
102
+ if ! grep -qx 'sprint: plans/sprints/20991231-2359-tarball-root.sprint.md' "$TMP_DIR/sprint-status.txt" \
103
+ || ! grep -qx 'tasks_total: 5' "$TMP_DIR/sprint-status.txt"; then
104
+ echo "[tarball-smoke] ERROR: packaged sprint-backlog helper did not read the target repo sprint state" >&2
105
+ cat "$TMP_DIR/sprint-status.txt" >&2
106
+ exit 1
107
+ fi
108
+
82
109
  printf '{"prompt":"review release readiness"}\n' | "$HOOK" prompt-guard-decide >/dev/null
83
110
 
84
111
  FAKE_HOME="$TMP_DIR/home"
@@ -175,6 +175,15 @@ export function inspectRepo(repo: string): InspectionResult {
175
175
  if (hasAnyPath(repo, generatedClaudeHookPaths)) {
176
176
  driftSignals.push("stale-generated-claude-hook-shims");
177
177
  }
178
+ const rootClaudeFile = join(repo, "CLAUDE.md");
179
+ const rootAgentsFile = join(repo, "AGENTS.md");
180
+ if (
181
+ existsSync(rootClaudeFile) &&
182
+ existsSync(rootAgentsFile) &&
183
+ readFileSync(rootClaudeFile, "utf-8") !== readFileSync(rootAgentsFile, "utf-8")
184
+ ) {
185
+ driftSignals.push("root-agent-context-divergent");
186
+ }
178
187
 
179
188
  if (driftSignals.includes("missing-runtime-contract-manifest")) {
180
189
  requiredDecisions.push("Install runtime workflow contract manifest");
@@ -200,6 +209,9 @@ export function inspectRepo(repo: string): InspectionResult {
200
209
  if (driftSignals.includes("stale-generated-claude-hook-shims")) {
201
210
  requiredDecisions.push("Remove manifest-owned generated .claude/hooks shims and keep .ai/hooks as source of truth");
202
211
  }
212
+ if (driftSignals.includes("root-agent-context-divergent")) {
213
+ requiredDecisions.push("Root CLAUDE.md and AGENTS.md have diverged; reconcile by hand — repo-harness never overwrites user-authored root files.");
214
+ }
203
215
 
204
216
  const upgradeSignals = new Set(driftSignals);
205
217
  if (hasCustomClaudeHooks(repo)) {
@@ -2160,19 +2160,44 @@ pi_root_context_content() {
2160
2160
  cat <<'EOF_ROOT_CONTEXT'
2161
2161
  # Repo Agent Context
2162
2162
 
2163
- This is the root routing contract for Claude Code and Codex.
2163
+ This is the root routing contract for Claude Code and Codex. Keep it short:
2164
+ load this first, then follow the repo-owned artifacts it names.
2164
2165
 
2165
2166
  ## Root Workflow Contract
2166
2167
 
2167
2168
  - Keep sibling `CLAUDE.md` and `AGENTS.md` files aligned. Claude Code consumes `CLAUDE.md`; Codex consumes `AGENTS.md`.
2169
+ - Prefer repo-local workflow artifacts over tool-specific chat memory.
2168
2170
  - Treat `docs/spec.md` as stable product truth, `tasks/current.md` as a derived status snapshot, and `tasks/todos.md` as the deferred-goal ledger; current execution stays in the active plan's `## Task Breakdown`.
2169
- - Treat `docs/researches/`, `tasks/lessons.md`, and `.ai/harness/policy.json` as durable workflow context.
2170
- - Use `.ai/context/context-map.json` and `.ai/context/capabilities.json` to discover functional-block contracts.
2171
+ - Treat `docs/researches/`, `tasks/lessons.md`, `tasks/notes/`, `.ai/harness/policy.json`, and `.ai/harness/handoff/current.md` as durable workflow context.
2172
+ - Use `.ai/context/context-map.json` and `.ai/context/capabilities.json` to discover functional-block contracts before adding local agent files.
2171
2173
  - Do not infer local `CLAUDE.md` or `AGENTS.md` files from broad physical layouts such as `apps/*`, `packages/*`, or `services/*`.
2172
2174
  - Put capability-specific ownership, entrypoints, and verification commands in explicitly selected functional-block contracts.
2173
2175
  - Keep root context concise; route deep implementation detail into plans, task notes, research, workstreams, or architecture docs.
2174
2176
  - Treat `_ref/` as ignored external reference material and `_ops/` as ignored local operations state.
2175
- - Prefer repo-local workflow artifacts over tool-specific chat memory.
2177
+
2178
+ ## Agent Context Scaffolding
2179
+
2180
+ - Before creating or changing agent context files, inspect existing high-context files, repo manifests, CI workflows, Makefiles, generated outputs, generators, and high-risk directories.
2181
+ - Treat scanners as leads, not authority. Verify commands, ownership, and generated-file boundaries against actual repo files before writing instructions.
2182
+ - Choose the smallest instruction stack that changes behavior: root context for repo-wide routing, scoped context only where local rules differ, and no nested file for ordinary implementation directories.
2183
+ - Preserve existing high-context files unless the user explicitly approved a rewrite; add pointers or scoped complements instead of normalizing names.
2184
+ - Pair every prohibition with the concrete alternative: source of truth, helper, generator, command, or verification surface.
2185
+
2186
+ ## Decision Protocol
2187
+
2188
+ - For non-trivial engineering work, complete P1/P2/P3 before design decisions or code edits: P1 map the real system boundary, P2 trace one concrete data/control path, and P3 state the design rationale and invariant being preserved.
2189
+ - For planning requests, produce one decision-complete recommendation with scope, non-scope, tradeoffs, tests, rollback/failure handling, and the most fragile assumption; do not implement until the user approves.
2190
+ - If the user says `implement this plan`, first check for obvious repo drift, then execute the approved plan without re-litigating the direction.
2191
+ - For bug hunts, trace the failing path and name the root cause before changing code.
2192
+ - For bundles of requests, classify items before accepting scope; do not treat every item as automatic implementation work.
2193
+ - Do not add fallback, compatibility, or "best effort" product code that re-derives an authority's semantics (LLM/provider/external/user-input) with local rules, regexes, or shadow parsers; fail closed with a clear error unless the current task or a human-approved migration/release contract explicitly requires that path.
2194
+
2195
+ ## Execution And Verification
2196
+
2197
+ - Prefer existing repo patterns, scripts, and standard-library/platform features before adding dependencies, files, or abstractions.
2198
+ - Preserve user-authored files; do not overwrite existing `CLAUDE.md` or `AGENTS.md` except when explicitly applying an approved scaffold or syncing the controlled architecture block.
2199
+ - After substantive changes, run focused checks for the touched area plus `bash scripts/check-task-sync.sh` and `bash scripts/check-task-workflow.sh --strict` when those scripts exist.
2200
+ - Report what changed, why it was the smallest coherent change, verification evidence, and any concrete residual risk.
2176
2201
  EOF_ROOT_CONTEXT
2177
2202
  }
2178
2203
 
@@ -2,7 +2,22 @@
2
2
  set -euo pipefail
3
3
 
4
4
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
- if REPO_ROOT="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null)"; then
5
+ if [[ -n "${REPO_HARNESS_TARGET_REPO_ROOT:-}" ]]; then
6
+ if [[ "$REPO_HARNESS_TARGET_REPO_ROOT" != /* ]]; then
7
+ echo "sprint-backlog: REPO_HARNESS_TARGET_REPO_ROOT must be an absolute path" >&2
8
+ exit 2
9
+ fi
10
+ if ! REPO_ROOT="$(cd "$REPO_HARNESS_TARGET_REPO_ROOT" 2>/dev/null && pwd -P)"; then
11
+ echo "sprint-backlog: REPO_HARNESS_TARGET_REPO_ROOT does not resolve to a directory" >&2
12
+ exit 2
13
+ fi
14
+ CURRENT_ROOT="$(pwd -P)"
15
+ if [[ "$REPO_ROOT" != "$CURRENT_ROOT" ]]; then
16
+ echo "sprint-backlog: REPO_HARNESS_TARGET_REPO_ROOT must match the current helper cwd" >&2
17
+ exit 2
18
+ fi
19
+ cd "$REPO_ROOT"
20
+ elif REPO_ROOT="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null)"; then
6
21
  cd "$REPO_ROOT"
7
22
  else
8
23
  cd "$SCRIPT_DIR/.."
@@ -83,6 +83,47 @@ validate_block() {
83
83
  [[ -e "$block" ]]
84
84
  }
85
85
 
86
+ helper_sibling() {
87
+ local helper_name="$1"
88
+ local helper_dir=""
89
+ if [[ -n "${REPO_HARNESS_HELPER_SOURCE_PATH:-}" ]]; then
90
+ helper_dir="$(dirname "$REPO_HARNESS_HELPER_SOURCE_PATH")"
91
+ fi
92
+ if [[ -n "$helper_dir" && -f "$helper_dir/$helper_name" ]]; then
93
+ printf '%s\n' "$helper_dir/$helper_name"
94
+ return 0
95
+ fi
96
+ return 1
97
+ }
98
+
99
+ capability_resolver() {
100
+ local sibling=""
101
+ if command -v bun >/dev/null 2>&1 && [[ -f "scripts/capability-resolver.ts" ]]; then
102
+ bun scripts/capability-resolver.ts "$@"
103
+ return $?
104
+ fi
105
+ sibling="$(helper_sibling capability-resolver.ts || true)"
106
+ if command -v bun >/dev/null 2>&1 && [[ -n "$sibling" ]]; then
107
+ bun "$sibling" "$@"
108
+ return $?
109
+ fi
110
+ return 127
111
+ }
112
+
113
+ context_contract_sync() {
114
+ local sibling=""
115
+ if [[ -x "scripts/context-contract-sync.sh" ]]; then
116
+ bash "scripts/context-contract-sync.sh" "$@"
117
+ return $?
118
+ fi
119
+ sibling="$(helper_sibling context-contract-sync.sh || true)"
120
+ if [[ -n "$sibling" ]]; then
121
+ bash "$sibling" "$@"
122
+ return $?
123
+ fi
124
+ return 127
125
+ }
126
+
86
127
  while [[ $# -gt 0 ]]; do
87
128
  case "$1" in
88
129
  --block)
@@ -139,12 +180,12 @@ if ! validate_block "$functional_block"; then
139
180
  exit 2
140
181
  fi
141
182
 
142
- if [[ ! -f "scripts/capability-resolver.ts" ]] || ! command -v bun >/dev/null 2>&1; then
143
- echo "workstream-sync: scripts/capability-resolver.ts and bun are required" >&2
183
+ if ! command -v bun >/dev/null 2>&1 || ! capability_resolver list --format json >/dev/null 2>&1; then
184
+ echo "workstream-sync: capability-resolver.ts and bun are required" >&2
144
185
  exit 2
145
186
  fi
146
187
 
147
- if ! resolver_json="$(bun scripts/capability-resolver.ts match --path "$functional_block" --format json 2>&1)"; then
188
+ if ! resolver_json="$(capability_resolver match --path "$functional_block" --format json 2>&1)"; then
148
189
  echo "$resolver_json" >&2
149
190
  exit 1
150
191
  fi
@@ -257,8 +298,6 @@ fi
257
298
  event_json="{\"ts\":\"$(json_escape "$iso_timestamp")\",\"file_path\":\"$(json_escape "$workstream_file")\",\"severity\":\"medium\",\"functional_block\":\"$(json_escape "$functional_block")\",\"capability_id\":\"$(json_escape "$capability_id")\",\"matched_prefix\":\"$(json_escape "$matched_prefix")\",\"architecture_domain\":\"$(json_escape "$architecture_domain")\",\"architecture_capability\":\"$(json_escape "$architecture_capability")\",\"architecture_module\":\"$(json_escape "$architecture_module")\",\"workstream_dir\":\"$(json_escape "$workstream_dir")\",\"contract_agents\":\"$(json_escape "$contract_agents")\",\"contract_claude\":\"$(json_escape "$contract_claude")\",\"active_workstream\":\"$(json_escape "$workstream_file")\",\"change_type\":\"workstream-sync\",\"spawn_recommended\":false,\"contract_sync_required\":true,\"request_file\":\"$(json_escape "$request_file")\"}"
258
299
  printf '%s\n' "$event_json" >> "$event_file"
259
300
 
260
- if [[ -f "$helper_dir/context-contract-sync.sh" ]]; then
261
- bash "$helper_dir/context-contract-sync.sh" sync-event --json "$event_json"
262
- fi
301
+ context_contract_sync sync-event --json "$event_json" >/dev/null 2>&1 || true
263
302
 
264
303
  echo "[WorkstreamSync] Ensured $workstream_file for $capability_id."
@@ -129,6 +129,34 @@ function packageVersion(sourceRoot: string): string | null {
129
129
  }
130
130
  }
131
131
 
132
+ function packageName(sourceRoot: string): string | null {
133
+ try {
134
+ const pkg = JSON.parse(readFileSync(join(sourceRoot, "package.json"), "utf-8"));
135
+ return typeof pkg.name === "string" ? pkg.name : null;
136
+ } catch (_error) {
137
+ return null;
138
+ }
139
+ }
140
+
141
+ function isBunDependencyLoop(step: GlobalRuntimeStep): boolean {
142
+ return /DependencyLoop|dependency loop/i.test(`${step.stdout ?? ""}\n${step.stderr ?? ""}`);
143
+ }
144
+
145
+ function parsePackedTarballFilename(stdout: string): string | null {
146
+ try {
147
+ const parsed = JSON.parse(stdout);
148
+ const entry = Array.isArray(parsed) ? parsed[0] : parsed;
149
+ return typeof entry?.filename === "string" ? entry.filename : null;
150
+ } catch (_error) {
151
+ return null;
152
+ }
153
+ }
154
+
155
+ function appendOutput(...values: Array<string | undefined>): string | undefined {
156
+ const output = values.filter((value) => value && value.trim()).join("\n");
157
+ return output || undefined;
158
+ }
159
+
132
160
  function bunGlobalPackageRoot(env?: NodeJS.ProcessEnv): string | null {
133
161
  const bunInstall = env?.BUN_INSTALL ?? process.env.BUN_INSTALL;
134
162
  const home = env?.HOME ?? process.env.HOME ?? process.env.USERPROFILE;
@@ -149,6 +177,7 @@ function isBunGlobalPackageSource(sourceRoot: string, env?: NodeJS.ProcessEnv):
149
177
 
150
178
  function installCli(sourceRoot: string, cwd: string, env?: NodeJS.ProcessEnv, installSpec?: string): GlobalRuntimeStep {
151
179
  const version = packageVersion(sourceRoot);
180
+ const name = packageName(sourceRoot);
152
181
  if (installSpec === undefined && isBunGlobalPackageSource(sourceRoot, env)) {
153
182
  return {
154
183
  step: "install repo-harness CLI",
@@ -160,6 +189,9 @@ function installCli(sourceRoot: string, cwd: string, env?: NodeJS.ProcessEnv, in
160
189
  }
161
190
  const spec = installSpec ?? (existsSync(join(sourceRoot, "package.json")) ? sourceRoot : "repo-harness");
162
191
  const step = runProcess("bun", ["add", "-g", spec], cwd, env);
192
+ if (installSpec === undefined && name === "repo-harness" && step.status === "failed" && isBunDependencyLoop(step)) {
193
+ return installCliFromPackedTarball(sourceRoot, cwd, env, version, step);
194
+ }
163
195
  return withStepName(
164
196
  step,
165
197
  "install repo-harness CLI",
@@ -167,6 +199,55 @@ function installCli(sourceRoot: string, cwd: string, env?: NodeJS.ProcessEnv, in
167
199
  );
168
200
  }
169
201
 
202
+ function installCliFromPackedTarball(
203
+ sourceRoot: string,
204
+ cwd: string,
205
+ env: NodeJS.ProcessEnv | undefined,
206
+ version: string | null,
207
+ dependencyLoopStep: GlobalRuntimeStep,
208
+ ): GlobalRuntimeStep {
209
+ const packDir = join(homeDir(env), ".repo-harness", "packages");
210
+ const detailPrefix = version ? `version=${version}; ` : "";
211
+ mkdirSync(packDir, { recursive: true });
212
+
213
+ const pack = runProcess("npm", ["pack", "--json", "--pack-destination", packDir], sourceRoot, env);
214
+ if (pack.status !== "ok") {
215
+ return withStepName(
216
+ {
217
+ ...pack,
218
+ stderr: appendOutput(dependencyLoopStep.stderr, pack.stderr),
219
+ },
220
+ "install repo-harness CLI",
221
+ `${detailPrefix}dependency-loop repair pack failed`,
222
+ );
223
+ }
224
+ const filename = parsePackedTarballFilename(pack.stdout ?? "");
225
+ if (filename === null) {
226
+ return {
227
+ step: "install repo-harness CLI",
228
+ status: "failed",
229
+ command: pack.command,
230
+ detail: `${detailPrefix}dependency-loop repair pack output invalid`,
231
+ stdout: dependencyLoopStep.stdout,
232
+ stderr: appendOutput(dependencyLoopStep.stderr, pack.stderr, "npm pack --json did not return a tarball filename"),
233
+ };
234
+ }
235
+ const remove = runProcess("bun", ["remove", "-g", "repo-harness"], cwd, env);
236
+ if (remove.status !== "ok") {
237
+ return withStepName(
238
+ {
239
+ ...remove,
240
+ stdout: appendOutput(dependencyLoopStep.stdout, remove.stdout),
241
+ stderr: appendOutput(dependencyLoopStep.stderr, pack.stderr, remove.stderr),
242
+ },
243
+ "install repo-harness CLI",
244
+ `${detailPrefix}dependency-loop repair remove failed`,
245
+ );
246
+ }
247
+ const add = runProcess("bun", ["add", "-g", join(packDir, filename)], cwd, env);
248
+ return withStepName(add, "install repo-harness CLI", `${detailPrefix}repaired=packed-tarball`);
249
+ }
250
+
170
251
  function syncRuntimeSkill(sourceRoot: string, env?: NodeJS.ProcessEnv): GlobalRuntimeStep {
171
252
  const script = join(sourceRoot, "scripts", "sync-codex-installed-copies.sh");
172
253
  if (!existsSync(script)) {
@@ -40,6 +40,8 @@ const WAZA_SHARED_RULES = ["anti-patterns.md", "chinese.md", "durable-context.md
40
40
  const GBRAIN_INSTALL_ARGS = ["install", "-g", "github:garrytan/gbrain"] as const;
41
41
  const GLOBAL_RULES_BEGIN = "<!-- BEGIN: repo-harness global-working-rules -->";
42
42
  const GLOBAL_RULES_END = "<!-- END: repo-harness global-working-rules -->";
43
+ const GLOBAL_RULES_SELF_NOTE =
44
+ "<!-- repo-harness manages this block; edits inside are overwritten on sync. Keep personal rules outside the markers. -->";
43
45
 
44
46
  export type InitBrainMode = "manifest-only" | "install-gbrain-cli" | "skip";
45
47
  export type ReportingLanguagePreset = "follow" | "zh-CN" | "en" | "custom";
@@ -234,16 +236,42 @@ function renderGlobalRules(sourceRoot: string, instruction: string): string {
234
236
  /^- Use the user's language for reports; keep technical terms in English\.$/m,
235
237
  `- ${instruction}`,
236
238
  );
237
- return `${GLOBAL_RULES_BEGIN}\n${rendered.trim()}\n${GLOBAL_RULES_END}\n`;
239
+ return `${GLOBAL_RULES_BEGIN}\n${GLOBAL_RULES_SELF_NOTE}\n${rendered.trim()}\n${GLOBAL_RULES_END}\n`;
238
240
  }
239
241
 
240
- function mergeManagedBlock(current: string, block: string): string {
241
- const start = current.indexOf(GLOBAL_RULES_BEGIN);
242
- const end = current.indexOf(GLOBAL_RULES_END);
243
- if (start >= 0 && end >= start) {
242
+ type ManagedBlockStatus = "written" | "blocked-unbalanced" | "skipped-legacy";
243
+
244
+ interface MergedManagedBlock {
245
+ content: string;
246
+ status: ManagedBlockStatus;
247
+ }
248
+
249
+ function countOccurrences(haystack: string, needle: string): number {
250
+ let count = 0;
251
+ let index = haystack.indexOf(needle);
252
+ while (index !== -1) {
253
+ count += 1;
254
+ index = haystack.indexOf(needle, index + needle.length);
255
+ }
256
+ return count;
257
+ }
258
+
259
+ function mergeManagedBlock(current: string, block: string): MergedManagedBlock {
260
+ const beginCount = countOccurrences(current, GLOBAL_RULES_BEGIN);
261
+ const endCount = countOccurrences(current, GLOBAL_RULES_END);
262
+
263
+ if (beginCount > 0 || endCount > 0) {
264
+ const start = current.indexOf(GLOBAL_RULES_BEGIN);
265
+ const end = current.indexOf(GLOBAL_RULES_END);
266
+ const balanced = beginCount === 1 && endCount === 1 && start >= 0 && end >= start;
267
+ if (!balanced) {
268
+ return { content: current, status: "blocked-unbalanced" };
269
+ }
244
270
  const afterEnd = end + GLOBAL_RULES_END.length;
245
- return `${current.slice(0, start)}${block.trimEnd()}${current.slice(afterEnd).replace(/^\n?/, "\n")}`;
271
+ const merged = `${current.slice(0, start)}${block.trimEnd()}${current.slice(afterEnd).replace(/^\n?/, "\n")}`;
272
+ return { content: merged, status: "written" };
246
273
  }
274
+
247
275
  if (
248
276
  /^# Global Working Rules\s*$/m.test(current) ||
249
277
  (
@@ -253,10 +281,10 @@ function mergeManagedBlock(current: string, block: string): string {
253
281
  current.includes("### P3: Design Decision")
254
282
  )
255
283
  ) {
256
- return current;
284
+ return { content: current, status: "skipped-legacy" };
257
285
  }
258
286
  const trimmed = current.trimEnd();
259
- return `${trimmed}${trimmed ? "\n\n" : ""}${block}`;
287
+ return { content: `${trimmed}${trimmed ? "\n\n" : ""}${block}`, status: "written" };
260
288
  }
261
289
 
262
290
  export function writeGlobalContextFiles(
@@ -276,19 +304,29 @@ export function writeGlobalContextFiles(
276
304
  if (target === "claude" || target === "both") targets.push(join(home, ".claude", "CLAUDE.md"));
277
305
 
278
306
  const changes: string[] = [];
307
+ let blocked = false;
279
308
  for (const filePath of targets) {
280
309
  mkdirSync(dirname(filePath), { recursive: true });
281
310
  const current = existsSync(filePath) ? readFileSync(filePath, "utf-8") : "";
282
- const next = mergeManagedBlock(current, block);
283
- if (next === current) {
311
+ const merged = mergeManagedBlock(current, block);
312
+ if (merged.status === "blocked-unbalanced") {
313
+ blocked = true;
314
+ changes.push(`blocked:${filePath} (unbalanced repo-harness markers; repair manually, then re-run)`);
315
+ continue;
316
+ }
317
+ if (merged.status === "skipped-legacy") {
318
+ changes.push(`skipped-legacy:${filePath} (unmanaged Global Working Rules present; add the repo-harness markers to enable managed sync)`);
319
+ continue;
320
+ }
321
+ if (merged.content === current) {
284
322
  changes.push(`unchanged:${filePath}`);
285
323
  continue;
286
324
  }
287
- writeFileSync(filePath, next, "utf-8");
325
+ writeFileSync(filePath, merged.content, "utf-8");
288
326
  changes.push(`${current ? "updated" : "created"}:${filePath}`);
289
327
  }
290
328
 
291
- return { step: "global working rules", status: "ok", detail: changes.join(", ") };
329
+ return { step: "global working rules", status: blocked ? "failed" : "ok", detail: changes.join(", ") };
292
330
  }
293
331
 
294
332
  /**
@@ -14,6 +14,7 @@ const SESSION_CONTEXT = [
14
14
  '3. Prefer the smallest direct implementation over new wrappers or extension points.',
15
15
  '4. Delete or shrink obsolete code before adding layers.',
16
16
  '5. Preserve explicit requirements, security, validation, data safety, error handling, accessibility, and runnable tests.',
17
+ '6. No compatibility fallbacks in product code: do not re-derive an LLM/provider/authority-owned value with local rules or regexes; if the authoritative value is missing or malformed, fail closed with a clear error instead of synthesizing a replacement.',
17
18
  'Before completion, justify each new dependency, file, and abstraction.',
18
19
  ].join('\n');
19
20
 
@@ -1,13 +0,0 @@
1
- # Functional Block Agent Context
2
-
3
- Keep this file focused on the local contract for this primary functional block.
4
-
5
- ## Local Context Contract
6
-
7
- - Describe only the ownership, boundaries, stable entrypoints, and local verification commands for this functional block.
8
- - Keep sibling `CLAUDE.md` and `AGENTS.md` files aligned. Claude Code consumes `CLAUDE.md`; Codex consumes `AGENTS.md`.
9
- - Record the local LSP/tooling profile here when it differs from the repo default.
10
- - Route deep implementation detail into nearby docs instead of inflating root agent context files.
11
- - Treat `.ai/context/context-map.json` as the index of discoverable context files.
12
- - Do not keep pushing context files deeper by default; add lower-level files only for a separately owned functional block with its own commands and invariants.
13
- - Prefer repo-local workflow artifacts over tool-specific chat memory.
@@ -1,13 +0,0 @@
1
- # Functional Block Agent Context
2
-
3
- Keep this file focused on the local contract for this primary functional block.
4
-
5
- ## Local Context Contract
6
-
7
- - Describe only the ownership, boundaries, stable entrypoints, and local verification commands for this functional block.
8
- - Keep sibling `CLAUDE.md` and `AGENTS.md` files aligned. Claude Code consumes `CLAUDE.md`; Codex consumes `AGENTS.md`.
9
- - Record the local LSP/tooling profile here when it differs from the repo default.
10
- - Route deep implementation detail into nearby docs instead of inflating root agent context files.
11
- - Treat `.ai/context/context-map.json` as the index of discoverable context files.
12
- - Do not keep pushing context files deeper by default; add lower-level files only for a separately owned functional block with its own commands and invariants.
13
- - Prefer repo-local workflow artifacts over tool-specific chat memory.