Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
9fcd6a2
test(customer): expose malformed Customer Master hierarchy loss
seonghobae Sep 1, 2026
eb37772
fix(customer): preserve malformed hierarchy entities
seonghobae Sep 1, 2026
16cf549
test(customer): require visible hierarchy issue projection
seonghobae Sep 1, 2026
8e56cc6
fix(customer): project malformed hierarchy safely
seonghobae Sep 1, 2026
47f8ab3
refactor(customer): depend on raw transport DTO
seonghobae Sep 1, 2026
0bc574b
test(customer): reproduce stale Customer Master response overwrite
seonghobae Sep 1, 2026
d3286e2
fix(customer): keep stale Customer Master requests from replacing cur…
seonghobae Sep 1, 2026
c583fff
fix(customer): bind Customer Master to newest request
seonghobae Sep 1, 2026
9cae92f
test(customer): keep request ownership when start throws
seonghobae Sep 1, 2026
99891b5
fix(customer): preserve request owner on sync start failure
seonghobae Sep 1, 2026
f6b9c32
test(customer): reproduce re-entrant request ownership cycle
seonghobae Sep 1, 2026
1fda283
fix(customer): preserve re-entrant newest request ownership
seonghobae Sep 1, 2026
2fdcf6c
test(customer): reject duplicate customer identities
seonghobae Sep 1, 2026
7b6d86f
fix(customer): fail closed on duplicate entity identities
seonghobae Sep 1, 2026
8d0db3e
test(customer): reproduce deep hierarchy call-stack failure
seonghobae Sep 2, 2026
9e5d2bb
fix(customer): materialize deep hierarchy iteratively
seonghobae Sep 2, 2026
0244be1
fix(customer): flatten deep hierarchy iteratively
seonghobae Sep 2, 2026
fe019f2
test(customer): disclose empty parent identity
seonghobae Sep 2, 2026
453b39a
fix(customer): distinguish null from malformed empty parent
seonghobae Sep 2, 2026
4932a02
test(customer): expose anonymous canonical entity roots
seonghobae Sep 2, 2026
d704067
fix(customer): reject blank canonical entity identities
seonghobae Sep 2, 2026
50db5ca
test(customer): reject canonical entity id whitespace aliases
seonghobae Sep 2, 2026
5b9aabd
fix(customer): reject canonical entity id whitespace aliases
seonghobae Sep 2, 2026
dd4c51c
chore(stack): converge Customer Master with protected main
seonghobae Sep 3, 2026
aa1755e
chore(customer): converge Customer Master with protected main
seonghobae Sep 3, 2026
bbc32b7
fix(web): bound authenticated API requests
Sep 4, 2026
0e97d07
chore(main): non-force converge protected #930
seonghobae Sep 4, 2026
4534841
chore(main): non-force converge protected #931
seonghobae Sep 4, 2026
3fa92d2
fix(customer): complete malformed hierarchy rendering
Sep 4, 2026
e82aed3
feat(customer): make malformed hierarchy visible
Sep 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions docs/adr/0364-authenticated-browser-request-boundary.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# ADR 0364: Authenticated browser request boundary

- Status: Accepted
- Date: 2026-09-04

## Context

The browser sends an access token to the configured LineageWeave API. A remote
cleartext URL would expose that credential in transit. Local Compose development
still needs loopback HTTP.

Global Ask is an asynchronous job. Its existing fifteen-minute product ceiling
was checked only between requests, so a stalled submission or poll could keep
the visible waiting state alive indefinitely.

## Decision

Authenticated browser requests admit HTTPS destinations. HTTP is admitted only
for `localhost`, `127.0.0.1`, and `[::1]`; embedded URL credentials and every
other scheme or cleartext host fail before the authorization header is built.

Global Ask establishes its existing whole-operation deadline before submission.
The submission and every poll receive an abort signal for the remaining time.
A deadline abort becomes the existing actionable Ask timeout outcome, while
other connectivity failures keep the shared unavailable outcome.

## Consequences

- A deployment cannot send an access token to a remote cleartext API by
configuration mistake.
- Loopback Compose development keeps its current HTTP URL.
- A stalled request cannot outlive the same ceiling that governs polling.
- This decision changes no server job deadline and does not claim that a timed
out job was cancelled server-side.

## Alternatives considered

- Enforce the rule only in deployment documentation: rejected because the
browser would still attach the token when configuration drifts.
- Start the Ask deadline after submission: rejected because submission latency
is part of the user's wait.
- Add a second shorter per-request timeout: rejected because no separate
evidence supports another threshold.
40 changes: 40 additions & 0 deletions docs/adr/0365-customer-master-malformed-hierarchy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# ADR 0365: Customer Master malformed hierarchy presentation

- Status: Accepted
- Date: 2026-09-05

## Context

An authorized Customer Master response can contain an entity whose parent is not
visible, points to itself, or participates in a cycle. Dropping that entity hides
authorized customer evidence. Treating the malformed edge as valid can recurse
forever or exhaust the browser call stack. Changing the stored parent would invent
organizational authority.

## Decision

The presentation projection keeps every uniquely identified authorized entity. It
omits a missing, self-referential, or one deterministic cycle-closing parent edge and
promotes that entity to a visible root. A presentation-only issue code travels to the
render boundary, where localized customer copy discloses the omitted edge. It does not
change the API's authoritative name, level, identifier, or stored parent.

Duplicate, blank, and whitespace-aliased canonical entity identifiers fail closed.
Tree construction, flattening, and rendering are iterative so valid depth cannot
exhaust the JavaScript call stack. Sibling and cycle-break ordering uses code-point
comparison and carries no ranking or organizational inference.

## Consequences

- Authorized entities stay visible even when their visible hierarchy is incomplete.
- The screen distinguishes source facts from a presentation-only omitted-edge notice.
- A malformed identity yields the existing load failure instead of an ambiguous tree.
- Deep hierarchies render as one flat DOM list with visual indentation.

## Alternatives considered

- Drop malformed descendants: rejected because it hides authorized evidence.
- Reassign a replacement parent: rejected because the product has no authority to
invent organizational structure.
- Render the source graph recursively: rejected because cycles and valid deep inputs
can prevent the screen from rendering.
2 changes: 2 additions & 0 deletions docs/adr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ decision from them.
| [`operability/http-concurrency-evidence.md`](../operability/http-concurrency-evidence.md) | [0204](0204-analysis-run-short-transaction-delivery.md), [0212](0212-single-query-authorized-post-filter-options.md), [0213](0213-global-ask-embedding-pool-release.md) |
| [`operability/mcp-concurrency-evidence.md`](../operability/mcp-concurrency-evidence.md) | [0218](0218-current-contract-mcp-global-ask.md) |
| Evidence operations Dashboard (`/`) | [0206](0206-evidence-operations-dashboard.md) |
| Authenticated browser requests and Global Ask polling | [0364](0364-authenticated-browser-request-boundary.md) |
| Customer Master malformed hierarchy presentation | [0365](0365-customer-master-malformed-hierarchy.md) |
| [`temporal-topic-context-influence-research.md`](../temporal-topic-context-influence-research.md) | [0210](0210-temporal-topic-context-influence-dashboard.md) |
| [`python-mathematical-compute-boundary-audit.md`](../doctoring/python-mathematical-compute-boundary-audit.md) | [0208](0208-externalize-local-mathematical-compute.md) |
| [`WORKER_FUNCTION_TAXONOMY_REFERENCES.md`](../doctoring/WORKER_FUNCTION_TAXONOMY_REFERENCES.md) | [0232](0232-worker-function-taxonomy-in-the-published-ontology.md) |
Expand Down
1 change: 1 addition & 0 deletions docs/storybook-inventory.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ operator-facing control you can click before changing product CSS.
| `Reports/LeftoverMapPlot` | Read the leftover-map graphic display of persisted `ξ` (posts) and `ζ` (criteria), match axis ticks to those coordinates and pair-segment `d` to leftover-map distance, then click a post marker to open that post. Leftover-map axes name persisted leftover-map axis share when finite. `ClosestAndFarthest`, `RankZeroOrigin`, `MissingCoordinates`, and `MissingAxisShare` cover two-pair maps, rank-0 origin with 0% share, a `0` tick, and `d 0.00`, omitted plots, and missing share that keeps existing leftover-map axis text. The plot does not invent a leftover score. | `LeftoverMapPlot`, `leftoverMapPlotLayout`, `leftoverMapPlotAxisShare`, `--color-primary`, `--color-palette-blue-mid` |
| `Reports/LeftoverPairList` | Read closest/farthest leftover pairs with named `R`, `Y`/`E`, rank, `U`, `s`, `e`, `x`, `R̂`, `ξ`/`ζ`, and `d`, then open that post. The leftover-map graphic display sits above the pair buttons when coordinates are finite, leftover-map axes name persisted leftover-map axis share, leftover-map axis ticks name persisted coordinates, and pair segments name persisted leftover-map distance. | `LeftoverPairList`, `LeftoverMapPlot`, `ticket-list`, `post-badge` |
| `Workspace/OperationsDashboard` | Compare Event and post counts, inspect external-information coverage, then open the cited source behind a claim, handover, or repeat-issue fact. `EvidenceReady`, `NarrowViewport`, `AnalysisPendingAndMissingEvidence`, `AnalysisFailed`, and `LoadError` cover populated, mobile, unavailable-evidence, analysis-pending, retryable failure, and transport-error states. | `--color-dashboard-*`, `OperationsDashboard` |
| `Workspace/CustomerMasterPanel` | Inspect every authorized customer entity even when imported parent links contain a cycle. `CyclePreserved` and `CyclePreservedMobile` cover desktop and narrow layouts while keeping the malformed link visibly omitted instead of hiding a record. | `CustomerMasterPanel`, `customer-master`, `--surface`, `--border`, `--size-control-min` |
| `Post/SimilarVocPanel` | Compare ontology/semantic similar VOC and prior action evidence, then open the source; unavailable states show no fabricated TEPP theta or weight. | `SimilarVocPanel.css`, `SimilarVocPanel` |
| `Post/Recorded perspectives` | Read the imported primary and every evidence-connected additional Voice with its recorded truth state instead of flattening them into one compound category. `CombinedEvidence`, `RejectedEvidence`, and `NarrowViewport` cover desktop, rejected-evidence, and narrow layouts. | `VoicePerspectiveList`, `ticket-list`, `post-meta` |
| `Post/Connect perspective` | Choose one unassigned Voice and an explicit evidence state, then record the open post as its evidence. `Ready`, `Completed`, and `NarrowViewport` cover untouched, successful, and mobile states. | `VoiceAssignmentForm`, `admin-form`, `btn-primary` |
Expand Down
88 changes: 88 additions & 0 deletions frontend/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,94 @@
text-transform: uppercase;
}

/* Workspace destinations */
.workspace-destination {
box-sizing: border-box;
width: min(100%, 64rem);
margin-inline: auto;
padding: var(--space-panel-block);
}

.workspace-destination > h2,
.workspace-destination > p {
margin-block-start: 0;
}

.section-eyebrow {
color: var(--color-text);
font-size: 0.75rem;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
}

.workspace-destination-intro {
color: var(--color-text);
max-width: 46rem;
}

.customer-master-list {
list-style: none;
margin: 0;
padding: 0;
}

.customer-master-tree,
.customer-master-tree-children {
display: grid;
gap: var(--space-control-gap);
}

.customer-master-tree-children {
margin-block-start: var(--space-control-gap);
}

.customer-master-tree li {
margin-inline-start: calc(var(--customer-hierarchy-depth, 0) * 1.25rem);
}

.customer-entity-button {
align-items: flex-start;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-control);
color: var(--text);
cursor: pointer;
display: flex;
flex-direction: column;
gap: 0.25rem;
min-height: var(--size-control-min);
padding: 0.75rem 1rem;
text-align: start;
width: 100%;
}

.customer-entity-button:hover,
.customer-entity-button:focus-visible {
border-color: var(--color-focus-border);
}

.customer-entity-button span {
color: var(--color-text);
font-size: 0.875rem;
}

.customer-related-posts,
.customer-keymen {
margin-block-start: var(--space-panel-block);
}

@media (max-width: 768px) {
.workspace-destination {
padding: var(--space-control-gap);
}

.customer-master-tree > li,
.customer-master-tree-children > li {
margin-inline-start: 0;
}
}

/* Popup / Modals (§3.6.1 모달 레이어 투명도 50%) */
.popup-backdrop {
position: fixed;
Expand Down
Loading
Loading