[ALT-10963] Change check_profile , opening project view.#39
[ALT-10963] Change check_profile , opening project view.#39KirillovProj wants to merge 6 commits into
check_profile , opening project view.#39Conversation
check_profile from server with an empty string.check_profile , opening project view.
meanmail
left a comment
There was a problem hiding this comment.
Review summary
The PR has grown well beyond its original one-line scope. The original empty-string-overwrite fix from commit 3766a0d was lost in subsequent commits, so the very bug this PR was created for is no longer prevented. There are also several leftover debug logs, unused imports, scope creep (UI URL change, project view refactor, soft-fail YAML loading, Retrofit body logging, two large docs files), and a few smaller correctness/style issues. Details inline.
Blocking
StudentTaskChangeApplierstill overwrites a non-emptycheckProfilewith an empty value when the deserialized item carries"". ThenewCheckProfile.isNotEmpty()guard from3766a0dwas dropped ine44e4073. Please restore it and add a regression test covering exactly this scenario.
Strongly recommended before merge
- Strip the
[DEBUG_LOG]-prefixed and per-call info logs (model setter, every YAML save, everyapplyChanges, every Retrofit request body, every deserialization). At minimum downgrade them todebug—LOG.infohere will produce a lot of noise on real courses and the Retrofit body log can leak auth-bearing payloads. - Drop unused imports in
YamlLoader.kt(EduOAuthCodeFlowConnector,HTTP_BAD_REQUEST,HTTP_FORBIDDEN,HTTP_UNAUTHORIZED). - Consider splitting the unrelated changes (course-view refactor, UTM-link change, soft-fail in
YamlDeepLoader, Retrofit body logging, the two new docs files) into separate PRs — they are not part of ALT-10963 and make review harder.
Smaller things
isHyperskillTopicsLesson()matchessection.presentableName == "Topics"— fragile; reuseHyperskillCourse.getTopicsSection()and compare by reference.HyperskillSubmitConnectoruser-facing error string is hardcoded English instead ofEduCoreBundle.HyperskillSubmissionFactory.createEduTaskSubmissionnow explicitly assignsreply.checkProfile = "".EduTaskhas no check profile concept — please confirm the server expects this field on plain edu submissions; otherwise drop the assignment.RemoteEduTaskYamlMixin.ktis missing a final newline; two blank lines beforeprivate val LOGinRemoteEduTask.kt.
| val newCheckProfile = deserializedItem.checkProfile | ||
| if (newCheckProfile != existingItem.checkProfile) { | ||
| LOG.info("Updating checkProfile for task ${existingItem.name}: '${existingItem.checkProfile}' -> '$newCheckProfile'") | ||
| existingItem.checkProfile = newCheckProfile |
There was a problem hiding this comment.
Blocking — the original bug is back.
The original fix in commit 3766a0d was if (newCheckProfile.isNotEmpty()) existingItem.checkProfile = newCheckProfile. Commit e44e4073 replaced that with a plain inequality check, so now if the deserialized YAML carries check_profile: '' while the in-memory task has a real profile (e.g. "hyperskill_go"), this line still overwrites the existing value with an empty string — the exact scenario ALT-10963 is supposed to prevent. The LOG.warn("checkProfile is empty … after applying changes") below is essentially logging the bug rather than preventing it.
Suggested fix: bring back the guard, e.g.
if (newCheckProfile.isNotEmpty() && newCheckProfile != existingItem.checkProfile) {
existingItem.checkProfile = newCheckProfile
}and add a regression test that loads YAML with an empty check_profile over a RemoteEduTask whose checkProfile was already set.
| override fun applyChanges(existingItem: Task, deserializedItem: Task) { | ||
| LOG.info("Applying changes for task: ${existingItem.name} (id=${existingItem.id})") | ||
| LOG.info("Existing item checkProfile: ${(existingItem as? RemoteEduTask)?.checkProfile}") | ||
| LOG.info("Deserialized item checkProfile: ${(deserializedItem as? RemoteEduTask)?.checkProfile}") |
There was a problem hiding this comment.
Three LOG.info lines per applyChanges call will be very noisy on real courses (this runs for every YAML change event). Please downgrade to debug or drop them — the same information is already logged on the setter and on save.
| existingItem.checkProfile = newCheckProfile | ||
| } | ||
| if (existingItem.checkProfile.isEmpty()) { | ||
| LOG.warn("checkProfile is empty for RemoteEduTask ${existingItem.name} after applying changes") |
There was a problem hiding this comment.
Once the empty-overwrite guard from line 35 is restored, this warning becomes unreachable / misleading. Either remove it, or replace it with a hard failure (throw YamlLoadingException(...)) so we don't silently keep a task in a broken state.
| var checkProfile: String = "" | ||
| set(value) { | ||
| if (field != value) { | ||
| LOG.info("[DEBUG_LOG] RemoteEduTask.checkProfile set to '$value' (was '$field')") |
There was a problem hiding this comment.
Putting a logging side-effect on a domain-model property setter (and with a [DEBUG_LOG] prefix) reads like leftover debugging instrumentation. If we need to trace when checkProfile changes, do it at the call sites (loader / change applier) rather than the model, and at debug level.
| */ | ||
| // see EDU-4504 Support Go edu problems | ||
|
|
||
|
|
There was a problem hiding this comment.
Nit: two consecutive blank lines between the type-level comment and private val LOG.
| if (task.checkProfile.isEmpty()) { | ||
| val message = "Check profile is empty for task ${task.name}. Submission aborted to avoid server error." | ||
| LOG.error(message) | ||
| return Err(message + " Please try to 'Synchronize project' or contact support.") |
There was a problem hiding this comment.
User-facing string is hardcoded in English here. Other error strings in this file go through EduCoreBundle.message(...) — please follow the same convention so the message stays translatable.
| } | ||
|
|
||
| fun submitRemoteEduTask(task: RemoteEduTask, files: List<SolutionFile>): Result<StepikBasedSubmission, String> { | ||
| LOG.info("Submitting RemoteEduTask: ${task.name} (id=${task.id}), checkProfile='${task.checkProfile}'") |
There was a problem hiding this comment.
Logging every submission at info is fine for now, but please consider whether debug would be enough — every check action will land here.
| reply.score = if (task.status == CheckStatus.Solved) "1" else "0" | ||
| reply.solution = files | ||
| reply.feedback = Feedback(feedback) | ||
| reply.checkProfile = "" |
There was a problem hiding this comment.
createEduTaskSubmission is for plain EduTask, which has no notion of checkProfile. Forcing reply.checkProfile = "" here sends an empty check_profile to the server for every regular edu submission — please confirm the server tolerates it; otherwise drop the assignment. If it is needed only to satisfy some serialization contract, a comment explaining why would help.
| if (newRequest.body != null) { | ||
| val buffer = Buffer() | ||
| runCatching { newRequest.body!!.writeTo(buffer) } | ||
| .onSuccess { LOG.info("Retrofit request body for ${newRequest.method} ${newRequest.url}: ${buffer.readUtf8()}") } |
There was a problem hiding this comment.
Logging the full request body at info for every Retrofit call is risky: it will (a) flood idea.log and (b) potentially log payloads that include tokens/PII (this interceptor runs after the auth interceptors). At minimum downgrade to debug and gate by a system property; ideally remove before merge.
| @set:JsonProperty(CHECK_PROFILE) | ||
| @get:JsonInclude(JsonInclude.Include.ALWAYS) | ||
| var checkProfile: String = "" | ||
| } No newline at end of file |
There was a problem hiding this comment.
Nit: file is missing a final newline.
Summary
check_profilefor remote tasks during YAML serialization/deserialization and student task updates, so server data is not overwritten with an empty valueTask.getDir()cannot resolve the task directorycheck_profileis empty and add logging around load/apply/save/submit flows to make these failures diagnosableDetails
RemoteEduTaskand explicitly serializecheck_profilecheck_profilefrom generic additional-property serialization to avoid duplicate/conflicting YAML outputcheck_profileonly for remote tasks and log mismatchesRemoteYamlLoadingExceptiongetDir()lookupTesting