From 96e2582652c609ccd418f0feaa6215d24b2a00b1 Mon Sep 17 00:00:00 2001 From: Troy Scott <846218+troyscott@users.noreply.github.com> Date: Tue, 1 Sep 2026 23:17:23 -0700 Subject: [PATCH 1/2] Publish sourced OneLake workspace chapter --- README.md | 8 +- content/published/dp700/book.yaml | 37 ++++- .../dp700/chapters/workspace-settings.md | 138 ++++++++++++++---- docs/content-model.md | 26 +++- src/study_reader/content/models.py | 35 ++++- src/study_reader/reader/static/reader.css | 5 +- .../reader/templates/chapter.html | 12 +- tests/content/test_dp700_outline.py | 26 +++- tests/integration/test_reader_page.py | 4 +- tests/unit/test_models.py | 26 +++- 10 files changed, 265 insertions(+), 52 deletions(-) diff --git a/README.md b/README.md index 1a95493..70b6b69 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,12 @@ reproducing Microsoft Learn pages. ## Project status -The project is in its first reader milestone. The repository provides separate +The project has completed its reader-foundation milestone. The repository provides separate public reader and private administration application factories, a validated exam-agnostic book contract, the current DP-700 outline, sanitized Markdown -rendering, a responsive reader shell, automated boundary tests, and CI. Reader -preferences, local progress, annotations, and offline support remain roadmap -work. +rendering, a responsive reader shell, persistent appearance and progress state, +an official-source registry, automated boundary tests, and CI. Annotations, +offline support, and the refresh/publishing pipeline remain roadmap work. ## Architecture boundary diff --git a/content/published/dp700/book.yaml b/content/published/dp700/book.yaml index 578e085..abc3815 100644 --- a/content/published/dp700/book.yaml +++ b/content/published/dp700/book.yaml @@ -7,6 +7,39 @@ sources: - id: dp700-study-guide title: Official DP-700 study guide url: https://learn.microsoft.com/en-us/credentials/certifications/resources/study-guides/dp-700 + retrieved_at: 2026-09-02T04:45:35Z + content_sha256: 97f5520c88cb9cc9833c1cebe2bb61d899f12825ac97dc2198584d683f3e5596 + chapter_ids: [workspace-settings, lifecycle-management, security-governance, orchestration, loading-patterns, batch-data, streaming-data, monitor-items, resolve-errors, optimize-performance] + - id: onelake-overview + title: What is OneLake? + url: https://learn.microsoft.com/en-us/fabric/onelake/onelake-overview + retrieved_at: 2026-09-02T04:45:35Z + content_sha256: fd6c5687b64f131db16d4264dbeedc37ec110a52ff13b487e5c9e1ad150c1ebb + chapter_ids: [workspace-settings] + - id: onelake-diagnostics + title: OneLake diagnostics + url: https://learn.microsoft.com/en-us/fabric/onelake/onelake-diagnostics-overview + retrieved_at: 2026-09-02T04:45:35Z + content_sha256: 3cd73c6ff5f198a7faf47f308aa3f58bc649bc1cebd3e215f958b43200cb7bb5 + chapter_ids: [workspace-settings] + - id: onelake-storage-tiers + title: Storage tiers in OneLake + url: https://learn.microsoft.com/en-us/fabric/onelake/onelake-storage-tiers + retrieved_at: 2026-09-02T04:45:35Z + content_sha256: 3e6d11876c66873d0cb452a5fe2cef02fdab3782a1400724b758a202f47d2120 + chapter_ids: [workspace-settings] + - id: onelake-lifecycle + title: OneLake lifecycle management + url: https://learn.microsoft.com/en-us/fabric/onelake/onelake-lifecycle-management + retrieved_at: 2026-09-02T04:45:35Z + content_sha256: 261d43b3f34bfbc66a472a0f32e9e7d3de5e57801018785d7ef50d1b57311c0a + chapter_ids: [workspace-settings] + - id: onelake-settings-api + title: OneLake Settings - Get Settings REST API + url: https://learn.microsoft.com/en-us/rest/api/fabric/core/onelake-settings/get-settings + retrieved_at: 2026-09-02T04:45:35Z + content_sha256: 5f6c3efbc8db82e5bf7e6864286f2eb9141f7026e02efcdf9eb15252629e28ea + chapter_ids: [workspace-settings] domains: - id: implement-manage title: Implement and manage an analytics solution @@ -16,8 +49,8 @@ domains: slug: workspace-settings title: Configure Microsoft Fabric workspace settings content_path: workspace-settings.md - status: draft - source_ids: [dp700-study-guide] + status: published + source_ids: [dp700-study-guide, onelake-overview, onelake-diagnostics, onelake-storage-tiers, onelake-lifecycle, onelake-settings-api] objectives: - {id: implement.workspace.spark, title: Configure Spark workspace settings} - {id: implement.workspace.domain, title: Configure domain workspace settings} diff --git a/content/published/dp700/chapters/workspace-settings.md b/content/published/dp700/chapters/workspace-settings.md index 127e7fd..02c0b11 100644 --- a/content/published/dp700/chapters/workspace-settings.md +++ b/content/published/dp700/chapters/workspace-settings.md @@ -1,42 +1,130 @@ # Configure Microsoft Fabric workspace settings -Workspace settings are control points. They shape how a team uses compute, organizes ownership, reaches shared data, and schedules orchestration. For the exam, focus on **who controls a setting, what scope it affects, and what operational consequence follows**. +The exam objective groups Spark, domain, OneLake, and Apache Airflow settings under one heading. This chapter concentrates on **OneLake workspace settings** as the representative case. The reliable way to reason through these settings is to identify the administrative scope, the data affected, and the operational consequence before selecting an option. -## Start with the boundary +## Orient yourself: OneLake, workspace, item - -A workspace is a collaboration and security boundary, but not every behavior is controlled at workspace scope. Some defaults inherit from capacity or tenant administration. Before changing a setting, identify the governing scope and whether the workspace administrator can override it. + +[OneLake](https://learn.microsoft.com/en-us/fabric/onelake/onelake-overview) is the single organizational data lake supplied with a Fabric tenant. Workspaces divide that lake into independently administered project or domain containers. A OneLake workspace setting therefore controls storage or diagnostics behavior for that workspace; it does not create another OneLake. -| Setting family | Primary concern | Exam question to ask | +Keep three scopes separate: + +| Scope | Typical owner | Examples | +| --- | --- | --- | +| Tenant | Fabric administrator | Whether a capability is allowed or delegated across the organization | +| Workspace | Workspace administrator | OneLake diagnostics, default storage tier, and lifecycle policy | +| Item or data | Item owner or appropriately privileged user | Lakehouse permissions and OneLake security roles | + +Changing a workspace setting is not the same as granting access to data. Workspace roles and OneLake security roles belong to the security model; storage-tier and diagnostic settings govern how workspace data is retained, observed, or billed. + +## Terminology that drives the decision + + +| Term | Working meaning | Why it matters | +| --- | --- | --- | +| Diagnostic destination | A lakehouse that receives OneLake access events as JSON logs | It must satisfy placement and permission prerequisites before diagnostics can be enabled | +| Immutability period | A retention window during which diagnostic files cannot be modified or deleted | It protects evidence, but it also prevents early cleanup | +| Default storage tier | The tier used when a file has no explicitly assigned tier | Changing it can move affected files and generate transaction or retrieval charges | +| Lifecycle policy | The workspace's collection of automated tiering rules | A workspace has one policy, whose rules can target the workspace or path prefixes | +| Access-time tracking | Metadata needed for rules based on the last time a file was accessed | OneLake enables it when a lifecycle rule requires last-access conditions | + +## What the OneLake settings control + + +| Requirement in a scenario | Setting to examine | Important consequence | | --- | --- | --- | -| Spark | Compute defaults and runtime behavior | Does this change the workspace default or only one session? | -| Domain | Business ownership and discovery | Is the workspace assigned to the correct data domain? | -| OneLake | How data is exposed and accessed | Does the change affect access, discoverability, or data movement? | -| Apache Airflow | Managed orchestration configuration | Who owns connections, schedules, and operational monitoring? | +| Investigate who accessed data, when, and through which route | OneLake diagnostics | Events begin flowing to the chosen lakehouse after enablement; allow for activation latency | +| Protect diagnostic evidence from alteration for a defined period | Diagnostic-log immutability | Files cannot be changed or deleted until their retention period expires | +| Choose the initial tier for files without an explicit tier | Workspace default storage tier | Hot favors access; cooler tiers trade lower storage cost for higher access and transaction costs | +| Move inactive files automatically | Lifecycle management policy | Rules evaluate creation, modification, or access age and run asynchronously | + +The settings are related but not interchangeable. Diagnostics produces evidence. Immutability protects that evidence. The default tier supplies a baseline for untiered files. Lifecycle rules change tiers later when their conditions are met. + +## Responsibility and prerequisite boundaries + + +A workspace administrator manages these OneLake settings. For diagnostics, the administrator also needs contributor access to the destination lakehouse. Microsoft Learn states that the destination lakehouse must be in the same capacity as the workspaces being monitored. Network protection can narrow the valid destination further. + +Before enabling diagnostics, verify: + +1. A suitable lakehouse exists for the diagnostic events. +2. Capacity and network placement meet the documented constraints. +3. The configuring principal has both workspace-admin and destination-lakehouse permissions. +4. Retention, privacy, and cleanup ownership are agreed before immutability is applied. + +That last check is deliberately operational. Immutability is not a temporary display option: protected files remain noneditable and nondeletable until their individual retention windows expire. + +## Choose storage behavior deliberately + + +Hot, cool, and cold tiers exchange storage cost for access cost and minimum-retention commitments. The [OneLake storage-tier documentation](https://learn.microsoft.com/en-us/fabric/onelake/onelake-storage-tiers) identifies a 30-day minimum for cool storage and a 90-day minimum for cold storage. Moving or deleting data before the applicable minimum can incur an early-deletion charge. + +Use this sequence: + +1. Measure how often the data is read and changed. +2. Separate active paths from retention-oriented paths. +3. Estimate storage savings together with retrieval, transaction, and early-deletion costs. +4. Set a default tier only when it is appropriate for files that do not carry an explicit tier. +5. Use path-scoped lifecycle rules when different parts of the workspace have different access patterns. + +Do not select the coldest tier merely because it has the lowest storage rate. A frequently queried dataset can cost more overall and perform less predictably when retrieval behavior is ignored. + +## Build a lifecycle policy from the evidence + + +A workspace has one lifecycle policy containing rules. A rule combines a scope, enabled state, time condition, and tiering action. Conditions can use age since creation, modification, or last access. Rules without a path filter affect all eligible files in the workspace, so a broad rule deserves explicit review. + +Example decision—not a production prescription: + +```json +{ + "rules": [ + { + "name": "cool-stable-diagnostic-exports", + "enabled": true, + "scope": "Files/DiagnosticExports/", + "condition": "daysAfterModificationGreaterThan: 30", + "action": "tierToCool" + } + ] +} +``` + +The example expresses intent in a readable form. When implementing a policy, use the current portal or API schema from Microsoft Learn rather than treating this study representation as an importable payload. + +Lifecycle changes are asynchronous. Microsoft Learn notes that new rules can take up to 24 hours to take effect and that policies attempt to run daily. An exam scenario that requires an immediate, one-time tier change is therefore different from a scenario asking for ongoing automated management. + +## Portal and API views describe the same workspace state + + +In the portal, lifecycle management is under **Workspace settings > OneLake > Lifecycle management**. The Fabric REST API can also retrieve workspace OneLake settings: -## A practical decision sequence +```http +GET https://api.fabric.microsoft.com/v1/workspaces/{workspaceId}/onelake/settings +``` - -1. Identify the required outcome: performance, governance, access, or orchestration. -2. Locate the narrowest administrative scope that owns the behavior. -3. Check inheritance and override rules before changing a default. -4. Validate the effect with a representative workload rather than assuming the setting is isolated. -5. Record the operational owner and a rollback path. +The caller must have the Admin workspace role and an appropriate delegated scope such as `OneLake.Read.All` or `OneLake.ReadWrite.All`. A response can report diagnostics status, diagnostic-log immutability, and lifecycle state, including the default tier. Reading settings does not itself enable or modify them. -## Exam distinction +## Exam distinctions - -Do not treat all workspace settings as interchangeable toggles. Spark settings primarily influence compute behavior; domain assignment communicates business organization; OneLake settings influence the shared data plane; and Apache Airflow settings support managed workflow orchestration. A scenario usually gives clues about **scope**, **owner**, and **effect**. + +- **Diagnostics versus monitoring:** diagnostics records OneLake data-access events. It is not a replacement for every workload-specific execution or performance log. +- **Immutability versus retention cleanup:** immutability prevents change during a fixed window; a separate cleanup process is still needed after the window expires. +- **Default tier versus lifecycle rule:** the default applies when no explicit tier is set; a rule evaluates conditions and changes eligible files over time. +- **Workspace setting versus data permission:** OneLake storage settings do not grant a user access to a lakehouse, table, row, or folder. +- **Workspace admin versus Fabric admin:** the workspace administrator manages the workspace policy; tenant-wide enablement and delegation remain tenant concerns. ## Active recall -- Which settings would you examine first when every notebook in a workspace starts with an unsuitable Spark default? -- Why is assigning a workspace to a domain different from granting access to the workspace? -- What evidence would you collect before changing a setting that may affect multiple workloads? +1. A compliance team needs access events retained in a tamper-resistant form for 180 days. Which two OneLake capabilities work together, and what cleanup decision remains? +2. A workspace contains frequently queried curated tables and rarely accessed historical exports. Why is one workspace-wide default tier insufficient as the complete design? +3. What permissions and placement constraints must be checked before selecting a diagnostic lakehouse? +4. Why might a last-access lifecycle rule change workspace metadata behavior? +5. A question asks for a tier change to happen immediately. Why should you hesitate before choosing lifecycle management? -## Source +## Sources and provenance - -Use the [official DP-700 study guide](https://learn.microsoft.com/en-us/credentials/certifications/resources/study-guides/dp-700) as the authoritative skills outline. This chapter is original study-oriented writing and will be expanded with setting-specific Microsoft Learn sources in the content-authoring milestone. + +This original study chapter was verified against the official Microsoft Learn pages linked below, retrieved September 1, 2026 (Pacific time). The Git-backed source registry records the retrieval timestamp and SHA-256 content hash for each page. diff --git a/docs/content-model.md b/docs/content-model.md index 9ec24f6..bd5f706 100644 --- a/docs/content-model.md +++ b/docs/content-model.md @@ -29,9 +29,18 @@ MUST NOT infer order from identifiers or filenames. ## Sources and ownership Every chapter MUST map to at least one source declared in its book manifest. -The manifest records the official blueprint URL and effective date. Additional -chapter-specific sources will record retrieval dates and hashes in the refresh -milestone. +The manifest records the official blueprint URL and effective date. Each source +record contains its canonical Microsoft Learn URL, retrieval timestamp, SHA-256 +content hash, and direct chapter mappings. Source-to-chapter and +chapter-to-source mappings MUST agree so that a future refresh can identify the +affected chapters without a lineage service. + +Only `https://learn.microsoft.com` sources are accepted by the published +content contract. Raw retrieval responses are working data and MUST NOT be +committed as public content. The later refresh milestone will add bounded +retrieval, normalization, conditional requests, and readable change summaries; +the registry deliberately does not attempt to generalize those mappings into a +dependency graph. Microsoft Learn remains authoritative for Microsoft exam objectives and product behavior. Markdown chapters MUST contain original study-oriented writing and @@ -39,8 +48,9 @@ MUST NOT reproduce Microsoft Learn pages wholesale. ## Validation -Pydantic rejects duplicate identifiers, duplicate slugs, broken source -references, invalid paths, and unknown manifest fields. Content tests confirm -that every planned chapter file exists and maps at least one objective and one -source. Rendering tests verify sanitized HTML, stable anchors, external-link -behavior, and a reviewed golden fixture. +Pydantic rejects duplicate identifiers, duplicate slugs, non-Learn source +hosts, malformed hashes, one-way source mappings, broken source references, +invalid paths, and unknown manifest fields. Content tests confirm that every +planned chapter file exists and maps at least one objective and one source. +Rendering tests verify sanitized HTML, stable anchors, external-link behavior, +and a reviewed golden fixture. diff --git a/src/study_reader/content/models.py b/src/study_reader/content/models.py index 1c5faf5..ff977be 100644 --- a/src/study_reader/content/models.py +++ b/src/study_reader/content/models.py @@ -1,6 +1,6 @@ """Exam-agnostic, validated book content models.""" -from datetime import date +from datetime import date, datetime from functools import cached_property from typing import Self @@ -19,6 +19,9 @@ class Source(ContentModel): id: str = Field(pattern=r"^[a-z0-9][a-z0-9-]*$") title: str = Field(min_length=1) url: HttpUrl + retrieved_at: datetime + content_sha256: str = Field(pattern=r"^[a-f0-9]{64}$") + chapter_ids: tuple[str, ...] = Field(min_length=1) class Objective(ContentModel): @@ -110,12 +113,38 @@ def validate_references_and_identifiers(self) -> Self: if len(objective_ids) != len(set(objective_ids)): raise ValueError("objective identifiers must be unique") - source_ids = {source.id for source in self.sources} + source_ids = [source.id for source in self.sources] + if len(source_ids) != len(set(source_ids)): + raise ValueError("source identifiers must be unique") + + chapter_id_set = set(chapter_ids) + for source in self.sources: + if source.url.host != "learn.microsoft.com": + raise ValueError(f"source {source.id} is not hosted on Microsoft Learn") + unknown_chapters = set(source.chapter_ids) - chapter_id_set + if unknown_chapters: + raise ValueError( + f"source {source.id} maps unknown chapters: " + f"{sorted(unknown_chapters)}" + ) + + source_id_set = set(source_ids) for chapter in self.chapters: - unknown_sources = set(chapter.source_ids) - source_ids + unknown_sources = set(chapter.source_ids) - source_id_set if unknown_sources: raise ValueError( f"chapter {chapter.id} references unknown source: " f"{sorted(unknown_sources)}" ) + + for source in self.sources: + referencing_chapters = { + chapter.id + for chapter in self.chapters + if source.id in chapter.source_ids + } + if referencing_chapters != set(source.chapter_ids): + raise ValueError( + f"source {source.id} chapter mappings must be bidirectional" + ) return self diff --git a/src/study_reader/reader/static/reader.css b/src/study_reader/reader/static/reader.css index 691f532..2f448c3 100644 --- a/src/study_reader/reader/static/reader.css +++ b/src/study_reader/reader/static/reader.css @@ -182,7 +182,8 @@ a:focus-visible, summary:focus-visible { outline: 3px solid #d69c52; outline-off .source-card { display: grid; grid-template-columns: 1fr auto; gap: 1.5rem; align-items: center; margin-top: 4rem; padding: 1.5rem; border-radius: .8rem; background: var(--accent-soft); } .source-card h2 { margin: 0; font: 600 1.35rem Georgia, serif; } .source-card p:not(.eyebrow) { max-width: 46ch; margin: .4rem 0 0; color: var(--muted); font-size: .88rem; line-height: 1.5; } -.source-card > a { padding: .75rem 1rem; border: 1px solid var(--accent); border-radius: .5rem; font-size: .8rem; font-weight: 700; text-decoration: none; } +.source-links { display: grid; gap: .45rem; min-width: min(100%, 18rem); } +.source-links a { padding: .6rem .75rem; border: 1px solid var(--accent); border-radius: .5rem; font-size: .75rem; font-weight: 700; line-height: 1.3; text-decoration: none; } .complete-button { display: flex; @@ -264,7 +265,7 @@ a:focus-visible, summary:focus-visible { outline: 3px solid #d69c52; outline-off .chapter-prose { font-size: 1.04rem; line-height: 1.72; } .chapter-prose h2 { margin-top: 2.5rem; } .source-card { grid-template-columns: 1fr; } - .source-card > a { text-align: center; } + .source-links { width: 100%; } .chapter-navigation { grid-template-columns: 1fr; } .chapter-navigation .next { grid-column: 1; text-align: left; } } diff --git a/src/study_reader/reader/templates/chapter.html b/src/study_reader/reader/templates/chapter.html index 393c93f..f92c309 100644 --- a/src/study_reader/reader/templates/chapter.html +++ b/src/study_reader/reader/templates/chapter.html @@ -143,11 +143,13 @@

{{ chapter.title }}

Grounded in Microsoft Learn

This reader summarizes and teaches. Microsoft Learn remains the source of truth.

- {% for source in sources %} - - Open official DP-700 study guide - - {% endfor %} +