Skip to content

Harden TIS credential, selection, and privacy contracts - #8

Merged
aprylewu merged 8 commits into
wormforce:mainfrom
Stevvven777:codex/harden-contracts-4-7
Sep 7, 2026
Merged

Harden TIS credential, selection, and privacy contracts#8
aprylewu merged 8 commits into
wormforce:mainfrom
Stevvven777:codex/harden-contracts-4-7

Conversation

@Stevvven777

@Stevvven777 Stevvven777 commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Summary

This is one conservative contract/safety patch for the four downstream-reported gaps:

  • verify Linux Secret Service writes by immediate read-back, roll back unverified writes, and return actionable locked-collection / desktop D-Bus / access-denied remediation
  • normalize selectable lecture/lab/tutorial rows into explicit bundles with one credit-bearing component, required-component coverage, merged teaching teams/meetings, parity weeks, and documented courseId -> p_id / rwh semantics
  • assign a local correlation ID to each TIS mutation, return a non-retriable uncertain state when submission may have started, and add bounded read-only tis selection reconcile outcomes (applied, not_applied, still_uncertain)
  • project availability, enrollment, degree progress, and degree-missing results through planning field allowlists; grades are absent by default and raw selection/mutation envelopes are excluded from CLI JSON
  • update the bundled Agent Skill and architecture/auth/output documentation so agents follow these contracts

Safety boundaries

  • No live campus mutation was performed.
  • TIS does not expose a verified idempotency-key facility here. clientRequestId is correlation metadata only and is not sent upstream; automatic retry remains forbidden.
  • Conflicting bundle credits, including contradictory duplicate rows for the same component, are omitted as ambiguous rather than summed or guessed. Ambiguous bundles are not marked selectable without guessing.
  • retainCourseSourceRecord is an explicit library diagnostics-only escape hatch and is never used by a CLI command.
  • Reconciliation performs 2–5 bounded exact read-backs and never repeats a write. Missing/mismatched round metadata or missing bid evidence remains uncertain. Transport errors retain semester, cultivation, round, bid, location and exact identifiers for reconciliation.
  • Planning enrollment output extracts supported SKSJ teacher, room, week and period fields before removing the raw description; explicit source fields take precedence.

Validation

  • npm run check
  • Maintainer validation on macOS / Node v22.19.0: 40/40 focused selection, planning, normalization, client and credential tests passed; newly added regressions reproduced the original failures before the fixes.
  • The integration branch including PRs feat: refine context into an AI-ready daily snapshot #12, fix(cli): align Unicode table columns #13 and feat(talks): add official campus lectures #14 passed 348/348 tests and 21/21 context/calendar tests with TZ=UTC, plus an isolated tarball installation and public lecture-query smoke test.
  • npm audit: 0 vulnerabilities
  • npm pack --dry-run: passed; new modules, docs, and Skill are in the tarball
  • official Skill Creator validator: Skill is valid!
  • no credentials, cookies, tokens, raw campus payloads, or real student fixtures were added

Related to #4 — keep open pending verification in the reporter's actual Linux desktop session.
Fixes #5
Fixes #6
Fixes #7

@Stevvven777

Copy link
Copy Markdown
Contributor Author

@wormforce When convenient, could you review this PR? The downstream advisor mitigations are now shipped in v0.2.1, including a checksummed GitHub Release and clean macOS/Ubuntu/Windows bootstrap smoke. The upstream patch here remains the protocol-level fix for #4#7; its branch passed the 326-test suite, audit, package, privacy, and Skill checks recorded in the PR body. I will address any requested changes promptly.

@Stevvven777

Copy link
Copy Markdown
Contributor Author

@wormforce One concrete unblock for this PR: GitHub created the pull-request CI run, but it is action_required before any jobs start and needs a maintainer to approve the workflow run: https://github.com/wormforce/sustech-cli/actions/runs/33559383724

The head is still mergeable against current main (7ce36b6 on base 8efad42). The same commit passed the full 326-test, type-check, audit, privacy, Skill, and package gates locally; no code change is currently requested. I will respond promptly if the approved matrix exposes a platform failure.

@pentaoa pentaoa left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed commit 7ce36b6. The build and 31 focused tests pass, but the following synthetic reproductions expose gaps that should be fixed before merging. No live selection mutation was performed.

  1. [P1] Validate the selection round before declaring reconciliation conclusive. In src/tis/remaining-selection.ts:482-500, reconciliation delegates to verifySelectionWrite without checking observation.roundCode against target.round. A bid.update target for bxxk, bid 5, with the exact courseId/RWH present at bid 5 in two yixuan snapshots returns applied. With the same matching bid but missing round metadata in both snapshots, it returns not_applied. Neither establishes the requested round's state. Treat missing/mismatched round evidence as still_uncertain and add both cases to the tests. This blocks the exact-target contract in #6.

  2. [P2] Preserve planning fields when enrollment metadata is supplied through SKSJ. src/tis/planning-projection.ts:100-106 copies only entry.teacher and entry.room, while dropping the description. normalisePersonalScheduleEntry supports SKSJ-only records but does not extract their bracketed teacher/room fields. A synthetic row with SKSJ: 'Synthetic course\n[Example Teacher]\n[Section A]\n[1-3周][Room 101][7-8节]' and no separate SKJS/SKDD yields teachingTeam: [] and room: '' in the new default JSON. Previously the description retained those fields. Normalize the supported description fields before projection and test that path, so #7 does not remove information that planners actually need.

  3. [P2] Check duplicate-row credit conflicts before discarding duplicate fields. In src/tis/selection-bundles.ts:73-91, same-component rows are collapsed before resolveCreditCarrier runs. Two records with the same explicit bundleId, id and rwh but xf: 2 and xf: 3 produce credits: 2, creditStatus: 'deduplicated', and selectableWithoutGuessing: true; reversing the input chooses 3 instead. The public contract says conflicting source credits are omitted as ambiguous. Retain/check conflicting credit evidence during deduplication and add the same-component variant of the existing conflict test for #5.

The Linux write read-back and actionable Secret Service diagnostics are useful improvements for #4. However, the reported issue only contains a generic lookup failure, so these tests do not establish that its specific desktop-session failure is resolved; keep that distinction explicit when closing the issue.

@aprylewu
aprylewu merged commit 17d50fa into wormforce:main Sep 7, 2026
11 of 12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants