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:
co-authored by
Claude Opus 4.8
parent
e891981b59
commit
7101af9fd4
@@ -1 +0,0 @@
|
||||
../../packages/casan-harness/agentops/alerts.yaml
|
||||
@@ -1 +0,0 @@
|
||||
../../packages/casan-harness/agentops/hallucination-tracking.yaml
|
||||
@@ -1 +0,0 @@
|
||||
../../packages/casan-harness/agentops/metrics.yaml
|
||||
@@ -1 +0,0 @@
|
||||
../../packages/casan-harness/agentops/rate-limits.yaml
|
||||
@@ -1 +0,0 @@
|
||||
../../packages/casan-harness/agentops/tracking.yaml
|
||||
@@ -1 +0,0 @@
|
||||
../packages/casan-harness/config
|
||||
@@ -1 +0,0 @@
|
||||
../packages/casan-harness/governance
|
||||
@@ -1 +0,0 @@
|
||||
../packages/casan-harness/init-options.json
|
||||
@@ -1 +0,0 @@
|
||||
../../packages/casan-harness/level5/drift-policy.yaml
|
||||
@@ -1 +0,0 @@
|
||||
../../apps/okr/domain/golden-runs
|
||||
@@ -1 +0,0 @@
|
||||
../../packages/casan-harness/level5/harness-package.json
|
||||
@@ -1 +0,0 @@
|
||||
../../packages/casan-harness/level5/kpi-schema.yaml
|
||||
@@ -1 +0,0 @@
|
||||
../../packages/casan-harness/level5/model-fallback.yaml
|
||||
@@ -1 +0,0 @@
|
||||
../../packages/casan-harness/level5/project-registry.json
|
||||
@@ -1 +0,0 @@
|
||||
../../packages/casan-harness/level5/provider-usage-sample.json
|
||||
@@ -1 +0,0 @@
|
||||
../../packages/casan-harness/level5/tool-registry.yaml
|
||||
@@ -1 +0,0 @@
|
||||
../packages/casan-harness/memory
|
||||
@@ -1 +0,0 @@
|
||||
../packages/casan-harness/scripts
|
||||
@@ -1 +0,0 @@
|
||||
../packages/casan-harness/security
|
||||
@@ -1 +0,0 @@
|
||||
../packages/casan-harness/templates
|
||||
@@ -1 +0,0 @@
|
||||
../packages/casan-harness/tests
|
||||
@@ -1 +0,0 @@
|
||||
../apps/okr/domain/traceability-map.json
|
||||
@@ -1 +0,0 @@
|
||||
../apps/okr/domain/input
|
||||
@@ -10,7 +10,7 @@ tracking:
|
||||
steps_with_tracking:
|
||||
- step: step-1-srs
|
||||
reference_docs:
|
||||
- docs/input/okr-requirement.md
|
||||
- apps/okr/domain/input/okr-requirement.md
|
||||
signals:
|
||||
- ungrounded_feature_claim
|
||||
- invented_requirement
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://casan.fpt/loop-policy.schema.json",
|
||||
"title": "CASAN Loop Budget Governor policy",
|
||||
"description": "Schema for .specify/config/loop-policy.yaml (Plan-17 Track 1). Budgets are non-negative numbers; on_exceed is halt|escalate. Absence of a rule means the strictest built-in ceiling applies (deny-by-default).",
|
||||
"description": "Schema for packages/casan-harness/config/loop-policy.yaml (Plan-17 Track 1). Budgets are non-negative numbers; on_exceed is halt|escalate. Absence of a rule means the strictest built-in ceiling applies (deny-by-default).",
|
||||
"type": "object",
|
||||
"required": ["version", "profiles"],
|
||||
"additionalProperties": false,
|
||||
|
||||
@@ -83,7 +83,7 @@ reporting:
|
||||
|
||||
enabled: true
|
||||
frequency: daily
|
||||
output: ".specify/governance/risk-report.md"
|
||||
output: "packages/casan-harness/governance/risk-report.md"
|
||||
|
||||
review:
|
||||
|
||||
@@ -93,6 +93,6 @@ review:
|
||||
auto_update:
|
||||
enabled: true
|
||||
trigger: new_action_type_detected
|
||||
script: .specify/scripts/powershell/update-risk-registry.ps1
|
||||
script: packages/casan-harness/scripts/powershell/update-risk-registry.ps1
|
||||
default_risk_for_unknown_action: high
|
||||
note: "Unknown actions default to high-risk (fail-secure). Run update-risk-registry.ps1 to register."
|
||||
@@ -1,7 +1,7 @@
|
||||
version: 1.0
|
||||
description: CASAN Level 5 drift detection policy
|
||||
|
||||
golden_dir: .specify/level5/golden-runs
|
||||
golden_dir: apps/okr/domain/golden-runs
|
||||
evidence_dir: docs/output/casan/level5-evidence
|
||||
|
||||
thresholds:
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
"python": ">=3.9"
|
||||
},
|
||||
"entrypoints": {
|
||||
"wrapper": ".specify/scripts/bash/casan-harness.sh",
|
||||
"test": ".specify/tests/run-casan4-harness-tests.sh",
|
||||
"wrapper": "packages/casan-harness/scripts/bash/casan-harness.sh",
|
||||
"test": "packages/casan-harness/tests/run-casan4-harness-tests.sh",
|
||||
"dashboard": "docs/output/casan/agentops-dashboard.html"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ tools:
|
||||
allowed_agents: "boss,implement-agent"
|
||||
rollback:
|
||||
strategy: git_patch_reverse
|
||||
script: .specify/scripts/bash/rollback-manager.sh
|
||||
script: packages/casan-harness/scripts/bash/rollback-manager.sh
|
||||
|
||||
- id: migration
|
||||
owner: database-owner
|
||||
@@ -29,7 +29,7 @@ tools:
|
||||
allowed_agents: "boss,implement-agent"
|
||||
rollback:
|
||||
strategy: migration_down_or_restore
|
||||
script: .specify/scripts/bash/rollback-manager.sh
|
||||
script: packages/casan-harness/scripts/bash/rollback-manager.sh
|
||||
|
||||
- id: deploy
|
||||
owner: release-manager
|
||||
@@ -41,7 +41,7 @@ tools:
|
||||
allowed_agents: "boss,release-manager"
|
||||
rollback:
|
||||
strategy: previous_release
|
||||
script: .specify/scripts/bash/rollback-manager.sh
|
||||
script: packages/casan-harness/scripts/bash/rollback-manager.sh
|
||||
|
||||
- id: external_api
|
||||
owner: platform-team
|
||||
@@ -52,7 +52,7 @@ tools:
|
||||
allowed_agents: "boss,implement-agent"
|
||||
rollback:
|
||||
strategy: compensating_request
|
||||
script: .specify/scripts/bash/rollback-manager.sh
|
||||
script: packages/casan-harness/scripts/bash/rollback-manager.sh
|
||||
|
||||
- id: db_write
|
||||
owner: database-owner
|
||||
@@ -63,7 +63,7 @@ tools:
|
||||
allowed_agents: "boss,implement-agent"
|
||||
rollback:
|
||||
strategy: restore_from_backup
|
||||
script: .specify/scripts/powershell/rollback-manager.ps1
|
||||
script: packages/casan-harness/scripts/powershell/rollback-manager.ps1
|
||||
|
||||
- id: write_file
|
||||
owner: engineering
|
||||
@@ -74,7 +74,7 @@ tools:
|
||||
allowed_agents: "boss,implement-agent,design-agent"
|
||||
rollback:
|
||||
strategy: delete_or_restore
|
||||
script: .specify/scripts/bash/rollback-manager.sh
|
||||
script: packages/casan-harness/scripts/bash/rollback-manager.sh
|
||||
|
||||
level5_gate:
|
||||
required_fields:
|
||||
|
||||
@@ -21,6 +21,9 @@ import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
# Plan-01: this script lives at <harness>/scripts/bash/; the harness root is two levels up.
|
||||
_HARNESS = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", ".."))
|
||||
|
||||
|
||||
def read_jsonl(path):
|
||||
rows = []
|
||||
@@ -73,11 +76,11 @@ def main():
|
||||
# H3 eval scorecard (best effort — reference known evidence)
|
||||
reports["h3-eval-scorecard.json"] = {
|
||||
"harness": "H3-eval", "run_id": run_id,
|
||||
"judge_gate_tests": os.path.exists(os.path.join(root, ".specify/tests/phase3-judge-gate-tests.sh")),
|
||||
"judge_gate_tests": os.path.exists(os.path.join(_HARNESS, "tests/phase3-judge-gate-tests.sh")),
|
||||
"note": "judge-gate fail-before/fix cycle proven by phase3-judge-gate-tests.sh",
|
||||
}
|
||||
traceability_out = os.path.join(pack_dir, "traceability-matrix.json")
|
||||
traceability_script = os.path.join(root, ".specify/scripts/bash/traceability-matrix.py")
|
||||
traceability_script = os.path.join(os.path.dirname(os.path.abspath(__file__)), "traceability-matrix.py")
|
||||
traceability_rc = 1
|
||||
if os.path.isfile(traceability_script):
|
||||
traceability_rc = subprocess.run(
|
||||
|
||||
@@ -136,7 +136,9 @@ def policy_path() -> str:
|
||||
explicit = os.environ.get("CASAN_LOOP_POLICY_FILE")
|
||||
if explicit:
|
||||
return explicit
|
||||
return os.path.join(project_root(), ".specify/config/loop-policy.yaml")
|
||||
# Plan-01: loop-policy.yaml is harness config, not app state — resolve it inside the
|
||||
# package (this file lives at <harness>/scripts/bash/), independent of any .specify facade.
|
||||
return os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "config", "loop-policy.yaml"))
|
||||
|
||||
|
||||
def load_policy():
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
"""CASAN H4 PII masker driven by .specify/security/pii-rules.yaml.
|
||||
"""CASAN H4 PII masker driven by packages/casan-harness/security/pii-rules.yaml.
|
||||
|
||||
Reads content on stdin, applies every `action: mask` rule from the rules
|
||||
file, and writes the masked content to stdout. Type-specific replacement
|
||||
|
||||
@@ -39,14 +39,15 @@ fi
|
||||
# Exclude known test-fixture files and evidence directories that intentionally
|
||||
# contain the pattern as test data.
|
||||
FIXTURE_EXCLUDES=(
|
||||
".specify/tests/"
|
||||
"packages/casan-harness/tests/"
|
||||
"docs/output/casan/evidence/"
|
||||
".specify/security/"
|
||||
".specify/scripts/bash/security-check.sh"
|
||||
".specify/scripts/bash/verify-audit-chain.sh"
|
||||
".specify/scripts/bash/verify-tool-audit.sh"
|
||||
".specify/scripts/bash/tool-audit-lib.sh"
|
||||
".specify/scripts/bash/governance-check.sh"
|
||||
"packages/casan-harness/security/"
|
||||
"apps/okr/domain/corpus/"
|
||||
"packages/casan-harness/scripts/bash/security-check.sh"
|
||||
"packages/casan-harness/scripts/bash/verify-audit-chain.sh"
|
||||
"packages/casan-harness/scripts/bash/verify-tool-audit.sh"
|
||||
"packages/casan-harness/scripts/bash/tool-audit-lib.sh"
|
||||
"packages/casan-harness/scripts/bash/governance-check.sh"
|
||||
)
|
||||
build_exclude_args() {
|
||||
for ex in "${FIXTURE_EXCLUDES[@]}"; do printf -- "--exclude-dir=%s " "$ex"; done
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
"""CASAN Plan-10 traceability matrix generator/gate.
|
||||
|
||||
Parses FR-* requirements from docs/input/okr-requirement.md and checks each
|
||||
Parses FR-* requirements from apps/okr/domain/input/okr-requirement.md and checks each
|
||||
requirement has at least one existing code file and one existing test file.
|
||||
"""
|
||||
import argparse
|
||||
|
||||
@@ -17,7 +17,7 @@ PASS=0; FAIL=0
|
||||
pass() { echo "PASS: $1"; PASS=$((PASS + 1)); }
|
||||
fail() { echo "FAIL: $1"; FAIL=$((FAIL + 1)); }
|
||||
|
||||
REQ="$PROJECT_ROOT/docs/input/okr-requirement.md"
|
||||
REQ="$CASAN_DOMAIN_ROOT/input/okr-requirement.md"
|
||||
MAP="$CASAN_DOMAIN_ROOT/traceability-map.json"
|
||||
OUT="$WORK/traceability-matrix.json"
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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',
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user