refactor: simplify onboarding cache contracts
This commit is contained in:
@@ -263,3 +263,31 @@ Staged follow-up audit ran `git diff --cached --check`, `--name-status`, and `--
|
||||
passed, and the staged set contained exactly nine follow-up paths: this report, the production
|
||||
route adapter, handler, payload boundary, route fake/test, policy test, candidate test, and root CI
|
||||
contract. Unrelated `.superpowers/sdd/task-1-report.md` and `.omo/` remained unstaged.
|
||||
|
||||
## Review cleanup: behavioral authority
|
||||
|
||||
The post-review cleanup removes implementation-text assertions from the root Python contract and
|
||||
leaves stateful TypeScript route tests as the authority for cache claim and completion behavior.
|
||||
Broad UI, authentication, migration, and structured suggestion-marker coverage remains in the
|
||||
Python contract; exact natural-language prompt prose is no longer pinned there.
|
||||
|
||||
The one-use `createOnboardingCompletionTransition` wrapper and its tautological unit test were
|
||||
removed. The handler now passes `identity.pendingVersion` and `identity.readyVersion` directly to
|
||||
the repository completion command. This is a refactor only, so the existing route integration
|
||||
matrix provided the behavior-preservation check rather than adding a new RED case.
|
||||
|
||||
### Cleanup verification
|
||||
|
||||
- Focused route, policy, and candidate-completion tests: exit 0; 30 passed, 0 failed.
|
||||
- Full frontend suite: exit 0; 454 passed, 0 failed.
|
||||
- Python agent-chat contract: exit 0; 2 passed.
|
||||
- Changed-file ESLint and Ruff: exit 0 with zero diagnostics.
|
||||
- Webpack production build: exit 0; compiled successfully, TypeScript completed, and 22/22 pages
|
||||
generated.
|
||||
- `git diff --check`: exit 0.
|
||||
- Pure LOC: cache policy 70, onboarding handler 182, policy test 154, and root contract 69; every
|
||||
modified code/test file remains below 200 pure LOC.
|
||||
|
||||
The build continues to use repository-standard CI placeholder Supabase values and webpack because
|
||||
the worktree's external dependency symlink is incompatible with default Turbopack. No new concern
|
||||
was introduced by this cleanup.
|
||||
|
||||
@@ -19,11 +19,6 @@ export type OnboardingCacheIdentity = {
|
||||
readonly pendingVersion: string;
|
||||
};
|
||||
|
||||
export type OnboardingCompletionTransition = {
|
||||
readonly expectedVersion: string;
|
||||
readonly readyVersion: string;
|
||||
};
|
||||
|
||||
type OnboardingCacheObservation<Payload> = {
|
||||
readonly identity: OnboardingCacheIdentity;
|
||||
readonly observedVersion: string | null;
|
||||
@@ -83,12 +78,3 @@ export function decideOnboardingCache<Payload>(
|
||||
pendingVersion: observation.identity.pendingVersion,
|
||||
};
|
||||
}
|
||||
|
||||
export function createOnboardingCompletionTransition(
|
||||
identity: OnboardingCacheIdentity,
|
||||
): OnboardingCompletionTransition {
|
||||
return {
|
||||
expectedVersion: identity.pendingVersion,
|
||||
readyVersion: identity.readyVersion,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {
|
||||
createOnboardingCacheIdentity,
|
||||
createOnboardingCompletionTransition,
|
||||
decideOnboardingCache,
|
||||
} from "./onboarding-cache-policy.ts";
|
||||
import {
|
||||
@@ -181,11 +180,10 @@ export function createOnboardingPost(dependencies: OnboardingPostDependencies):
|
||||
);
|
||||
}
|
||||
|
||||
const completion = createOnboardingCompletionTransition(identity);
|
||||
const completed = await session.repository.completeProfile({
|
||||
userId: session.userId,
|
||||
expectedPendingVersion: completion.expectedVersion,
|
||||
readyVersion: completion.readyVersion,
|
||||
expectedPendingVersion: identity.pendingVersion,
|
||||
readyVersion: identity.readyVersion,
|
||||
payload,
|
||||
generatedAt: dependencies.now().toISOString(),
|
||||
});
|
||||
|
||||
@@ -2,7 +2,6 @@ import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
import {
|
||||
createOnboardingCacheIdentity,
|
||||
createOnboardingCompletionTransition,
|
||||
decideOnboardingCache,
|
||||
ONBOARDING_CLAIM_TTL_MS,
|
||||
} from "../src/lib/onboarding-cache-policy.ts";
|
||||
@@ -64,22 +63,6 @@ test("changed profile cannot wait on the previous profile's active pending claim
|
||||
});
|
||||
});
|
||||
|
||||
test("stale profile completion loses ownership after the current profile claims", () => {
|
||||
// Given: B has replaced A's pending identity in the row.
|
||||
const identityA = createOnboardingCacheIdentity(profileA);
|
||||
const identityB = createOnboardingCacheIdentity({ ...profileA, cityCode: "310100" });
|
||||
const rowVersionAfterBClaims = identityB.pendingVersion;
|
||||
|
||||
// When: each completion prepares an exact compare-and-set transition.
|
||||
const completionA = createOnboardingCompletionTransition(identityA);
|
||||
const completionB = createOnboardingCompletionTransition(identityB);
|
||||
|
||||
// Then: A cannot match the row, while B can commit its own ready identity.
|
||||
assert.notEqual(rowVersionAfterBClaims, completionA.expectedVersion);
|
||||
assert.equal(rowVersionAfterBClaims, completionB.expectedVersion);
|
||||
assert.equal(completionB.readyVersion, identityB.readyVersion);
|
||||
});
|
||||
|
||||
test("current profile accepts only valid ready content and an active current pending claim", () => {
|
||||
// Given: one current profile identity and a valid cached payload.
|
||||
const identity = createOnboardingCacheIdentity(profileA);
|
||||
|
||||
@@ -5,10 +5,6 @@ PAGE = ROOT / "frontend" / "src" / "app" / "page.tsx"
|
||||
AGENT = ROOT / "frontend" / "src" / "mastra" / "index.ts"
|
||||
ONBOARDING_ROUTE = ROOT / "frontend" / "src" / "app" / "api" / "onboarding" / "route.ts"
|
||||
ONBOARDING_CLIENT = ROOT / "frontend" / "src" / "lib" / "onboarding-client.ts"
|
||||
ONBOARDING_POST = ROOT / "frontend" / "src" / "lib" / "onboarding-post.ts"
|
||||
ONBOARDING_CACHE_POLICY = (
|
||||
ROOT / "frontend" / "src" / "lib" / "onboarding-cache-policy.ts"
|
||||
)
|
||||
CONSULT_ROUTE = ROOT / "frontend" / "src" / "app" / "api" / "consult" / "route.ts"
|
||||
MODELS_ROUTE = ROOT / "frontend" / "src" / "app" / "api" / "models" / "route.ts"
|
||||
MODEL_SELECTION = ROOT / "frontend" / "src" / "lib" / "consultation-model-selection.ts"
|
||||
@@ -29,8 +25,6 @@ def test_onboarding_and_agent_suggestion_contract() -> None:
|
||||
agent = AGENT.read_text(encoding="utf-8")
|
||||
route = ONBOARDING_ROUTE.read_text(encoding="utf-8")
|
||||
onboarding_client = ONBOARDING_CLIENT.read_text(encoding="utf-8")
|
||||
onboarding_post = ONBOARDING_POST.read_text(encoding="utf-8")
|
||||
cache_policy = ONBOARDING_CACHE_POLICY.read_text(encoding="utf-8")
|
||||
consult_route = CONSULT_ROUTE.read_text(encoding="utf-8")
|
||||
migration = ONBOARDING_MIGRATION.read_text(encoding="utf-8")
|
||||
|
||||
@@ -54,32 +48,12 @@ def test_onboarding_and_agent_suggestion_contract() -> None:
|
||||
|
||||
assert "export function getOnboardingAgent" in agent
|
||||
assert "skills: [jyotishSkillPath]" in agent
|
||||
assert "This is onboarding, not a chart reading" in agent
|
||||
assert "<!--AYANAM_SUGGESTIONS:" in agent
|
||||
assert "grounded in the answer just given" in agent
|
||||
assert "Treat the server-provided current time as authoritative" in agent
|
||||
|
||||
assert "supabase.auth.getUser()" in route
|
||||
assert "function currentTimeContext(now = new Date())" in consult_route
|
||||
assert "currentTimeContext(requestTime)," in consult_route
|
||||
assert "中国标准时间(UTC+8)" in consult_route
|
||||
assert "export const POST = createOnboardingPost" in route
|
||||
assert 'claim.is("onboarding_version", null)' in route
|
||||
assert '.eq("onboarding_version", command.expectedVersion)' in route
|
||||
assert 'claim.is("onboarding_generated_at", null)' in route
|
||||
assert '.eq("onboarding_generated_at", command.expectedGeneratedAt)' in route
|
||||
assert (
|
||||
'.eq("onboarding_version", command.expectedPendingVersion)\n'
|
||||
' .select("id")\n'
|
||||
" .maybeSingle();"
|
||||
) in route
|
||||
assert "createOnboardingCacheIdentity" in onboarding_post
|
||||
assert "expectedGeneratedAt: profile.onboarding_generated_at" in onboarding_post
|
||||
assert "completed.data" in onboarding_post
|
||||
assert 'source: "cache"' in onboarding_post
|
||||
assert 'source: "pending"' in onboarding_post
|
||||
assert 'createHash("sha256")' in cache_policy
|
||||
assert "getOnboardingAgent(model).generate" in route
|
||||
assert "onboarding_payload" in migration
|
||||
assert "to service_role" in migration
|
||||
assert "to authenticated" not in migration
|
||||
|
||||
Reference in New Issue
Block a user