feat(plan-01): Phase 4c — hard cutoff, remove .specify compat facade

Repoint every remaining literal `.specify/...` / `docs/input` reference to the real
package/domain location and delete all compat symlinks. The harness now runs purely via
packages/casan-harness/... with no .specify facade; .specify holds ONLY runtime state
(logs/, agentops/alerts.log, level5/central-governance).

Refs fixed (Phase 0.5 only caught `$VAR/.specify/` — these were bare/`__file__`/literal):
- secrets-scan.sh: scan-target excludes -> packages/casan-harness/... (+ apps/okr/domain/corpus)
- loop_common.py: loop-policy.yaml -> harness config (package-relative)
- evidence-pack-build.py: judge-gate test + traceability-matrix.py -> harness/sibling
- phase10-traceability: REQ -> $CASAN_DOMAIN_ROOT/input
- run-casan-pipeline.mjs: model-fallback/drift-detect/rollback-manager -> HARNESS_BASH,
  golden -> GOLDEN_PLAN (apps/okr/domain), with .specify/logs state kept
- casan-step.mjs: requirement fallback restored to docs/input for hermetic sandboxes
- descriptive config (tool-registry/harness-package/drift-policy/hallucination/risk-registry/
  loop-policy.schema + docstrings) repointed for accuracy
- policy-bundle.yaml: 8 policy paths -> packages/casan-harness/...; manifest regenerated +
  re-signed (POLICY_HASHES_VALID files=8, POLICY_SIGNATURE_VALID)

Removed 22 .specify code/config symlinks + docs/input symlink.
Full gate via packages path, NO facade: PASS=64 FAIL=0 SKIP=3.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
thanhnv
2026-07-08 12:28:37 +09:00
co-authored by Claude Opus 4.8
parent e891981b59
commit 7101af9fd4
38 changed files with 48 additions and 60 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
// CASAN shared log helper (Node side).
// Taxonomy (shared with .specify/scripts/bash/casan-log.sh):
// Taxonomy (shared with packages/casan-harness/scripts/bash/casan-log.sh):
// error(0) < warn(1) < info(2) < debug(3) < trace(4), default info.
// All lines go to stderr so stdout stays reserved for existing outputs.
+1 -1
View File
@@ -252,7 +252,7 @@ switch (step) {
extraInstructions: 'Create an SRS with purpose, scope, functional requirements, non-functional requirements, and traceable FR IDs.',
});
write(srsPath, generated.content);
report(`docs/output/output_logs/${featureId}/reports/01-srs-report.md`, '# STEP 1: SRS Generation Report', `Generated ${srsPath} from docs/input/okr-requirement.md. source=${generated.source} note=${generated.note}.`, 'APPROVED', [srsPath]);
report(`docs/output/output_logs/${featureId}/reports/01-srs-report.md`, '# STEP 1: SRS Generation Report', `Generated ${srsPath} from apps/okr/domain/input/okr-requirement.md. source=${generated.source} note=${generated.note}.`, 'APPROVED', [srsPath]);
break;
}
case '02-bd': {
@@ -10,10 +10,15 @@ const dryRun = process.argv.includes('--dry-run');
const featureId = '001-okr-web-app';
const root = process.cwd();
// Plan-01: harness relocated to packages/casan-harness/; fall back to the .specify facade.
const HARNESS = existsSync(join(root, 'packages/casan-harness/scripts/bash/casan-harness.sh'))
? 'packages/casan-harness/scripts/bash/casan-harness.sh'
: '.specify/scripts/bash/casan-harness.sh';
// Plan-01: harness relocated to packages/casan-harness/, domain to apps/okr/domain/;
// fall back to the pre-move paths so this runner works from either layout.
const HARNESS_BASH = existsSync(join(root, 'packages/casan-harness/scripts/bash'))
? 'packages/casan-harness/scripts/bash'
: '.specify/scripts/bash';
const HARNESS = `${HARNESS_BASH}/casan-harness.sh`;
const GOLDEN_PLAN = existsSync(join(root, 'apps/okr/domain/golden-runs/okr-plan.golden.txt'))
? 'apps/okr/domain/golden-runs/okr-plan.golden.txt'
: '.specify/level5/golden-runs/okr-plan.golden.txt';
const logDir = `docs/output/output_logs/${featureId}`;
const casanDir = `${logDir}/casan`;
const reportsDir = `${logDir}/reports`;
@@ -340,7 +345,7 @@ runHarness({ id: '07-plan-attempt-2', agent: 'speckit.plan', step: '05-plan', at
const fallbackOut = `${casanDir}/model-fallback-output.txt`;
log('debug', 'boss', `model-fallback invoked (real primary failure) → ${fallbackOut}`);
execFileSync(
'.specify/scripts/bash/model-fallback.sh',
`/model-fallback.sh`,
[
fallbackOut,
// Real primary failure: reading a nonexistent path exits non-zero (not a
@@ -361,8 +366,8 @@ appendBoss(`Model fallback invoked; output ${fallbackOut}`);
const driftCandidate = `${casanDir}/drift-plan-candidate.txt`;
copyFileSync(fallbackOut, driftCandidate);
log('debug', 'boss', 'drift-detect: fallback output vs golden baseline');
execFileSync('.specify/scripts/bash/drift-detect.sh', [
'.specify/level5/golden-runs/okr-plan.golden.txt',
execFileSync(`/drift-detect.sh`, [
GOLDEN_PLAN,
driftCandidate,
'.specify/logs/level5/okr-plan-drift-report.json',
], { cwd: root, stdio: 'inherit' });
@@ -390,7 +395,7 @@ copyFileSync(rollbackTarget, rollbackBackup);
writeFileSync(`${rollbackDir}/rollback-before.txt`, readFileSync(rollbackTarget, 'utf8'), 'utf8');
writeFileSync(rollbackTarget, 'changed content that must be undone\n', 'utf8');
writeFileSync(`${rollbackDir}/rollback-changed.txt`, readFileSync(rollbackTarget, 'utf8'), 'utf8');
const record = execFileSync('.specify/scripts/bash/rollback-manager.sh', [
const record = execFileSync(`/rollback-manager.sh`, [
'record',
'restore rollback target evidence file',
`cp ${rollbackBackup} ${rollbackTarget}`,
@@ -400,7 +405,7 @@ const tx = record.match(/transaction_id=([^\s]+)/)?.[1];
if (!tx) {
throw new Error('rollback transaction id not found');
}
const execute = execFileSync('.specify/scripts/bash/rollback-manager.sh', ['execute', tx], {
const execute = execFileSync(`/rollback-manager.sh`, ['execute', tx], {
cwd: root,
encoding: 'utf8',
});