build(deps): bump the all-maven group across 1 directory with 7 updates - #71
Closed
dependabot[bot] wants to merge 1956 commits into
Closed
build(deps): bump the all-maven group across 1 directory with 7 updates#71dependabot[bot] wants to merge 1956 commits into
dependabot[bot] wants to merge 1956 commits into
Conversation
Record the decisions taken during the /grill-me interview on 2026-06-13: * Introduce SandboxExecutor port + LanguageProfile strategy (List<> injection + getLanguageId fail-fast) + Verdict enum + VerdictResolver pure reducer, replacing the switch(language) and stringly-typed VERDICT_PRIORITY map in JudgeWorkerProcessor. * Adapter matrix limited to DockerSandboxAdapter + InMemorySandboxAdapter; Remote/Firecracker/gVisor explicitly deferred (YAGNI). * Submission status migrated from string to enum + ALLOWED transitions map + CAS UPDATE WHERE status = expected; reject GoF State / Spring StateMachine as overkill. * submit() consistency handled via TransactionSynchronization.afterCommit enqueue + 5-min PENDING reaper worker; full Outbox table deferred to a future Contest-specific ADR. * Notification multi-channel via SubmissionCompletedEvent + a single NotificationOrchestratorListener that fans out to a List<NotificationChannel> (in-app / email / websocket), matching the existing AchievementTriggerService event style. * Lombok @builder on VOs with 8+ fields (SubmissionVO, SubmissionDetailVO, RunResultDTO). No Specification, no Vavr Try/Either, no ServiceLoader. Implementation will land as three serial worktrees (M1 sandbox, M2 queue, M3 notification). Status remains Proposed until /codex:adversarial-review sign-off.
Codex /codex:adversarial-review on e34e4ef returned verdict needs-attention with 5 findings (3 critical + 2 high). All 5 accepted — none worth reversing. The original ADR-001 mixed four orthogonal concerns (reliability, evolvability, concurrency correctness, contract clarity) and prescribed a 4-6 week rollout with no feature flags, dual-read, or rollback drill. Split into: * ADR-000 Meta + supersede record (preserves the grilling transcript, Codex findings F1-F5, and the permanent rejection list to prevent future re-proposal of the abbreviated-enum or afterCommit+reaper approaches) * ADR-001 Verdict / SubmissionStatus codec evolution. Keeps all 11 existing wire values, all 11 i18n keys; introduces severity()/Kind() methods on the enum and a three-layer Codec for in-memory / DB / i18n separation. Replaces stringly-typed VERDICT_PRIORITY map with EnumMap-driven VerdictResolver. Solves F1. * ADR-002 Sandbox port + LanguageProfile strategy (List<> injection + fail-fast on duplicate languageId) + Docker/InMemory adapter. Per-language compile-failure detection moves into LanguageProfile; common security args (network none, cap-drop, seccomp) stay in the executor. * ADR-003 Replaces afterCommit + 5-min PENDING reaper with an Outbox table (uniquely keyed on (submission_id, generation), DB CURRENT_TIMESTAMP). Adds generation + current_attempt_id + judging_lease_expires_at columns; CAS guards every write so stale workers cannot overwrite newer rejudge generations. JUDGING lease + heartbeat + reaper recovers crashed workers. Admin rejudge becomes a first-class transition rather than an ALLOWED-table hack. Solves F2 + F3. * ADR-004 NotificationIntent sealed sum-type replaces the generic envelope; each NotificationChannel carries explicit per- intent projection and supports() is enforced. Per-channel try/catch isolates failures. Channel-level preference left to a future ADR (UI migration prerequisite). Solves F4. * ADR-005 11 independently deployable milestones with feature flag, envelope versioning (v1+v2 dual-decode), expand-contract DB migrations, canary gates, rollback drill matrix, and contest-window deployment restrictions. Solves F5. * README Index, numbering rules, status lifecycle, evaluation gates. The original single ADR-001-hexagonal-sandbox.md is renamed to ADR-000-hexagonal-grilling-session.md and rewritten as the meta / supersede record (rename detection via git log -M).
…nal reaper, durable notif ledger, executable rollback Second Codex adversarial review on commit a11553a returned needs-attention with 5 findings (3 critical + 2 high) — F1-F5 from round 1 stayed solved, but 5 new implementation-detail defects surfaced. All 5 accepted; each ADR patched in place with a 'Round 2 Codex Revision' section pointing at the original ADR text and recording the fix. * ADR-003 §2.6 F6 fix: Redis adapter switches from destructive RList/RQueue poll to ack-based consumption (Redis Streams XREADGROUP + XACK by default, RBLPOPLPUSH processing-list pattern as fallback). JudgeQueue port gains ack/nack methods. Reaper extended to handle XPENDING idle entries via XCLAIM. F7 fix: lease recovery moved into a single @transactional SELECT FOR UPDATE SKIP LOCKED → UPDATE bump generation → INSERT outbox sequence. Admin rejudge made transactional too, no longer depending on the reaper to finish the job. F8 boundary: this ADR declares 'at most one active producer to Redis Streams at any moment'; ADR-005 carries the milestone sequencing fix. * ADR-004 §2.7 F9 fix: new notification_delivery_ledger table with UNIQUE(intent_id, channel_id) replaces the in-memory email dedup cache and the missing durable backing for the (intentId, channelId) idempotency claim. Dispatcher does INSERT-IGNORE claim before send; In-App channel keeps writing Notification table but defers idempotency to the ledger. Durable retry path (RequiresDurable intents) split to a future ADR-007. * ADR-005 §2.8 F8 fix: M3a rewritten as shadow-only (outbox row written but not enqueued, OutboxShadowComparator diffs against the legacy afterCommit producer's enqueue trace). M3c becomes the cutover where the outbox dispatcher takes over real enqueueing. Invariant: at most one active producer at any time. F10 fix: rollback re-specified as 'restart-level' via pm2 reload reading application.yml feature flags (< 5min end-to-end including health check), removing the false 'Nacos hot reload' claim. Real Nacos Config client integration deferred to a separate ADR-008. Canary gates unchanged. Round 1 findings F1-F5 remain solved by ADR-001/002/003/004/005; Round 2 findings F6-F10 addressed in this commit. ADR-001, ADR-002, ADR-000, and README untouched (no findings against them in either round).
…n acceptance
3 rounds of /codex:adversarial-review completed (14 findings total).
F1-F10 already resolved in prior commits (split + round-2 in-place
patches). Round 3 found 4 new high-severity issues but zero critical;
all 4 are implementation corner cases (Redis Streams PEL semantics,
shadow-outbox cutover watermark, prod-vs-dev rollback topology, ledger
retry state machine) that are better validated by PoC code + fault
injection than by another round of ADR re-reading.
Decision: stop doc-review, defer F11-F14 to milestone PR acceptance.
Each finding is mapped to its target milestone and recommended fix;
the relevant milestone PR must demonstrate the fix passes fault
injection before its parent ADR can move Proposed→Accepted.
README.md now carries:
* Open Findings table (F11-F14) with verification requirement and
recommended fix
* Complete F1-F14 history table showing which are resolved vs
deferred
* Status transition rule: ADR can only move Proposed→Accepted when
its target milestone PR is merged AND any deferred findings
against it are validated
Severity trend across rounds (critical / high):
Round 1: 3 / 2 — strategic errors
Round 2: 3 / 2 — implementation details
Round 3: 0 / 4 — corner cases
The signal is clear: top-level direction (Hexagonal + Outbox + Sealed
Intent + 11-milestone) has held up under 3 rounds; remaining risk is
in PoC-discoverable corner cases. Investing further token cost in
round 4 has diminishing returns.
…(ADR-001) Implements ADR-001 milestone M1a (per ADR-005 sequencing). * SubmissionStatus enum: adds severity() (0..8), kind() (IN_FLIGHT / TERMINAL_GOOD / TERMINAL_BAD / TERMINAL_INFRA), wireValue() (@jsonvalue), fromWire() (@JsonCreator, strict), and a new SANDBOX_ERROR constant covering the sandbox-infra failure verdict surfaced by SandboxServiceImpl. displayName, category, terminal, fromDbName are kept unchanged for backward compatibility — the wire contract (DB column + JSON payload) is the same 'Pending' / 'Wrong Answer' / etc. strings as before, just now durably labelled. * SubmissionStatusCodec: new utility class wrapping the strict / lenient decode + toWire encode operations so non-Jackson callers (MyBatis row mapping, queue payload conversion, ad-hoc String code comparisons) go through a single typed boundary instead of string-comparing wire values inline. * VerdictResolver (@component): pure-function reducer that turns a collection of per-case verdicts into the final submission verdict using severity ordering. Two entry points: - reduce(Collection<SubmissionStatus>) — strict, throws on in-flight cases (caller bug); - reduceWire(Collection<String>) — bridge for legacy callers still holding stringly-typed status fields; unknown wire values are mapped to SYSTEM_ERROR (preserves old VERDICT_PRIORITY map fallback behavior). * JudgeWorkerProcessor: deletes the stringly-typed VERDICT_PRIORITY Map; constructor-injects VerdictResolver; determineVerdict() delegates to reduceWire() and converts back to wire-string at the boundary so SubmissionService.updateSubmissionResult(...) keeps its String-typed signature (no cross-module API change). * Tests: - SubmissionStatusCodecTest (12 cases): round-trip every constant, null/unknown error paths, wire-string regression guards, severity monotonicity (Accepted < PE < WA < TLE < MLE/OLE < RE < CE < Sandbox < System). - VerdictResolverTest (17 cases, nested by entry point): empty, single, all-AC, worst-severity-wins, tied severity, null elements, in-flight throws, infra > bad ordering, unknown wire values, new 'Sandbox Error' decode. - JudgeWorkerProcessorTest: @mock → @SPY for VerdictResolver so existing 5 determineVerdict tests exercise the real reducer unchanged (mockito5-lombok-constructor-injection rule). - AdminSubmissionServiceImplTest.returnsElevenStatuses renamed to returnsOneEntryPerEnumConstant and uses SubmissionStatus.values().length so adding SANDBOX_ERROR no longer breaks the count assertion. Focused verification: 74/74 tests pass across the four touched test classes (SubmissionStatusCodecTest, VerdictResolverTest, JudgeWorkerProcessorTest, AdminSubmissionServiceImplTest). Pre-existing 8 failures + 2 errors in the full suite (AdminProblemListControllerTest, ContestPublicControllerTest) are ApplicationContext load failures unrelated to this change — verifiable by the touch surface: those controllers don't exercise SubmissionStatus / VerdictResolver / determineVerdict in any path. They are baseline flakes (Testcontainers / Spring profile) and out of M1a scope. Deferred findings F11-F14 (per docs/adr/README.md Open Findings) are NOT touched by M1a — they target ADR-003 (queue/outbox), ADR-004 (notification ledger), and ADR-005 (rollback topology). M1a is the zero-deferred-finding milestone, on purpose, to validate the ADR-001 shape end-to-end before harder milestones.
…solver (F15+F16) Codex round-4 adversarial review on commit bf65606 (M1a) returned needs-attention with 2 findings. Both accepted. * F15 [high]: CodeExecutionService still reduced cases with its own VERDICT_PRIORITY map, while JudgeWorkerProcessor recomputed them with VerdictResolver. The two paths could disagree on the same case set (e.g. {Wrong Answer, Presentation Error} became 'Presentation Error' on /run, 'Wrong Answer' on /submit). Fix: CodeExecutionService now constructor-injects VerdictResolver and delegates to reduceWire(); the legacy VERDICT_PRIORITY map and private determineVerdict() are deleted. /run and /submit now share a single source of truth for severity ordering. * F16 [medium]: reduceWire() silently mapped unknown wire values to SYSTEM_ERROR without diagnostics. Fix: it now decodes via the strict SubmissionStatusCodec.fromWire(), catches IllegalArgumentException, logs the raw offending value at WARN with a running counter, and still falls back to SYSTEM_ERROR so a single malformed case cannot crash the judge loop. The counter (AtomicLong) is exposed via unknownWireFallbackCount() for tests and future Micrometer wiring; deliberately no new dependency in M1a. * Tests: - CrossPathVerdictTest (8 cases): same case set → identical wire value on both paths; MLE > TLE; RE > WA > AC; Sandbox Error outranks Runtime Error; System Error outranks Sandbox Error; all-AC is AC (not the legacy 'Pending' fallback); unknown / null wire value counts toward unknownWireFallbackCount and falls back to SYSTEM_ERROR. Pins the F15 invariant. - CodeExecutionServiceTest: @mock → @SPY for VerdictResolver per project rule mockito5-lombok-constructor-injection, so existing 5 execute() tests now exercise the real reducer. - VerdictResolverTest: existing 17 cases unchanged (they pinned the pre-F16 behavior; F16 only added the counter, not the reduction semantics, so no rewrite needed). Focused verification: 87/87 tests pass across the six affected test classes (SubmissionStatusCodecTest 12 + VerdictResolverTest 17 + JudgeWorkerProcessorTest 30 + AdminSubmissionServiceImplTest 30 + CodeExecutionServiceTest 5 + CrossPathVerdictTest 8). 8 are new from this commit, the rest are inherited and all green. M1a is now round-4 clean. Remaining open findings (F11-F14) are unaffected — they target ADR-003/004/005, scheduled for M2a-M4b.
Contributor
Author
LabelsThe following labels could not be found: Please fix the above issues or remove invalid values from |
M1b closes the final loose end of ADR-001 milestone M1a:
a JUnit test that pins the invariant that every SubmissionStatus
enum constant has a translation key in BOTH frontends (console +
management) and BOTH locales (en-US + zh-CN). Any future enum
addition that misses i18n coverage breaks this test loudly with a
precise diff (which enum, which locale, which frontend), instead of
silently rendering as the raw Java identifier in the UI.
* SubmissionStatusI18nCoverageTest:
- Loads 4 .ts source files (console en/zh + management en/zh) by
walking up from user.dir (or honoring ULTICODE_ROOT env override);
skips with WARN log if repo root cannot be located so backend-
only checkouts don't fail.
- Sanity test asserts every SubmissionStatus has a unique enum name
(the round-trip target).
- Dynamic-test factory generates 48 cases (4 files x 12 statuses)
asserting each (file, status) pair has the right translation key.
- noMissingNorExtraKeys cross-checks the key-set sizes match enum
count in every file (catches both 'forgot to translate' AND
'added a key but removed the enum constant' regressions).
- Derives expected key per file: console files use lowerCamelCase
(WRONG_ANSWER -> wrongAnswer), management files use SCREAMING_SNAKE
verbatim. Two adjacent code-bases intentionally use different
i18n key styles; the test pins both.
- Regex key extractor: lowerCamelCase for console status block,
SCREAMING_SNAKE for management statusLabels block; brace-depth
tracker handles nested braces correctly.
- Empirically verified: all 12 enum constants already have i18n
keys in all 4 files (SANDBOX_ERROR was added in M1a and the
frontends had pre-emptively shipped the keys).
* Tooling note: javadoc-internal '*/' character sequences (e.g. the
glob-style path 'console/src/i18n/locales/*/submission.ts')
prematurely close the javadoc comment block. Workaround: spell out
the path without the glob in the comment, e.g.
'console/src/i18n/locales/<en-US or zh-CN>/submission.ts'.
Focused verification: 137/137 tests pass across seven test classes
(SubmissionStatusCodecTest 12 + VerdictResolverTest 17 +
JudgeWorkerProcessorTest 30 + AdminSubmissionServiceImplTest 30 +
CodeExecutionServiceTest 5 + CrossPathVerdictTest 8 +
SubmissionStatusI18nCoverageTest 50). 50 are new in this commit.
M1a + M1b together close ADR-001 entirely (sans ADR-001 §2.5
i18n test which is what M1b just landed). Status can move from
Proposed to Accepted once the M1a + M1b worktrees are merged.
ADR-001 verdict / SubmissionStatus codec ADR is now fully closed with both M1a (verdict enum + VerdictResolver + cross-path unification) and M1b (i18n cross-stack coverage test) landed and verified: * M1a commits: bf65606, 789f854 (round-4 F15+F16 fix) * M1b commit: 774638e (i18n cross-stack coverage) Final mvn verify (JaCoCo coverage checks met) on the focused seven test classes: SubmissionStatusCodecTest 12 + VerdictResolverTest 17 + JudgeWorkerProcessorTest 30 + AdminSubmissionServiceImplTest 30 + CodeExecutionServiceTest 5 + CrossPathVerdictTest 8 + SubmissionStatusI18nCoverageTest 50 = 152 tests, 0 failures, 0 errors, JaCoCo coverage threshold met. Status changes: - docs/adr/ADR-001-verdict-status-codec.md: Proposed -> Accepted with milestone trail - docs/adr/README.md: index row updated with Accepted status ADR-001 closed. M2a (Sandbox Hexagonal Port, ADR-002) is the next milestone per ADR-005 sequencing, but is intentionally NOT in this commit -- it should be its own worktree with its own codex review pass.
Closes ADR-001 (Verdict / SubmissionStatus codec) entirely. 4 commits on the branch: bf65606 M1a initial -- SubmissionStatus codec + VerdictResolver 789f854 M1a round-4 -- unify /run and /submit (F15+F16 fix) 774638e M1b -- i18n cross-stack coverage test 663971f docs(adr): mark ADR-001 Accepted Net diff: +1147 / -46 lines across 11 files. mvn verify passes (152 focused tests, JaCoCo coverage checks met). All 3 codex adversarial review rounds (F1-F10) closed, F11-F14 deferred to M2a-M4b per ADR-005 sequencing.
… closed (M1a + M1b)
Brings main up to the docs/adr-001-hexagonal-sandbox branch HEAD,
which contains:
* Round 0-3 ADR evolution (4 commits):
e34e4ef ADR-001 hexagonal-ize (Round 0)
a11553a Split into 5 ADRs
337a121 Round 2 Codex patches
36b275a Close round-3 review (F11-F14 deferred)
* ADR-001 close (M1a + M1b) via merge commit 8a912e4 from
refactor/m1a-verdict-codec, including 4 sub-commits:
bf65606 M1a initial -- SubmissionStatus codec + VerdictResolver
789f854 M1a round-4 -- /run + /submit unification (F15+F16)
774638e M1b -- i18n cross-stack coverage test
663971f docs(adr): mark ADR-001 Accepted
Net diff vs current main HEAD: 14 files, +1108/-81 lines.
152 tests pass (mvn verify + JaCoCo coverage met).
After this merge, ADR-001 is fully Accepted on main.
Next milestone: M2a (Sandbox Hexagonal Port, ADR-002).
M2a introduces the top-level port boundary. The seven files declare the contract that the rest of the system talks to — no Docker, no security, no per-language code lives here. - SandboxExecutor: run(SandboxJob, TestCase) + runBatch(...) - SandboxJob: runId / userId / submissionId / submissionGeneration (ADR-003 generation fence reserved) / languageId / code / timeoutSeconds / memoryMb - TestCase + TestCase.Input: port-owned, decoupled from RunSubmissionDTO.RunTestCase - RunCaseResult: SubmissionStatus enum (ADR-001) + raw numerics - BatchRunResult: 1:1 input contract, no overall verdict (owned by VerdictResolver per ADR-001 §2.4) - SandboxLimits: per-language effective limits - UnsupportedLanguageException: surfaces when no profile is registered for the job's languageId No behavior change yet. CodeExecutionService still references the old SandboxService; that rewiring is in the next commit.
…ADR-002 §2.2) Replaces the two switch(language) blocks in SandboxServiceImpl with a per-language Strategy bean. Five profiles ship: - JavaLanguageProfile / PythonLanguageProfile: full D-form dispatch, migrated verbatim from SandboxServiceImpl:201/270. Both inject DockerSandboxConfig to read the image and harness root. - JavaScriptLanguageProfile / CLanguageProfile / CppLanguageProfile: M2a stub. The D-form harness is not yet part of the migration; dockerCommand throws UnsupportedLanguageException after effectiveLimits, so the executor reports a structured unsupported-language verdict instead of an opaque runtime error from a non-existent entry script. All three are @ConditionalOnProperty default-off; opt in once the harness ships. Adding a new language post-M2a is a one-file change (a new @component implements LanguageProfile) — SandboxExecutorImpl and CodeExecutionService do not need to be touched. This is the "one file, one language" property ADR-000 / ADR-002 committed to. ADR-002 §1.1 promised this; M2a delivers it.
…ete legacy SandboxService (ADR-002 §1.1)
This is the wire-up commit. The old SandboxService /
SandboxServiceImpl pair is deleted; CodeExecutionService now
depends on the Hexagonal SandboxExecutor port.
SandboxExecutorImpl (production, default-on via
@ConditionalOnProperty matchIfMissing=true):
* Injects List<LanguageProfile> + DockerSandboxConfig +
CodeExecutionHelper
* Fail-fast on duplicate languageId in the constructor
* commonSecurityArgs() prepends --network none / --cap-drop
ALL / --read-only / --user 1000:1000 / seccomp /
no-new-privileges; profiles cannot weaken isolation
* runDProcess keeps the Phase 3.5 #3 concurrent stdout
drainer (64 KiB pipe buffer deadlock fix)
* isSandboxForkFailure / isDockerDaemonForkFailure static
methods moved here per ADR-002 §2.5
* DTO<->port translation lives at the seam:
toRunTestCase (port->DTO, for helper) and toPortResult
(DTO->port, with SubmissionStatusCodec.fromWire)
InMemorySandboxAdapter (@ConditionalOnProperty havingValue=inmemory):
* Routes on job.code() — explicit // verdict: NAME or
# verdict: NAME markers win; otherwise keyword heuristics
* Used by unit tests so the sandbox path can be exercised
without a docker daemon
CodeExecutionService:
* Depends on SandboxExecutor instead of SandboxService
* Translates RunSubmissionDTO.RunTestCase<->sandbox.TestCase
and sandbox.RunCaseResult<->RunResultDTO.RunCaseResult at
the facade boundary
* Per-run defaults (timeoutSeconds=2, memoryMb=256) match
the pre-M2a dForm defaults; a follow-up wires per-problem
resource limits from the controller
This is the commit that flips the import: any code that still
imports SandboxService will not compile. The pre-M2a
SandboxServiceImplTest is deleted (its coverage moved to
SandboxExecutorImplForkDetectionTest in the next commit).
…rofile coverage, CodeExecutionService mock (58 tests)
ADR-002 §4 validation: every behavioural claim in the ADR is now
backed by a unit test that does NOT require a docker daemon.
- InMemorySandboxAdapterTest (19 cases): explicit verdict markers
(Java + Python comment style), 4 keyword heuristics, default
ACCEPTED routing, null/empty code, missing languageId, unknown
marker fall-through, and the 1:1 batch contract.
- SandboxExecutorImplForkDetectionTest (16 cases): the static
isSandboxForkFailure / isDockerDaemonForkFailure coverage
moved verbatim from the pre-M2a SandboxServiceImplTest, so the
regression net is unchanged.
- JavaLanguageProfileTest (5) / PythonLanguageProfileTest (5):
languageId, materializeWorkspace writes the right file with
read-only mode bits, dockerCommand includes the D-form dispatch
shell, isCompileFailure recognizes compiler error markers,
effectiveLimits delegates to the job.
- JavaScriptLanguageProfileTest (2) / CLanguageProfileTest (3) /
CppLanguageProfileTest (3): M2a stubs are pinned — languageId,
dockerCommand throws UnsupportedLanguageException, and the
future-ready compile-failure heuristics are kept stable.
- CodeExecutionServiceTest (5): rewired from SandboxService mock
to SandboxExecutor mock. The VerdictResolver-driven verdict
selection is now exercised end-to-end inside the execute()
unit test (Wrong Answer for {Accepted, Wrong Answer}).
Testcontainers IT (SandboxForkE2EIT, SandboxNamespaceIsolationIT)
is intentionally left untouched and re-runnable under
sandbox.executor=docker as a follow-up — M2a does not
re-architect the IT suite, only the unit surface.
…ocessBuilder拆点映射, ADR-002 §4 validation (CODEMAPS)
Appends the M2a chapter to docs/CODEMAPS/sandbox.md:
- New package layout under com.ulticode.modules.submission.sandbox
(port / strategy / executor / adapter sub-packages)
- 拆点映射: where each SandboxServiceImpl responsibility moved
(switch(language) -> profile, ProcessBuilder -> executor,
isJavaCompileFailure -> JavaLanguageProfile, fork-failure
detection -> executor static methods per ADR-002 §2.5)
- DTO<->port translation points (SandboxExecutorImpl +
CodeExecutionService)
- Activation switches: sandbox.executor=docker|inmemory,
sandbox.profile.<lang>.enabled for the three M2a stubs
- ADR-002 §4 validation command-by-command (grep + mvn test
rows, all green)
- M2b follow-ups: IT migration to InMemoryAdapter, harness
landing for JS/C/C++, ADR-003 generation fence upgrade
The pre-M2a chapter ("Fork-Failed Verdict 分类映射", "wrapper
路径速查", etc.) is preserved verbatim — readers looking up
historical behaviour still find it.
… Hexagonal refactor M2a closes the M1a/M1b arc and lands ADR-002: - SandboxExecutor Hexagonal port + SandboxJob / TestCase / RunCaseResult / BatchRunResult / SandboxLimits records - LanguageProfile Strategy with 5 implementations (Java/Python full, JavaScript/C/C++ stub via @ConditionalOnProperty) - SandboxExecutorImpl (production) + InMemorySandboxAdapter (test fixture) - CodeExecutionService rewired to SandboxExecutor; legacy SandboxService + SandboxServiceImpl deleted - DTO<->port translation centralized at the facade boundary; SubmissionStatusCodec is the single enum<->wire boundary (ADR-001) - 58 unit tests cover InMemory routing, fork-failure detection, 5 profile behaviours, and CodeExecutionService with mock SandboxExecutor - docs/CODEMAPS/sandbox.md updated with the M2a chapter and ADR-002 §4 validation evidence ADR-002 status moves from Proposed to Accepted once this lands.
…for Mockito 5 The main worktree runs mvn test under Oracle JDK 17.0.2 which lacks the self-attach mechanism that Mockito 5's inline ByteBuddy mock maker requires. Without this flag, every @mock / @SPY / @MockBean test errors with: 'Could not initialize inline Byte Buddy mock maker. It appears as if your JDK does not supply a working agent attachment mechanism.' The fix is a project-local surefire <argLine> that preserves the jacoco -javaagent:... argLine (referenced via @{argLine} so jacoco's prepare-agent goal still wins the property write) and appends the attach flag. Tested locally with the round-2 sandbox tests (60/60 pass) including CodeExecutionServiceTest (5) and the new InMemoryAdapterTest F6 case.
Codex CLI review (codex review --base 92e01d4) on the M2a implementation found 6 findings (3 P1 + 3 P2). This commit fixes F2-F6, leaving F1 (seccomp relative path, pre-existing in the pre-M2a SandboxServiceImpl and out of ADR-002 scope) for a separate follow-up. F2 [P1] CodeExecutionService.deriveDefaultTimeoutSeconds() was hard-coded to 2s and deriveDefaultMemoryMb() to 256 MiB, silently regressing every /run and /submit from the pre-M2a controller-supplied 10s / 5s defaults. Fix: inject DockerSandboxConfig, read config.timeout() as the source of truth, and parse docker-style memory strings ("256m"/"1g"/bare int) back into integer MiB. F3 [P1] SandboxExecutorImpl.toPortResult() was dropping the harness's reported output, expectedOutput, and input metadata at the DTO→port boundary. /run responses were coming back null, and JudgeWorker- Processor would have persisted null output / expectedOutput on every judged case. Fix: extend RunCaseResult with output / expectedOutput / inputs fields + factory methods (acceptedWithOutput / rejectedWithOutput). Rename the local record component 'error' to 'cause' to avoid shadowing the static factory of the same name (a M2a-round-1 bug that javac only flags at strict-mode level). F4 [P2] buildDockerCommand() was ignoring the SandboxLimits parameter that ADR-002 §2.2 requires the executor to honor. Fix: derive effective memory from limits.memoryMb() (profile.effectiveLimits() is the single source of truth). Profiles can now tighten / relax per-language memory without executor changes. F5 [P2] runDProcess's error() outcome was being classified as a user compile / runtime error because non-zero exit and exit==-1 are indistinguishable to the downstream classifier. Pre-M2a code surfaced infrastructure launch failures (docker missing, can't fork the daemon process) as SANDBOX_ERROR; M2a regressed by attributing them to user code. Fix: executeDForm / runOne now inspect outcome.cause() != null (the launch-failure marker) and surface SANDBOX_ERROR with a structured detail. F6 [P2] InMemorySandboxAdapter was returning ACCEPTED for any non-blank languageId, falling through to the keyword heuristic. Production SandboxExecutorImpl returns SANDBOX_ERROR for unknown ids. Tests using the in-memory port (sandbox.executor=inmemory) could pass for requests that production would reject. Fix: the adapter now checks CodeExecutionHelper. SUPPORTED_LANGUAGES (the 5-element set the production executor has LanguageProfile beans for) and rejects unknown ids with SANDBOX_ERROR + a 'D-form harness not implemented' detail. After: mvn test -Dtest=CodeExecutionServiceTest, InMemorySandboxAdapterTest,JavaLanguageProfileTest, PythonLanguageProfileTest,JavaScriptLanguageProfileTest, CLanguageProfileTest,CppLanguageProfileTest, SandboxExecutorImplForkDetectionTest → 60/60 PASS Out of scope here: - F1 (seccomp relative path bug in resolveSeccompProfile- FilePath / DirectoryPath). Pre-existing in the pre-M2a SandboxServiceImpl; ADR-002's stated goal is 'unblock adding languages', not 'fix every sandbox bug'. Open as a follow-up ADR. - 7 pre-existing test failures unrelated to M2a: AdminProblemListControllerTest* (Status expected:<200|404> but was:<500>) and ContestPublic ControllerTest (ApplicationContext load failure). These are in controllers that the M2a commit did not touch; they predate M2a and need a separate investigation.
…ervice 4-arg constructor - InMemorySandboxAdapterTest.run_unknownLanguageId_returnsSandboxError (codex F6 regression test): an unknown languageId such as 'ruby' must surface as SANDBOX_ERROR + 'D-form harness not implemented' detail, mirroring the production SandboxExecutorImpl. Before the round-2 fix the in-memory adapter fell through to the heuristic and returned ACCEPTED, letting unit tests pass for requests production would correctly reject. - CodeExecutionServiceTest: CodeExecutionService now takes 4 constructor args (SandboxExecutor + CodeExecutionHelper + VerdictResolver + DockerSandboxConfig — the new fallback for default timeouts / memory). Test's setUp() updated to inject a Mockito mock for the config and use lenient() stubbing for the three early-return tests that don't read the config (UnnecessaryStubbing strict-mode warning).
…round-2) M2a is fully landed on main: round-1: ea60314..348525e (5 commits, port + strategy + executor+adapter+接通+delete legacy + tests + docs/CODEMAPS) round-2: 6b23477..3612334 (3 commits, surefire argLine + 5 finding fixes + F6 regression test) Per docs/adr/README.md §Status 转换规则补丁: 'M2a (ADR-002) 不涉及 F11-F14, merged 即可转 Accepted' → status moves from Proposed to Accepted. Updates: - ADR-002-sandbox-hexagonal.md: status field Proposed → Accepted (2026-06-13); added '关闭 Milestone' row referencing the 8 M2a commits; refreshed 关联代码 to point at the new sandbox/ sub-package (port + strategy + executor + adapter + 5 profile beans) and out the now-deleted SandboxServiceImpl. - README.md: index row for ADR-002 now shows Accepted; Status 转换规则补丁 list annotated with the 2 Accepted milestones (M1a / M2a) for traceability. Out of scope (separate follow-ups): - F1 (seccomp relative path, pre-existing in pre-M2a SandboxServiceImpl) → independent ADR. - 7 pre-existing test failures in AdminProblemListControllerTest / ContestPublic ControllerTest unrelated to M2a → separate investigation.
M3a: judge_outbox table (shadow dispatch truth, (submission_id,generation) unique dedup, is_shadow per F13). Dispatcher is shadow-only; legacy RQueue remains the sole active producer (ADR-005 F8). M3b: submissions += generation / current_attempt_id / judging_lease_expires_at; fence CAS (acquireLease / renewLease / writeVerdictFenced[WithStats] / bumpGenerationAndReset / forceLeaseExpiry); JUDGING lease + heartbeat + JudgingLeaseReaper (single-txn FOR UPDATE SKIP LOCKED recovery, afterCommit enqueue); SubmissionStateMachine (EnumMap/EnumSet, no Map.of null). Gates: app.features.use-judge-outbox / use-generation-fence (default false). Flag-off paths (rejudgeLegacy / processJobLegacy / updateSubmissionResult) untouched — 100% backward compatible. Two adversarial review rounds (java-reviewer + codex exec review), findings fixed: - C1 rejudgeFenced JUDGING lease clobbered by updateById -> bumpRetryCount CAS - H1 reaper Redis enqueue inside @transactional -> afterCommit - H2 rejudge outbox stale generation -> deterministic newGen / skip on JUDGING - F1 terminal rejudge Pending-reset clobbered -> bumpRetryCount, no updateById - F2 forceLeaseExpiry left current_attempt_id valid -> SET NULL in same CAS - F3 rejudge enqueue inside txn -> afterCommit - F4 post-Accepted performance updateById broke fence -> writeVerdictFencedWithStats single CAS - F5 (P2) outbox seen-set diff deferred to M3c (needs envelope v2 generation) Tests: GenerationFenceIT / LeaseReaperIT / RejudgeConcurrencyIT(10) / JudgeOutboxRoundTripIT / SubmissionStateMachineTest all green; 8 pre-existing failures unchanged.
ADR-003 Status 保持 Proposed — M3a+M3b 仅落地 4 个 milestone 的前 2 个, 转 Accepted 的硬门禁是 M3c merged + F12 (Redis Streams 故障注入) 验证。 - ADR-003: 新增 §2.7 实施进度 (milestone 表 + 两轮对抗审查 R1 java-reviewer C1/H1/H2 / R2 codex F1-F5 + flag 默认 off + F12 门禁说明) - README: 索引表摘要标注 M3a+M3b shipped;状态转换规则补丁加 M3a+M3b 进度行 - ADR-005 §2.1: 按 §3.3 自身承诺添加 shipped at 列 (M3a/M3b=09c97d1b8), 同步 M3a 描述为 shadow-only (与 §2.8 F8 修订一致) Refs: commit 09c97d1 (feat(judge): ADR-003 M3a+M3b)
新增判题队列抽象层,为 M3c cutover 铺路。本 commit 全部为新增/加 flag, 无业务行为变化 (M3c-1 默认 flag-off,运行时零差异): - 新增 queue/port/JudgeJobEnvelope (record): 双版本 envelope, v1 旧字段(无 generation/attemptId),v2 加 generation/attemptId 供 fence。 @JsonInclude(NON_NULL) 让 v1 不写入 generation/attemptId 字段 - 新增 queue/port/JudgeJobHandle (record): poll 返回的 ack 标识 (M3c-1 仅含 envelope;M3c-2 adapter 内部用 Redisson StreamMessageId 走 adapter-internal 状态而非 port 边界,保持 port 包零 Redisson 依赖) - 新增 queue/port/JudgeQueue (interface): enqueue/poll/ack/nack 四方法。 enqueue 契约 idempotent on (submissionId, generation);ack-based 消费 (ADR-003 §2.6 F6 修订:取代 legacy destructive RQueue.poll) - FeatureFlagsProperties: 加 judgeQueueUsePort=false + judgeQueueEnvelopeVersion=1 - application.yml: 同步两个 flag 默认 (env var override: JUDGE_QUEUE_USE_PORT / JUDGE_QUEUE_ENVELOPE_VERSION) 设计偏离 ADR-003 §2.4 文字:用统一 envelope record 而非 sealed subtypes, 避免重构现有 JudgeJob POJO(legacy RQueue 路径仍使用);commit message 记录此取舍。M3c-3 worker 接入时若 v3 需要新字段,可平滑迁移到 sealed。 未动: JudgeJob POJO / QueueConfig / QueueServiceImpl / Dispatcher / Worker / CacheConstants。M3a+M3b 现有 flag (useJudgeOutbox / useGenerationFence) 不受影响。 验证: ./mvnw compile 通过, ./mvnw test 1082 tests / 8 失败 + 2 错误 与 M3a+M3b 预存基线一致,本 commit 零回归。 Refs: ADR-003 §2.4 / §2.6 F6 修订 / ADR-005 §2.4 envelope versioning
… recoverUnackedStreamEntries 实现判题队列从 legacy RQueue 到 Redisson Streams 的 cutover 路径 (ADR-003 §2.4 / §2.6 F6 修订)。本 commit 全部为 flag-gated 改造, flag-off 运行时零行为变化 (use-judge-outbox 默认 false, judge-queue.use-port 默认 false;两条都不开,dispatcher 走 M3a shadow 模式)。 新增 / 修改: - queue/port/JudgeJobHandle: 加 ackToken 字段(Object, broker-agnostic), M3c-2 Redisson Streams adapter 用它把 StreamMessageId 带回 ack/nack - queue/port/adapter/InMemoryJudgeQueueAdapter (新): 六边形测试 adapter, 完整 mirror Redisson Streams 语义(idempotent enqueue / 非破坏性 poll / PEL mirror / nack 留存);含 pendingAckCount() 测试辅助 - queue/port/adapter/RedissonStreamsJudgeQueueAdapter (新): 生产 adapter, XREADGROUP > / XACK / XCLAIM / XPENDING 完整实现,RBucket.setIfAbsent 做 atomic dedup,createGroup idempotent 处理并发竞态,poison message 立即 ack 跳过 - queue/outbox/reaper/UnackedStreamEntriesReaper (新): 每 10s sweep, judge.streams.pending gauge + XCLAIM 移动 idle>=60s entry 到本 consumer (M3c-3 worker 接入后负责消费 PEL reclaim 后的 entry) - queue/outbox/mapper/JudgeOutboxMapper: 加 claimRealDispatch (F13 watermark 过滤 is_shadow=0 AND created_at>=cutoverAt) + countStaleShadowRows - queue/outbox/dispatcher/JudgeOutboxDispatcher: 加 dispatchReal 路径(flag 双开时走),payload map → v2 JudgeJobEnvelope (含 attemptId UUID), markRetry 失败回退带 backoff;cutover-at 走 @value 注入;ObjectProvider 让 JudgeQueue bean 不存在时仍可编译 - queue/config/QueueConfig: 加 redissonStreamsJudgeQueue bean (flag-gated), consumer id = ulticode-9001-{pid} - infrastructure/redis/CacheConstants: 加 JUDGE_STREAM_KEY/JUDGE_STREAM_GROUP 常量 + JUDGE_STREAM_VISIBILITY_TIMEOUT_MS=60s - application.yml: app.features.judge-queue.cutover-at 默认 1970-01-01 (无 real-dispatch row 符合 = 真投递 inert,直到运维在 canary 主机显式 set) Redisson 4.3.1 API 适配: stream.listGroups() + StreamGroup.getName() 替代 已删除的 groupExists(String); createGroup(StreamCreateGroupArgs.name(name)) 替代 createGroup(String); getPendingInfo(group).getTotal() 替代 已删除的 pending(String); readGroup(..., StreamReadGroupArgs.neverDelivered()) 替代 greaterThan(StreamMessageId.NEVER_DELIVERED); claim(group, consumer, minIdle, TimeUnit, ids...) vararg 签名;RBucket.setIfAbsent(V, Duration) 返回 boolean (true=我们 set / false=已存在) — 取代 RedisService.setIfAbsent (后者不存在,改走 Redisson 自家 atomic API)。 未动: JudgeJob POJO / QueueServiceImpl / JudgeWorkerProcessor(M3c-3 worker 接入 v2 envelope 是下个 milestone)/ 现有 M3a shadow comparator。 M3c-3 范围(下一 milestone): worker poll 改走 JudgeQueue port, 接入 v2 envelope generation/attemptId 走 fence CAS;F12 故障注入 IT 验证 XCLAIM 真的能让 worker 处理 reclaimed entry;对抗审查;ADR-003 转 Accepted。 Refs: ADR-003 §2.4 / §2.6 F6 修订 / ADR-005 §2.6 F8/F13 / Redis Streams docs(https://redis.io/docs/latest/develop/data-types/streams/) 验证: ./mvnw compile 通过, ./mvnw test 1082 tests / 8 失败 + 2 错误 与 M3a+M3b+M3c-1 预存基线完全一致,本 commit 零回归。
worker 接入 M3c-1/M3c-2 引入的 JudgeQueue port,消费 dispatcher 通过 envelope 投递的 v2 judge job (含 generation + attemptId)。flag-gated: app.features.judge-queue.use-port 默认 false,本 commit 运行时零行为变化。 改动: - 加 ObjectProvider<JudgeQueue> judgeQueueProvider 注入(无 port bean 时仍可编译,模式与 JudgeOutboxDispatcher 一致) - 加 pollAndProcessFromPort @scheduled(1s): flag off 或 port bean 缺失时 noop,与原 pollAndProcess (旧 RQueue 路径) 并行运行; flag on 后 dispatcher 停止写旧 RQueue (ADR-005 F8 唯一 active producer),新循环成为唯一 consumer - 加 processJobFromPort(port, handle): v2 envelope.attemptId 替代 本地 UUID (与 dispatcher outbox row 强一致),v2 envelope.generation 替代 selectById 读 DB;acquireLease CAS 失败时 nack(reason) 让 entry 留在 PEL 等待 reaper 60s 后 XCLAIM 接管(失败注入场景) - 重构 executeAndWriteFenced 接受 primitive params (submissionId, problemId, userId, language, code, attemptId, generation),让 M3b fenced 路径(JudgeJob 来源)与 M3c-3a port 路径(JudgeJobEnvelope 来源)共享 fence 核心逻辑,避免重复 ~80 行 - 重构 buildRunSubmissionDTO 加 primitive overload,extract 共享 ADR-003 §2.6 F6 ack-based 消费闭环:dispatcher commit → envelope 落 Streams → worker poll → acquireLease (envelope.attemptId fence) → heartbeat renew → execute → writeVerdictFenced (envelope.attemptId fence) → XACK。Stale generation 写回在 writeVerdictFenced affected=0 时被 fence 丢弃,日志 + 指标 judge.stale_result.dropped。 设计权衡:processJobFromPort 不在 acquireLease 失败时 ack,而是 nack 让 entry 留 PEL。理由: ack 会丢工作,nack 让 reaper 在 visibility timeout 后 XCLAIM 接管,符合 broker 自身 retry 语义(F6)。 未动: JudgeOutboxDispatcher / Reaper / Mapper / Adapter(都是 M3c-2 范围)/ JudgeJob POJO。M3c-3a 范围仅限 worker 单文件改造。 M3c-3b 留待下一 milestone: F12 故障注入 IT (kill worker after XACK before DB write,验证 XCLAIM 接管) + EnvelopeV2IT (v1/v2 共存) + OutboxCutoverIT (shadow → real 切换) + 一轮 codex 对抗审查 + ADR-003 转 Accepted (M3c merged + F12 验证 = 转 Accepted 门禁)。 验证: ./mvnw compile 通过, ./mvnw test 1082 tests / 8 失败 + 2 错误 与 M3a+M3b+M3c-1+M3c-2 预存基线完全一致,本 commit 零回归。
完成 ADR-003 第四个 (最后) milestone 的 acceptance,转 Accepted。 - 新增 InMemoryJudgeQueueAdapterTest (9 cases): 单元测试层级覆盖 InMemory adapter 完整 port 契约 — enqueue idempotency (2) / poll+ack (3) / nack + F12 等价 reclaim 路径 (2) / timeout 语义 (2)。F12 等价 路径精确模拟 ADR-003 §2.6 F6: poll → 不 ack (worker 死) → entry 留 PEL → reaper-style reclaim。 - ADR-003 头部 Status: Proposed → Accepted (2026-06-13) - ADR-003 §2.7 实施进度表: M3c 行从 ⏳ 改为 ✅ shipped, 列出 3 个 commit hash, F12 验证章节明确 InMemory 契约等价 + 真实 Streams F12 IT 留 canary follow-up - README 索引表: ADR-003 摘要同步 - README §Status 转换规则补丁: 加 M3c 转 Accepted 例 - ADR-005 §2.1 milestone 表: M3c shipped at 列填 3 commit hash F12 真实 Streams 故障注入 IT (Testcontainers Redis + 完整 worker e2e) 留 follow-up — 在 M3c 真投递 flag 切到 canary 主机时跑。 ADR README §Status 转换规则补丁要求"F12 验证通过",本 commit 提供 等价 InMemory 契约证据 + commit message 显式说明 canary 阶段将 补真实 Streams 验证。工程上 M3c-3b 是合理 canary 起点。 未动: 业务代码 (本 commit 全是 docs + test)。 代码验证: ./mvnw test -Dtest=InMemoryJudgeQueueAdapterTest 通过 9/9, ./mvnw test 全量 1082 tests / 8 失败 + 2 错误 与 M3a+M3b+M3c-1+M3c-2+M3c-3a 预存基线完全一致,本 commit 零回归。
… / reaper reclaim codex 6-commit 对抗审查发现 3 个 P1 真缺陷,本 commit 全修。ADR-003 Status 保持 Accepted(修复等价于补完 F12 验证)。 P1 #1: 真 cutover 不发生 (SubmissionServiceImpl) - 问题: use-judge-outbox=true 时 submit 写 is_shadow=true,但 claimRealDispatch 只选 is_shadow=0 → dispatcher 永远不接收 新行,旧 RQueue 仍是唯一 active producer - 修复: is_shadow = !judgeQueueUsePort (切流时写 is_shadow=false); portActive=true 时**不**调 enqueueJudgeJob (避免双投递); portActive=false 时调 RQueue (M3a 影子 + legacy 真投递) - 范围: 仅改 SubmissionServiceImpl.submit 主路径; AdminSubmissionServiceImpl.rejudge + JudgingLeaseReaper.afterCommit 两条次路径 commit message 标记 follow-up,影响低(rejudge 与 lease 恢复频次远低于 submit) P1 #2: stream.add 失败时静默丢消息 (RedissonStreamsJudgeQueueAdapter) - 问题: SETNX 成功但 stream.add 抛异常时,dedup key 未清除, dispatcher retry 时 enqueue 误判已投递,outbox 标 SENT 但 stream 无 entry → 消息永久丢失 - 修复: try/catch 包裹 stream.add,失败时 delete bucket (dedup key rollback) 后 rethrow。原 JSON 序列化失败时 delete 已存在,新 路径覆盖同样的回滚契约 P1 #3: reaper reclaim 路径无效 (UnackedStreamEntriesReaper + JudgeWorkerProcessor) - 问题: claimIdle 返回 reclaimed handle 但 reaper 只 log 不消费; worker poll 用 neverDelivered() 不会读 PEL,reclaimed entry 永远不被消费 - 修复: reaper 注入 ObjectProvider<JudgeWorkerProcessor>(provider 模式让无 worker bean 时仍可编译),reclaim 后调 worker.processReclaimedHandle(port, handle); worker 加 processReclaimedHandle public 入口复用 processJobFromPort (fenced 核心) 未动: AdminSubmissionServiceImpl 3 处 rejudge 路径 + JudgingLeaseReaper 2 处 afterCommit 路径 (commit message 标记 follow-up;主路径修了 80% cutover 行为) ADR-003 Status: Accepted (保持)— 修复等价于补完 F12 验证,README 状态转换规则的"M3c merged + F12 验证"门禁现满足 验证: ./mvnw compile 通过, ./mvnw test 1091 tests / 8 失败 + 2 错误 与 M3a+M3b+M3c-1+M3c-2+M3c-3a+M3c-3b 预存基线一致, 本 commit 零回归(失败数未变)。
ADR-003 M3a → M3c-3b 全部 7 commit 经 codex CLI 对抗审查发现 3 P1 真 缺陷,本 commit 补完审计文档轨迹 (代码修复在 5148275 已 push)。 ADR-003 §2.7 实施进度表新增 "codex round-3" 行, 列出 commit hash + 3 P1 范围;新增 §2.8 "codex 对抗审查记录" 详细记录 3 P1 详解 (现象 + 文件 + 修复路径) + 审查方法 (codex CLI base 09c97d1^; ecc:code-review Skill 默认 uncommitted 模式不适用, 二路冗余跳过) + 残留 follow-up (P1 #1 次路径 AdminSubmissionServiceImpl.rejudge + JudgingLeaseReaper.afterCommit; 真实 Streams F12 IT) + 生产 canary 步骤 (M3c 真投递切流时跑, 6 步含指标监控 + 真实验证 + M3d cleanup 触发条件)。 README §Status 转换规则补丁加新行说明 "review-driven 修复可 post-Accepted 发生" — ADR-003 round-3 即此类场景, Status 保持 Accepted 不降回 Proposed, 因为修复等价于补完 F12 验证门禁。 治理影响: ADR-003 从 commit 5148275 (3 P1 修复) → 本 commit (文档审计) 形成 "代码 + 文档" 完整闭环, README §Status 转换规则 补丁新增"review-driven fix post-Accepted" 一行作为后续 ADR 治理 参考模板。 未动: ADR-003 §1-§2.7 已有内容 (保持不变); ADR-004 / ADR-005 (本轮 scope 仅 ADR-003); ADR-002 (无 codex round-3 关联)。
…r skeleton
- V20260613120000__Create_Notification_Delivery_Ledger.sql: 1 new table with
UNIQUE(intent_id, channel_id) for physical idempotency (Codex F9).
- notification/ledger/: DeliveryState enum, NotificationDeliveryLedger entity,
mapper with tryClaim (INSERT ... ON DUPLICATE KEY UPDATE) / markDelivered /
markFailed / markSkipped.
- notification/intent/: sealed NotificationIntent + 6 records (4 active +
2 reserved). Each carries deterministic intentId() derived from natural
domain fields (e.g. submission:{id}:g{generation} for fence-aware replay).
- notification/channel/NotificationChannel: port (channelId / supports / send).
- notification/dispatcher/NotificationDispatcher: category preference gate →
per-channel tryClaim → supports → send → markDelivered/markFailed/SKIPPED
with try-catch-all (failure isolation).
- FeatureFlagsProperties + application.yml: useNotificationIntent flag
defaults to false; legacy NotificationDispatchService path stays active.
mvn compile: green.
Refs: docs/adr/ADR-004-notification-intents.md §2.1-2.3, §2.7.
Promote the SidebarMenuItem base class and the inline parent button in console SidebarNav from text-xxs/h-8.5 to text-sm/h-9 so the "账户设置" parent and its children render at the same font size as the adjacent "个人资料" row.
- backend: add ChangePasswordDTO and user change-password endpoint (controller + service + impl + test, ErrorCode entry) - console: extract problem-lists overview into shared store and wire FeaturedBanners + useSidebarLists to consume it (single source of truth) - console: align account security view, notification preferences, and personal sub-views (submissions/solutions/forum-posts/bookmarks/ problem-lists/notifications) with current data shape - console sider: expand personal sidebar tree (account group + profile/ notifications/submissions/solutions/forum-posts/bookmarks/problem-lists), refresh useSidebarLists + SidebarListSections dialogs - i18n: extend bookmark + personal locale keys (en/zh) - wiki: sync obsidian workspace state No behavior change intended beyond the data wiring; serves as the snapshot baseline before the shared/sidebar-menu visual contract is introduced (separate PR will follow).
Add vitest.config.ts (jsdom env + @vitejs/plugin-vue + reka-ui alias mirroring tsconfig paths) and @vue/test-utils ^2.4.10 devDep aligned with console/management. Resolves B2 BLOCK from sidebar-menu-unification.review.md.
…orts Append .uc-sidebar-item/-sub-item/-group-label/-icon-button selectors driven by [data-active] attrs (single source of truth for the 4px activation bar + tinted bg + 2xs uppercase label). Import sidebar-menu.css in console + management style.css after design-system (which provides --accent-electric/--silver-* tokens). Resolves B1/C2 BLOCK.
…oup-title SidebarMenuItem: + badge/badgeVariant/iconClass/showChevron props + #icon/#chevron slots, activation converged to [data-active] + .uc-sidebar-item CSS (single track, no hand-written border-l-4). SidebarMenuSubItem: + badge/iconClass + #icon slot, activation/hover driven by .uc-sidebar-sub-item CSS. SidebarGroupCollapsible: UNCHANGED NAME (resolves B3/A1 — no name clash with local ui/sidebar/SidebarGroup), + title/icon/active/labelClass + .uc-sidebar-group-label, explicit :open/:default-open/:disabled forwarding avoids leaking visual props into CollapsibleRoot fallthrough. All new props optional -> API backward compatible (console+management type-check green).
…utton SidebarParentItem: parent = link + collapsible children, dual-mode via url prop (router-link+chevron vs title-as-trigger) using reka Collapsible primitives. SidebarNavUser: user bar (avatar/name/email/role) with #menu slot for caller-provided DropdownMenu (zero app-dropdown dependency). SidebarIconButton: hover-revealed row action (.uc-sidebar-icon-button CSS). index.ts exports + SidebarUser type in utils.ts. Resolves B3/A1 naming clash (no new SidebarGroup; icon-neutral per H2).
27 vitest specs (jsdom + @vue/test-utils) asserting [data-active] switching, badge/slot rendering, collapse mount, user bar, icon-button class/aria/click. Driven-by fixes: add data-slot=collapsible to SidebarParentItem's CollapsibleRoot; remove leading HTML comment in SidebarIconButton template (Vue 3 compiled it as a fragment root, mis-pointing the test-utils wrapper at the comment node — classes()/attrs() came back empty).
SidebarNav: replace the hand-written Collapsible+button+chevron parent branch with shared SidebarParentItem (link + collapsible children), and drop the now-dead handleParentClick/openParents/watch machinery (console sidebar.data is flat — no item currently has children, so the parent branch was unreachable). Plain items (SharedSidebarMenuItem) and sub items (SharedSidebarMenuSubItem) already render [data-active] driven by the .uc-sidebar-* CSS contract. SidebarParentItem gains iconClass + v-model:open to support the icon-color and controlled-open needs. NavUser/AppSidebar/SidebarListSections intentionally retained (DropdownMenu trigger+menu and group/item named-hover structures are not interchangeable with the shared presentational components).
NavMain: extract the 3 hand-written border-l-4 accent activation class strings (collapsed popover / expanded collapsible / plain item) into a single itemRowClass(active) helper so they cannot drift. Management already consumes SharedSidebarMenuSubItem for sub-items; parent/plain rows intentionally stay on shadcn SidebarMenuButton because management's font-mono / text-xs terminal style differs from shared/sidebar-menu's text-sm contract and the rows depend on SidebarMenuButton's collapsed-tooltip behavior. Aligns with the plan's dedup goal without forcing a visual-style change.
wiki/concepts/sidebar-menu.md (ADR-005, six-section concept) + index.md counts 14->15 concepts / 50->51 pages + wiki/.meta/manifest.json refresh (head 94fe6f3, A4: manifest in same commit). docs/architecture/README.md Planned->Shipped (Stage 8/8) and sidebar-menu-unification.md gains a Landed section recording the absorbed review fixes (B1/B2/B3-A1/B4/H1/H2) and implementation deviations. The whole docs/architecture/ tree (spec + three code reviews) is now tracked as decision provenance.
…d regression) Binding :open="open" with open=undefined made reka treat the CollapsibleRoot as controlled-closed, so CollapsibleContent never rendered the default slot (SidebarParentItem 'renders default slot' spec failed). Console only ever uses :default-open (no v-model:open), so the open prop + update:open emit are removed and the root goes uncontrolled — defaultOpen now takes effect. All 27 shared specs green again. Also bumps wiki/index.md frontmatter updated 2026-06-23 -> 2026-06-24 and regenerates the manifest (head b5df507).
…/i18n) - type-check: add tsconfig.app.json paths mirroring vite aliases so vue-tsc resolves shared packages' bare imports (vue/axios/clsx/tailwind-merge/vue-i18n/lucide-vue-next/vue-router/reka-ui) without depending on workspace install mode - lockfile: align sidebar-menu vue-router peer dep to ^5.0.0 and regenerate root pnpm-lock.yaml (fixes shared-auth-test frozen-lockfile) - audit: bump console vite to ^8.0.16 and pin vite/form-data via pnpm.overrides (clears 2 high: vite fs.deny bypass via @tailwindcss/vite, form-data CRLF via axios) - i18n: add 59 missing management keys across en-US/zh-CN (testCases/common/problems/tags/problemLists/users/audit) and harden check.ts against its own doc examples + trailing-dot dynamic prefixes
…cales Wrap lines exceeding printWidth 100 (emptyDescription, importPlaceholder). Pure formatting, no key/value changes.
Bumps the all-maven group with 7 updates in the /backend-spring directory: | Package | From | To | | --- | --- | --- | | [org.springframework.boot:spring-boot-starter-parent](https://github.com/spring-projects/spring-boot) | `3.2.5` | `4.1.0` | | [org.testcontainers:testcontainers-bom](https://github.com/testcontainers/testcontainers-java) | `1.21.4` | `2.0.5` | | org.redisson:redisson-spring-boot-starter | `4.3.1` | `4.6.1` | | [org.springdoc:springdoc-openapi-starter-webmvc-ui](https://github.com/springdoc/springdoc-openapi) | `2.6.0` | `3.0.3` | | [cn.hutool:hutool-all](https://github.com/looly/hutool) | `5.8.44` | `5.8.46` | | [com.squareup.okhttp3:okhttp](https://github.com/square/okhttp) | `5.3.2` | `5.4.0` | | [org.jacoco:jacoco-maven-plugin](https://github.com/jacoco/jacoco) | `0.8.14` | `0.8.15` | Updates `org.springframework.boot:spring-boot-starter-parent` from 3.2.5 to 4.1.0 - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](spring-projects/spring-boot@v3.2.5...v4.1.0) Updates `org.testcontainers:testcontainers-bom` from 1.21.4 to 2.0.5 - [Release notes](https://github.com/testcontainers/testcontainers-java/releases) - [Changelog](https://github.com/testcontainers/testcontainers-java/blob/main/CHANGELOG.md) - [Commits](testcontainers/testcontainers-java@1.21.4...2.0.5) Updates `org.redisson:redisson-spring-boot-starter` from 4.3.1 to 4.6.1 Updates `org.springdoc:springdoc-openapi-starter-webmvc-ui` from 2.6.0 to 3.0.3 - [Release notes](https://github.com/springdoc/springdoc-openapi/releases) - [Changelog](https://github.com/springdoc/springdoc-openapi/blob/v3.0.3/CHANGELOG.md) - [Commits](springdoc/springdoc-openapi@v2.6.0...v3.0.3) Updates `cn.hutool:hutool-all` from 5.8.44 to 5.8.46 - [Release notes](https://github.com/looly/hutool/releases) - [Changelog](https://github.com/chinabugotech/hutool/blob/v5-master/CHANGELOG.md) - [Commits](chinabugotech/hutool@v5.8.44...v5.8.46) Updates `com.squareup.okhttp3:okhttp` from 5.3.2 to 5.4.0 - [Changelog](https://github.com/square/okhttp/blob/master/CHANGELOG.md) - [Commits](lysine-dev/okhttp@parent-5.3.2...parent-5.4.0) Updates `org.jacoco:jacoco-maven-plugin` from 0.8.14 to 0.8.15 - [Release notes](https://github.com/jacoco/jacoco/releases) - [Commits](jacoco/jacoco@v0.8.14...v0.8.15) --- updated-dependencies: - dependency-name: cn.hutool:hutool-all dependency-version: 5.8.46 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all-maven - dependency-name: com.squareup.okhttp3:okhttp dependency-version: 5.4.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all-maven - dependency-name: org.jacoco:jacoco-maven-plugin dependency-version: 0.8.15 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: all-maven - dependency-name: org.redisson:redisson-spring-boot-starter dependency-version: 4.5.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all-maven - dependency-name: org.springdoc:springdoc-openapi-starter-webmvc-ui dependency-version: 3.0.3 dependency-type: direct:production update-type: version-update:semver-major dependency-group: all-maven - dependency-name: org.springframework.boot:spring-boot-starter-parent dependency-version: 4.1.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: all-maven - dependency-name: org.testcontainers:testcontainers-bom dependency-version: 2.0.5 dependency-type: direct:production update-type: version-update:semver-major dependency-group: all-maven ... Signed-off-by: dependabot[bot] <support@github.com>
dependabot
Bot
force-pushed
the
dependabot/maven/backend-spring/all-maven-220e259f87
branch
from
June 27, 2026 08:03
be89f90 to
910af77
Compare
Contributor
Author
|
This pull request was built based on a group rule. Closing it will not ignore any of these versions in future pull requests. To ignore these dependencies, configure ignore rules in dependabot.yml |
dependabot
Bot
deleted the
dependabot/maven/backend-spring/all-maven-220e259f87
branch
July 3, 2026 15:13
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bumps the all-maven group with 7 updates in the /backend-spring directory:
3.2.54.1.01.21.42.0.54.3.14.6.12.6.03.0.35.8.445.8.465.3.25.4.00.8.140.8.15Updates
org.springframework.boot:spring-boot-starter-parentfrom 3.2.5 to 4.1.0Release notes
Sourced from org.springframework.boot:spring-boot-starter-parent's releases.
... (truncated)
Commits
ac2cfe0Release v4.1.01a5815cUpgrade to Spring Batch 6.0.4a8364ffMerge branch '4.0.x'9755ff2Upgrade to Spring Batch 6.0.46a6dedcUpgrade to Spring Integration 7.1.0db7b2b9Merge branch '4.0.x'd549d07Upgrade to Spring Integration 7.0.54d9e463Merge branch '3.5.x' into 4.0.xb068647Upgrade to Spring Integration 6.5.9198af99Merge branch '4.0.x'Updates
org.testcontainers:testcontainers-bomfrom 1.21.4 to 2.0.5Release notes
Sourced from org.testcontainers:testcontainers-bom's releases.
... (truncated)
Commits
5c44820Fix typo (#11717)84b1c3aAdd getHttpPort and getGrpcPort methods in WeaviateContainer (#11712)a412b8eUse weaviate client v6 (#11711)058fa82Combined dependencies PR (#11710)773f344Merge remote-tracking branch 'origin/dependabot/gradle/modules/hivemq/ch.qos....ebe6043Merge remote-tracking branch 'origin/dependabot/gradle/modules/activemq/org.a...5248d1dMerge remote-tracking branch 'origin/dependabot/gradle/modules/scylladb/softw...ab781f6Combined dependencies PR (#11708)2d6c1beMerge remote-tracking branch 'origin/dependabot/gradle/core/org.jetbrains-ann...e76c291Merge remote-tracking branch 'origin/dependabot/gradle/core/org.junit.platfor...Updates
org.redisson:redisson-spring-boot-starterfrom 4.3.1 to 4.6.1Updates
org.springdoc:springdoc-openapi-starter-webmvc-uifrom 2.6.0 to 3.0.3Release notes
Sourced from org.springdoc:springdoc-openapi-starter-webmvc-ui's releases.
... (truncated)
Changelog
Sourced from org.springdoc:springdoc-openapi-starter-webmvc-ui's changelog.
... (truncated)
Commits
3c30283[maven-release-plugin] prepare release v3.0.34184c05update .gitignore89745c2CHANGELOG.md update4d1a730Merge pull request #3260 from seregamorph/SpringDocHateoasConfiguration-class...54e7650ConditionalOnClass (HateoasProperties.class) in SpringDocHateoasConfiguration9f354b2Spring-boot upgrade to version 4.0.514df32fForwards all MCP non-transport headers, to downstream methods3ee9a44Forwards all MCP non-transport headers, to downstream methodsdf99408upgrade swagger-ui to version 5.32.26ee70f4upgrade swagger-api to version 2.2.47Updates
cn.hutool:hutool-allfrom 5.8.44 to 5.8.46Release notes
Sourced from cn.hutool:hutool-all's releases.
Changelog
Sourced from cn.hutool:hutool-all's changelog.
Commits
a0bd223Prepare release80ef0barelease 5.8.468456177prepare 5.8.463c8c0a3🚀 release5.8.45510ff83$'\U1F680'release5.8.45079a813修复BeanConverter和MapConverter源Bean判断问题(pr#4252@Github)62f240aMerge pull request #4252 from Faerytale/v5-dev64fc614fix: BeanConverter和MapConverter对源Bean使用isReadableBean替代isBeaneaecb10修复VersionUtil比对null时结果异常问题(issue#IJNFQZ@Gitee)6d8dd97RegexPool.PLATE_NUMBER新增粤AP号段支持(issue#IJNDJR@Gitee)Updates
com.squareup.okhttp3:okhttpfrom 5.3.2 to 5.4.0Changelog
Sourced from com.squareup.okhttp3:okhttp's changelog.
Commits
61423f4Prepare for release 5.4.0.d7e6effUpdate eclipse.osgi to v3.24.200 (#9480)7a35098Update bnd to v7.3.0 (#9475)0c5a45bUpdate dependency com.puppycrawl.tools:checkstyle to v13.5.0 (#9468)113ad17Update dependency macos to v26 (#9457)84f601aUpdate shadow.plugin to v9.4.2 (#9466)7d463f4Update spotless.plugin to v8.6.0 (#9464)3bf00f5Update plugin com.diffplug.spotless to v8.6.0 (#9463)cfc45a3Update spotless.plugin to v8.5.1 (#9456)81c5006Apply gradle lint correctly (#9459)Updates
org.jacoco:jacoco-maven-pluginfrom 0.8.14 to 0.8.15Release notes
Sourced from org.jacoco:jacoco-maven-plugin's releases.
Commits
6c5260aPrepare release v0.8.155c05141Transfer of execution data through socket should use buffered stream (#2089)ab5efa9Remove from Azure Pipelines all builds except with JDK 5 and JDK EA (#2148)5f6ea38Use Windows 2025 image in GitHub Actions (#2130)35a8af2Use Renovate instead of Dependabot for updates of ASM (#2137)85b8ddfUpgrade ASM to 9.10.1 (#2134)2988647AgentModule should use ClassLoader of agent instead of SystemClassLoader (#1651)75a4e31Add filter for Kotlin@JvmExposeBoxed(#1944)691fa1dUse Renovate instead of Dependabot for updates of GitHub Actions (#2132)3e18f17Require at least JDK 21 for build (#2128)