Skip to content

Commit e2e8016

Browse files
authored
Merge pull request #23 from ericpassmore/product-idea
Add product-idea refinement skills
2 parents b99c5f0 + ca27d15 commit e2e8016

5 files changed

Lines changed: 1178 additions & 0 deletions

File tree

codex/product-idea-principles.md

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
# Product Refinement Constitution
2+
3+
*(Applies only in Product-Idea Refinement Mode)*
4+
5+
---
6+
7+
## 1. Baseline First
8+
9+
Refinement MUST begin with a documented baseline containing:
10+
11+
* Clear problem statement (actor + pain/opportunity)
12+
* Quantifiable success outcome
13+
* Explicit non-goals
14+
15+
No refinement may proceed without this baseline.
16+
17+
Objectives remain stable unless explicitly re-baselined.
18+
19+
---
20+
21+
## 2. Reduce Ambiguity Scope Every Iteration
22+
23+
Ambiguity must be tracked quantitatively across all phases.
24+
25+
### Ambiguity Record Format
26+
27+
Each ambiguity must include:
28+
29+
* Category:
30+
* Domain
31+
* Technology
32+
* Regulatory
33+
* Integration
34+
* Data model
35+
* Testability
36+
* Scope Impact (1-5)
37+
* Systemic Risk (1-5)
38+
* Regulatory Risk (1-5)
39+
* Breadth of Surface (1-5)
40+
41+
### Ambiguity Score
42+
43+
Ambiguity Score = Scope x max(Systemic, Regulatory) x Breadth
44+
45+
The goal is not fewer ambiguities.
46+
The goal is:
47+
48+
* Reduce total weighted ambiguity score
49+
* OR replace one high-score ambiguity with multiple low-score, bounded ambiguities
50+
51+
Each iteration must satisfy one of those conditions.
52+
If not, the iteration is invalid and must:
53+
54+
* force a decision,
55+
* convert uncertainty into an explicit assumption,
56+
* or declare BLOCKED.
57+
58+
Refinement without weighted ambiguity reduction or bounded decomposition is drift.
59+
60+
---
61+
62+
## 3. Positive Drift Only
63+
64+
Model evolution is permitted only if it:
65+
66+
* increases clarity,
67+
* improves feasibility,
68+
* strengthens testability,
69+
* reduces risk,
70+
* or better satisfies the quantified success outcome.
71+
72+
Refinement may reshape the solution.
73+
It may not silently reshape the objective.
74+
75+
After each iteration, audit alignment to the original baseline.
76+
77+
---
78+
79+
## 4. Assumptions Are Fluid; Objectives Are Stable
80+
81+
Assumptions are expected to change and must be explicitly logged.
82+
83+
Objectives may change only through explicit re-baselining with:
84+
85+
* documented rationale,
86+
* updated success metric,
87+
* and acknowledgment of prior objective retirement.
88+
89+
Silent objective drift is prohibited.
90+
91+
---
92+
93+
## 5. Resolve Tension Explicitly
94+
95+
When objectives or constraints are in tension:
96+
97+
* the conflict must be documented,
98+
* prioritization must be declared,
99+
* and the chosen tradeoff must be justified.
100+
101+
Unresolved tension is misalignment.
102+
103+
### Principle: Structured Objective Tension Resolution
104+
105+
Objective tension must be resolved through explicit, comparable, and traceable analysis:
106+
107+
* each objective defines a measurable desired outcome,
108+
* objective-to-capability relationships are explicit before tradeoff decisions,
109+
* cross-purpose tensions are identified using a consistent comparison method,
110+
* and non-negotiable objectives remain preserved across selected tradeoff paths.
111+
112+
---
113+
114+
## 6. Durable Documentation Is Mandatory
115+
116+
No reasoning may remain transient.
117+
118+
After each refinement session:
119+
120+
* Log changes.
121+
* Log broken assumptions.
122+
* Log decisions and alternatives considered.
123+
* Re-state baseline and confirm alignment.
124+
125+
If the alignment audit fails, refinement must pause.
126+
127+
---
128+
129+
# Why This Is Consistent With Your Execution Doctrine
130+
131+
Execution Mode enforces:
132+
133+
* Lock goals before action
134+
* Minimal change
135+
* Drift hard gates
136+
* Verification before done
137+
138+
Refinement Mode enforces:
139+
140+
* Baseline stability
141+
* Ambiguity reduction
142+
* Positive drift discipline
143+
* Assumption hygiene
144+
* Explicit tradeoffs
145+
* Persistent state
146+
147+
Execution optimizes implementation.
148+
Refinement optimizes problem clarity.
149+
150+
They do not conflict. They govern different phases.
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
IDEA_NAME="${1:-}"
5+
EXPECTED_FINGERPRINT="${2:-}"
6+
NOW_UTC="${3:-}"
7+
8+
ROOT_DIR="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
9+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
10+
IDEA_DIR="${ROOT_DIR}/project-ideas/${IDEA_NAME}"
11+
REG_DIR="${IDEA_DIR}/regulatory"
12+
13+
MANIFEST_FILE="${REG_DIR}/regulatory-manifest.md"
14+
SURFACE_FILE="${REG_DIR}/02-regulatory-surface.md"
15+
EVAL_FILE="${REG_DIR}/02b-regulatory-evaluation.md"
16+
SOURCES_FILE="${REG_DIR}/regulatory-sources.md"
17+
IMPLICATIONS_FILE="${REG_DIR}/regulatory-capability-implications.md"
18+
EXCEPTION_FILE="${REG_DIR}/regulatory-exception.md"
19+
DECISION_LOG_FILE="${IDEA_DIR}/decision-log.md"
20+
21+
usage() {
22+
echo "Usage (canonical): ./.codex/scripts/product-idea-regulatory-intake-validate.sh <idea-name> [expected-input-fingerprint] [current-utc]"
23+
echo "Usage (repo-local fallback): ./codex/scripts/product-idea-regulatory-intake-validate.sh <idea-name> [expected-input-fingerprint] [current-utc]"
24+
echo "Usage (home fallback): ${HOME}/.codex/scripts/product-idea-regulatory-intake-validate.sh <idea-name> [expected-input-fingerprint] [current-utc]"
25+
}
26+
27+
now_utc_default() {
28+
date -u +"%Y-%m-%dT%H:%M:%SZ"
29+
}
30+
31+
is_rfc3339_utc() {
32+
[[ "${1}" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$ ]]
33+
}
34+
35+
extract_field() {
36+
local file="$1"
37+
local key="$2"
38+
awk -v key="${key}" '
39+
BEGIN { key_l = tolower(key) }
40+
{
41+
line = $0
42+
gsub(/^[[:space:]]*[-*][[:space:]]*/, "", line)
43+
sub(/^[[:space:]]+/, "", line)
44+
line_l = tolower(line)
45+
if (line_l ~ ("^" key_l ":[[:space:]]*")) {
46+
sub(/^[^:]+:[[:space:]]*/, "", line)
47+
print line
48+
exit
49+
}
50+
}
51+
' "${file}"
52+
}
53+
54+
get_manifest_field() {
55+
local value
56+
for key in "$@"; do
57+
value="$(extract_field "${MANIFEST_FILE}" "${key}")"
58+
if [[ -n "${value}" ]]; then
59+
printf '%s' "${value}"
60+
return
61+
fi
62+
done
63+
}
64+
65+
issues=()
66+
67+
if [[ -z "${IDEA_NAME}" ]]; then
68+
usage
69+
exit 2
70+
fi
71+
72+
if [[ ! "${IDEA_NAME}" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]]; then
73+
echo "ERROR: idea-name must be kebab-case using lowercase letters, digits, and hyphens only." >&2
74+
exit 2
75+
fi
76+
77+
if [[ -z "${NOW_UTC}" ]]; then
78+
NOW_UTC="$(now_utc_default)"
79+
fi
80+
81+
if ! is_rfc3339_utc "${NOW_UTC}"; then
82+
echo "ERROR: current-utc must be RFC 3339 UTC format (YYYY-MM-DDTHH:MM:SSZ)." >&2
83+
exit 2
84+
fi
85+
86+
if [[ ! -d "${REG_DIR}" ]]; then
87+
issues+=("Missing required directory: ${REG_DIR}")
88+
fi
89+
90+
if [[ ! -f "${MANIFEST_FILE}" ]]; then
91+
issues+=("Missing required file: ${MANIFEST_FILE}")
92+
fi
93+
94+
if [[ ! -f "${SURFACE_FILE}" ]]; then
95+
issues+=("Missing required file: ${SURFACE_FILE}")
96+
fi
97+
98+
if [[ ! -f "${SOURCES_FILE}" ]]; then
99+
issues+=("Missing required file: ${SOURCES_FILE}")
100+
fi
101+
102+
if [[ ! -f "${IMPLICATIONS_FILE}" ]]; then
103+
issues+=("Missing required file: ${IMPLICATIONS_FILE}")
104+
fi
105+
106+
status=""
107+
generated_at=""
108+
expires_at=""
109+
input_fingerprint=""
110+
111+
if [[ -f "${MANIFEST_FILE}" ]]; then
112+
status="$(get_manifest_field "status")"
113+
generated_at="$(get_manifest_field "generated_at" "generated at")"
114+
expires_at="$(get_manifest_field "expires_at" "expires at")"
115+
input_fingerprint="$(get_manifest_field "input_fingerprint" "input fingerprint")"
116+
117+
case "${status}" in
118+
SURFACE_FOUND|NO_SURFACE|EXCEPTION_APPROVED|INCONCLUSIVE) ;;
119+
*)
120+
issues+=("Invalid or missing manifest status in ${MANIFEST_FILE}. Expected SURFACE_FOUND|NO_SURFACE|EXCEPTION_APPROVED|INCONCLUSIVE.")
121+
;;
122+
esac
123+
124+
if [[ "${status}" == "INCONCLUSIVE" ]]; then
125+
issues+=("Manifest status is INCONCLUSIVE; regulatory intake cannot progress without EXCEPTION_APPROVED.")
126+
fi
127+
128+
if [[ "${status}" == "SURFACE_FOUND" && ! -f "${EVAL_FILE}" ]]; then
129+
issues+=("Missing required file for SURFACE_FOUND status: ${EVAL_FILE}")
130+
fi
131+
132+
if [[ -z "${generated_at}" ]]; then
133+
issues+=("Missing manifest field: generated_at")
134+
elif ! is_rfc3339_utc "${generated_at}"; then
135+
issues+=("Invalid generated_at format in ${MANIFEST_FILE}; expected RFC 3339 UTC.")
136+
fi
137+
138+
if [[ -z "${expires_at}" ]]; then
139+
issues+=("Missing manifest field: expires_at")
140+
elif ! is_rfc3339_utc "${expires_at}"; then
141+
issues+=("Invalid expires_at format in ${MANIFEST_FILE}; expected RFC 3339 UTC.")
142+
elif [[ "${NOW_UTC}" > "${expires_at}" || "${NOW_UTC}" == "${expires_at}" ]]; then
143+
issues+=("Manifest is stale: current time (${NOW_UTC}) is at/after expires_at (${expires_at}).")
144+
fi
145+
146+
if [[ -z "${input_fingerprint}" ]]; then
147+
issues+=("Missing manifest field: input_fingerprint")
148+
fi
149+
fi
150+
151+
if [[ -z "${EXPECTED_FINGERPRINT}" ]]; then
152+
if [[ -x "${SCRIPT_DIR}/product-idea-scope-fingerprint.sh" ]]; then
153+
if ! EXPECTED_FINGERPRINT="$("${SCRIPT_DIR}/product-idea-scope-fingerprint.sh" "${IDEA_NAME}" 2>/dev/null)"; then
154+
issues+=("Unable to derive expected input fingerprint from project baseline/surface files.")
155+
fi
156+
else
157+
issues+=("Missing fingerprint helper script: ${SCRIPT_DIR}/product-idea-scope-fingerprint.sh")
158+
fi
159+
fi
160+
161+
if [[ -n "${EXPECTED_FINGERPRINT}" && -n "${input_fingerprint}" && "${input_fingerprint}" != "${EXPECTED_FINGERPRINT}" ]]; then
162+
issues+=("Manifest fingerprint mismatch: manifest=${input_fingerprint}, expected=${EXPECTED_FINGERPRINT}.")
163+
fi
164+
165+
if [[ "${status}" == "EXCEPTION_APPROVED" ]]; then
166+
if [[ ! -f "${EXCEPTION_FILE}" ]]; then
167+
issues+=("Missing required exception file for EXCEPTION_APPROVED status: ${EXCEPTION_FILE}")
168+
else
169+
for field in "rationale" "scope" "owner" "expiry date" "accepted risks" "mitigation plan"; do
170+
if [[ -z "$(extract_field "${EXCEPTION_FILE}" "${field}")" ]]; then
171+
issues+=("Missing required exception field '${field}' in ${EXCEPTION_FILE}.")
172+
fi
173+
done
174+
fi
175+
176+
if [[ ! -f "${DECISION_LOG_FILE}" ]]; then
177+
issues+=("Missing decision log required for exception risk flag: ${DECISION_LOG_FILE}")
178+
elif ! grep -Eqi 'risk flag|regulatory-exception|exception approved' "${DECISION_LOG_FILE}"; then
179+
issues+=("Decision log must record explicit risk flag for exception usage: ${DECISION_LOG_FILE}")
180+
fi
181+
fi
182+
183+
if [[ "${#issues[@]}" -gt 0 ]]; then
184+
echo "BLOCKED"
185+
for issue in "${issues[@]}"; do
186+
echo "- ${issue}"
187+
done
188+
exit 1
189+
fi
190+
191+
echo "REGULATORY INTAKE PASSED"
192+
echo "- status: ${status}"
193+
echo "- fingerprint: ${input_fingerprint}"
194+
echo "- expires_at: ${expires_at}"
195+
exit 0

0 commit comments

Comments
 (0)